DIRTY DAVE
DIRTY DAVE

Reputation: 2731

How to structure class for deserializing this nested array?

I'm trying to deserialize a nested array from a JSON response. It's the first time I've ever gotten an array of arrays and I'm not quite sure how to structure my class to handle it.

{
"prices": [
            [
                1641670404234,
                0.01582586939240936
            ],
            [
                1641674037525,
                0.015999047707867396
            ],
            [
                1641677655158,
                0.016072905257982606
            ]
            
            ...
         ],
}

If the brackets were { instead of [

{
"prices": {
            {
                1641670404234,
                0.01582586939240936
            },
            {
                1641674037525,
                0.015999047707867396
            },
            {
                1641677655158,
                0.016072905257982606
            }
           }
            ...
}

I could use

@SerializedName("prices")
private List<Price> prices;
public class Price {
    private long date;
    private BigDecimal price;
}

However since it is [ instead, I am quite unsure how to structure it.

I've tried adding another List wrapper to it but that throws an error

@SerializedName("prices")
private List<List<Price>> prices;
IllegalStateException: Expected BEGIN_OBJECT but was NUMBER at line 1 column 26 path $.prices[0][0]

I've also tried wrapping it with a JSONArray

 @SerializedName("prices")
private List<JSONArray<Price>> prices;

but that's not quite right

enter image description here

I've tried searching other SO answers but I could not find any examples where it's two consecutive [ [ brackets.

They are all { [ or [ {.

What's the correct way to do it?

Upvotes: 0

Views: 183

Answers (2)

Marcono1234
Marcono1234

Reputation: 6884

The proper way to solve this is to write a custom TypeAdapter for your Price class. This has the advantage that you can keep your model classes as is (with a List<Price> prices field), and have them represent more closely the actual data. If instead you parsed the JSON data as List<List<BigDecimal>> or similar, then you would have to manually validate that the JSON data is wellformed and have to convert the List<BigDecimal> to a Price object yourself.

Here is how a TypeAdapter implementation for your Price class could look like:

class PriceTypeAdapter extends TypeAdapter<Price> {
    @Override
    public void write(JsonWriter out, Price value) throws IOException {
        out.beginArray();
        out.value(value.date);
        out.value(value.price);
        out.endArray();
    }

    @Override
    public Price read(JsonReader in) throws IOException {
        in.beginArray();

        Price priceObj = new Price();
        priceObj.date = in.nextLong();
        // nextString() automatically converts JSON numbers to String, if necessary
        // This is similar to how Gson's default adapter for BigDecimal works
        priceObj.price = new BigDecimal(in.nextString());

        in.endArray();

        return priceObj;
    }
}

Note: Alternatively to reading the BigDecimal manually as shown here, you could create this type adapter inside a TypeAdapterFactory and get the default Gson adapter for BigDecimal. This allows reusing Gson's built-in adapters inside your own type adapter, but here for BigDecimal that overhead is probably not worth it.

You can then either register your adapter on a GsonBuilder instance or you can place an @JsonAdapter annotation on your Price class, which references the adapter. In case you use the GsonBuilder approach, you might want to create a null-safe variant of your adapter by calling nullSafe() on it (or you implement null handling in the adapter manually).

Upvotes: 2

Sergio
Sergio

Reputation: 30645

Assuming this is the correct JSON:

{
    "prices": [
        [
            1641670404234,
            0.01582586939240936
        ],
        [
            1641674037525,
            0.015999047707867396
        ],
        [
            1641677655158,
            0.016072905257982606
        ]
    ]
}

Then you can use this model to deserialize data to:

JAVA:

public class PricesModel {
    public ArrayList<ArrayList<Double>> prices;
}

KOTLIN:

data class PricesModel (

  @SerializedName("prices" ) var prices : ArrayList<ArrayList<Double>> = arrayListOf()

)

Handy JSON converters to Java and Kotlin.

Upvotes: 0

Related Questions