0

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?

2 Answers 2

2

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).

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for taking the time to write this. I very much appreciate it
0

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.

2 Comments

The Kotlin class is incorrect (probably due to a bug with the used code generator), the property type should be ArrayList<ArrayList<Double>>.
thanks @Marcono1234 for noticing.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.