【问题标题】:Deserialize JSON Array with random name - GSON使用随机名称反序列化 JSON 数组 - GSON
【发布时间】:2022-01-26 15:48:56
【问题描述】:

我正在尝试使用 GSON 反序列化复杂的 JSON 结构。 API 提供者通过在结果中提供一个随机名称的数组来使事情复杂化。

这是(简化/通用)JSON:

{
    "field_1": "value",
    "field_2": "value",
    "field_3": {
        "RANDOM_NAME": [
            {
                "array_field_1": "value",
                "array_field_2": "value",
                "array_field_3": "value"
            },
            {
                "array_field_1": "value",
                "array_field_2": "value",
                "array_field_3": "value"
            }
        ]
    },
    "field_4": "value"
}

这是对应的(高度简化的)POJO:

public class responseObject {
    String field_1;
    String field_2;
    Field3 field_3;
    String field_4;

    class Field3{
        ArrayObject[] arrayObjects;
    }
    class ArrayObject{
        String array_field_1;
        String array_field_2;
        String array_field_3;
    }
}

但是,当我运行 responseObject response = new Gson().fromJson(getJSON(),responseObject.class); 时,我得到以下调用堆栈:

表明field_3 没有正确反序列化,并且不包含ArrayObject 的数组。

this 发布答案参考如何将数据转换为地图,但在我的情况下,数组中每个项目的数据结构实际上比这个简化示例大得多,它违背了使用 GSON 的目的如果我必须从复杂的嵌套地图列表中手动选择我需要的数据。在随机对象是数组而不是普通 json 对象的情况下,也无法让这些答案正常工作。

如何让 JSON 中随机命名的数组正确反序列化为变量 responseObject.Field3.arrayObjects??

【问题讨论】:

  • 这是一个复杂的结构。两步反序列化怎么样?第一步是使用带有 的 map。之后再次反序列化字符串值。
  • 你能用 gson 演示一下如何通过一两个简单的步骤做到这一点吗?
  • 类似这样:第一步:public class responseObject { String field_1;字符串字段_2;字段 3 字段_3;字符串字段_4;类 Field3{ Map field_3; } 类 ArrayObject{ 字符串 array_field_1;字符串数组_字段_2;字符串数组_字段_3; } } 第二步:for(String key: field_3.keySet()) { //对 field_3.get(key) 应用反序列化 }

标签: java arrays json gson


【解决方案1】:

您可以通过设置 field_3 Map<String, List<ArrayObject>> 的类型来避免使用 TypeAdapeter 的复杂性

public class responseObject {
    String field_1;
    String field_2;
    Map<String, List<ArrayObject>> field_3;
    String field_4;

    class ArrayObject{
        String array_field_1;
        String array_field_2;
        String array_field_3;
    }
}

然后在不知道密钥的情况下从 Map 中取出第一项,您可以使用:

public List<ResponseObject.ArrayObject> getFirstValue(Map<String, List<ResponseObject.ArrayObject>> field_3) {
    return field_3.values().iterator().next();
}

【讨论】:

  • 工作!谢谢你。接受了这个答案,因为它避免了编写自定义TypeAdapter,这更符合GSONs 易于反序列化的简单精神......
【解决方案2】:

这可以通过为Field3 编写自定义TypeAdapter 来解决,该Field3 忽略属性的名称并且只读取值。 TypeAdapter 必须由 TypeAdapterFactory 创建,以允许获取 ArrayObject[] 的委托适配器:

class Field3TypeAdapterFactory implements TypeAdapterFactory {
    public Field3TypeAdapterFactory() {
    }

    @Override
    public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
        // Only support Field3 class
        if (type.getRawType() != Field3.class) {
            return null;
        }

        TypeAdapter<ArrayObject[]> fieldValueAdapter = gson.getAdapter(ArrayObject[].class);

        // Cast is safe, check at beginning made sure type is Field3
        @SuppressWarnings("unchecked")
        TypeAdapter<T> adapter = (TypeAdapter<T>) new TypeAdapter<Field3>() {
            @Override
            public void write(JsonWriter out, Field3 value) throws IOException {
                throw new UnsupportedOperationException("Serialization is not supported");
            }

            @Override
            public Field3 read(JsonReader in) throws IOException {
                if (in.peek() == JsonToken.NULL) {
                    in.nextNull();
                    return null;
                }

                in.beginObject();
                // Skip the random property name
                in.skipValue();
                ArrayObject[] fieldValue = fieldValueAdapter.read(in);
                in.endObject();

                Field3 object = new Field3();
                object.arrayObjects = fieldValue;
                return object;
            }
        };
        return adapter;
    }
}

然后您可以register the factory with a GsonBuilder,或者您可以使用@JsonAdapter 注释您的Field3 类。当使用@JsonAdapter 时,工厂类应该有一个无参数的构造函数。

【讨论】:

    猜你喜欢
    • 2014-06-21
    • 2015-02-24
    • 2011-03-28
    • 1970-01-01
    • 2017-07-31
    • 2017-01-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多