【问题标题】:How to decode JSON with unknown field using Gson?如何使用 Gson 解码具有未知字段的 JSON?
【发布时间】:2013-12-07 14:06:15
【问题描述】:

我有类似这样的 JSON:

{
  "unknown_field": {
    "field1": "str",
    "field2": "str",
    "field3": "str",
    "field4": "str",
    "field5": "str"
  }, ......
}

我创建了类来映射这个 json

public class MyModel implements Serializable {
  private int id;
  private HashMap<String, Model1> models;

  // getters and setter for id and models here
}

Model1 类是一个只有字符串字段的简单类。

但它不起作用。

编辑:JSON format 看起来像这样:

{
    "1145": {
        "cities_id": "1145",
        "city": "Nawanshahr",
        "city_path": "nawanshahr",
        "region_id": "53",
        "region_district_id": "381",
        "country_id": "0",
        "million": "0",
        "population": null,
        "region_name": "Punjab"
    },
    "1148": {
        "cities_id": "1148",
        "city": "Nimbahera",
        "city_path": "nimbahera",
        "region_id": "54",
        "region_district_id": "528",
        "country_id": "0",
        "million": "0",
        "population": null,
        "region_name": "Rajasthan"
    }, 
    ...
}

【问题讨论】:

  • 只需将其解析为地图即可。
  • 我做到了,但没有结果。此方法 - gson.fromJson(json, MyModel.class) 返回 null
  • 加上“unknown_field”,是不是说这个对象在JSON字符串中的名字可以不一样?
  • 因为您没有将其解析为 Map。 Gson 必须有一个普通的解析器模式,它将生成一个没有模型类的 Map 或 List。

标签: java json parsing gson


【解决方案1】:

(在OP评论实际上JSON looks like this之后,我完全更新了答案。)

Gson 2.0+解决方案

我just learned 认为,对于较新的 Gson 版本,这非常简单:

GsonBuilder builder = new GsonBuilder();
Object o = builder.create().fromJson(json, Object.class);

创建的对象是一个地图(com.google.gson.internal.LinkedTreeMap),如果打印出来,看起来是这样的:

{1145={cities_id=1145, city=Nawanshahr, city_path=nawanshahr, region_id=53, region_district_id=381, country_id=0, million=0, population=null, region_name=Punjab}, 
 1148={cities_id=1148, city=Nimbahera, city_path=nimbahera, region_id=54, region_district_id=528, country_id=0, million=0, population=null, region_name=Rajasthan}
...

使用自定义反序列化器的解决方案

(NB:事实证明你并不是真正的自定义反序列化器,除非你坚持使用 2.0 之前的 Gson 版本。但知道如何做 custom deserialisation (and serialisation) in Gson 仍然很有用,它通常可能是最好的方法,具体取决于您希望如何使用已解析的数据。)

所以我们确实在处理随机/变化的字段名称。 (当然,这种JSON格式不是很好,这种数据应该在JSON数组里面,这样就可以很容易的读入List。哦,还可以解析这个。)

首先,这是我在 Java 对象中建模 JSON 数据的方式:

// info for individual city
public class City    {
    String citiesId;
    String city;
    String regionName;
    // and so on
}

// top-level object, containing info for lots of cities
public class CityList  {
    List<City> cities;

    public CityList(List<City> cities) {
        this.cities = cities;
    }
}

然后,解析。处理这种 JSON 的一种方法是为顶级对象 (CityList) 创建一个自定义反序列化器。

类似这样的:

public class CityListDeserializer implements JsonDeserializer<CityList> {

    @Override
    public CityList deserialize(JsonElement element, Type type, JsonDeserializationContext context) throws JsonParseException {
        JsonObject jsonObject = element.getAsJsonObject();
        List<City> cities = new ArrayList<City>();
        for (Map.Entry<String, JsonElement> entry : jsonObject.entrySet()) {
            // For individual City objects, we can use default deserialisation:
            City city = context.deserialize(entry.getValue(), City.class); 
            cities.add(city);
        }
        return new CityList(cities);
    }

}

需要注意的一个关键点是对 jsonObject.entrySet() 的调用,它会返回所有顶级字段(名称如“1145”、“1148”等)。 This Stack Overflow answer 帮我解决了这个问题。

完整的解析代码如下。请注意,您需要使用 registerTypeAdapter() 来注册自定义序列化器。

GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(CityList.class, new CityListDeserializer());
Gson gson = builder.setFieldNamingPolicy(LOWER_CASE_WITH_UNDERSCORES).create();
CityList list = gson.fromJson(json, CityList.class);

(这是一个完整的,executable example,我用于测试。除了 Gson,它还使用 Guava 库。)

【讨论】:

  • @Nazik:是的,这有点棘手,但可以使用自定义反序列化器解决。请参阅我编辑的答案。
  • 我再次更新了答案,原来是very simple with newer Gson versions。很高兴了解有关 Gson 的新知识。
  • 感谢您非常有帮助的回复
  • 感谢LinkedTreeMap。手动解析 JSON 对象中的字符串值很困难,但至少有帮助。
猜你喜欢
  • 1970-01-01
  • 2018-10-05
  • 2023-01-10
  • 2011-08-13
  • 2017-03-18
  • 1970-01-01
  • 2021-05-09
  • 1970-01-01
  • 2015-10-14
相关资源
最近更新 更多