GSON在同一列表中反序列化两个不同的对象类型

时间:2018-04-06 00:54:52

标签: java gson

我尝试使用具有以下返回值的API:

{
   "data":{
      "id":"12345",
      "name":"Some Name",
      "regions":[
         "r987",
         "r654"
      ]
   }
}

区域属性是List<String>,只有区域ID 但是我可以要求同一个请求检索完整的区域对象,所以json改为:

{
   "data":{
      "id":"12345",
      "name":"Some Name",
      "regions":{
         "data":[
            {
               "id":"r987",
               "name":"region 1"
            },
            {
               "id":"r654",
               "name":"region 2"
            }
         ]
      }
   }
}

我想创建一个适配器来始终翻译Id列表以返回包含完整对象的列表,例如

class RegionListAdapter implements JsonDeserializer<List<Region>> {

    @Override
    public List<Region> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext jsc) throws JsonParseException {

        List<Region> result = new ArrayList<>();

        if (json.isJsonObject()) {
            JsonObject envelope = json.getAsJsonObject();
            JsonArray data = envelope.getAsJsonArray("data");
            result = jsc.deserialize(data, typeOfT);
        } else {
            JsonArray idArray = json.getAsJsonArray();
            for(JsonElement e : idArray){
                String regionId = e.getAsString();
                Region region = new Region(regionId);
                result.add(region);
            }
        }

        return result;
    }
}

并且一切正常,仅接收ID或完整对象...

问题是,我有其他属性以相同的方式工作。有没有办法让这个适配器一般工作或以不同的方式工作?或者我需要为每个对象创建一个适配器?

1 个答案:

答案 0 :(得分:0)

制作此泛型的难点在于您需要创建列表中对象类型的新实例。如果所有对象都将使用名为id的字段作为列表版本中的内容,我们可以使用它来创建新实例。最简单的黑客攻击如下所示,我们将字符串作为id字段填充到新的JsonObject中,然后使用Gson构造新对象。

class IdListAdapter<T> implements JsonDeserializer<List<T>> {

  @Override
  public List<T> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext jsc) throws JsonParseException {

    if (json.isJsonObject()) {
      JsonObject envelope = json.getAsJsonObject();
      JsonArray data = envelope.getAsJsonArray("data");
      return jsc.deserialize(data, typeOfT);
    } else {
      JsonArray idArray = json.getAsJsonArray();
      List<T> result = new ArrayList<T>(idArray.size());
      for (JsonElement id : idArray) {
        if (typeOfT instanceof ParameterizedType) {
          Type parameterType = ((ParameterizedType) typeOfT).getActualTypeArguments()[0];
          JsonObject obj = new JsonObject();
          obj.add("id", id);
          T element = jsc.deserialize(obj, parameterType);
          result.add(element);
        }
      }
      return result;
    }
  }
}