如何构造 class 来反序列化这个嵌套数组?

How to structure class for deserializing this nested array?

我正在尝试从 JSON 响应中反序列化嵌套数组。这是我第一次得到一个数组数组,我不太确定如何构建我的 class 来处理它。

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

如果括号是 { 而不是 [

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

我可以用

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

但是因为它是 [,所以我不确定如何构造它。

我试过向它添加另一个 List 包装器,但这会引发错误

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

我也试过用JSONArray

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

但这不太对

我尝试搜索其他 SO 答案,但找不到任何包含两个连续 [ [ 括号的示例。

他们都是{ [[ {

正确的做法是什么?

假设这是正确的JSON:

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

然后您可以使用此模型将数据反序列化为:

JAVA:

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

KOTLIN:

data class PricesModel (

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

)

方便的 JSON 转换器到 Java and Kotlin

解决此问题的正确方法是为您的 Price class 编写自定义 TypeAdapter。这样做的好处是您可以保持模型 class 原样(带有 List<Price> prices 字段),并让它们更接近实际数据。相反,如果您将 JSON 数据解析为 List<List<BigDecimal>> 或类似数据,则您必须手动验证 JSON 数据是否格式正确,并且必须将 List<BigDecimal> 转换为 Price反对你自己。

TypeAdapter Price class 的实现如下所示:

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;
    }
}

注意:除了如此处所示手动读取 BigDecimal,您可以在 TypeAdapterFactory 中创建此类型的适配器并获取 BigDecimal 的默认 Gson 适配器。这允许在您自己的类型适配器中重用 Gson 的内置适配器,但是对于 BigDecimal 来说,这种开销可能不值得。

然后您可以在其上 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()(或者您在适配器中手动实现 null 处理)。