Reputation: 2731
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
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
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
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