【问题标题】:How to structure class for deserializing this nested array?如何构造用于反序列化此嵌套数组的类?
【发布时间】:2022-01-10 19:19:02
【问题描述】:

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

{
"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 答案,但找不到任何连续两个 [ [ 括号的示例。

他们都是{ [[ {

正确的做法是什么?

【问题讨论】:

    标签: java android json kotlin gson


    【解决方案1】:

    解决此问题的正确方法是为您的Price 类编写自定义TypeAdapter。这样做的好处是您可以保持模型类原样(使用List&lt;Price&gt; prices 字段),并让它们更接近地表示实际数据。如果您将 JSON 数据解析为 List&lt;List&lt;BigDecimal&gt;&gt; 或类似名称,则必须手动验证 JSON 数据是否格式正确,并且必须自己将 List&lt;BigDecimal&gt; 转换为 Price 对象。

    下面是您的Price 类的TypeAdapter 实现的样子:

    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 或者您可以在引用适配器的Price 类上放置@JsonAdapter 注释。如果您使用GsonBuilder 方法,您可能希望通过在其上调用nullSafe() 来创建适配器的null-safe 变体(或者您在适配器中手动实现null 处理)。

    【讨论】:

    • 感谢您抽出宝贵时间撰写本文。非常感谢
    【解决方案2】:

    假设这是正确的 JSON:

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

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

    JAVA

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

    科特林

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

    方便的 JSON 转换器到 JavaKotlin

    【讨论】:

    • Kotlin 类不正确(可能是由于使用的代码生成器存在错误),属性类型应为ArrayList&lt;ArrayList&lt;Double&gt;&gt;
    • 感谢@Marcono1234 的关注。
    猜你喜欢
    • 1970-01-01
    • 2019-09-22
    • 1970-01-01
    • 2019-12-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多