如何在使用gson解析json时忽略重复键?

时间:2016-05-13 06:22:44

标签: json duplicates gson

我在使用GSON解析包含时间戳作为键的JSON响应时遇到重复键异常。它给出了以下错误:

  

com.google.gson.JsonSyntaxException:重复键:1463048935           在com.google.gson.internal.bind.MapTypeAdapterFactory $ Adapter.read(MapTypeAdapterFactory.java:186)           在com.google.gson.internal.bind.MapTypeAdapterFactory $ Adapter.read(MapTypeAdapterFactory.java:141)

如何让它忽略重复的条目,然后用重复的条目中的任何一个将其解析为地图?

1 个答案:

答案 0 :(得分:0)

Hackerman解决方案,已使用GSON v2.8.5进行了测试和工作,但后果自负!每当您将GSON更新到新版本时,请确保检查它是否仍然有效!

基本上,您可以使用以下事实:通用ObjectTypeAdapter忽略重复项,如here所示:

  

就像MapTypeAdapterFactory一样,检查是否重复

  V replaced = map.put(key, value);
  if (replaced != null) {
    throw new JsonSyntaxException("duplicate key: " + key);
  }
  

但是ObjectTypeAdapter没有

case BEGIN_OBJECT:
  Map<String, Object> map = new LinkedTreeMap<String, Object>();
  in.beginObject();
  while (in.hasNext()) {
    map.put(in.nextName(), read(in));
  }
  in.endObject();
  return map;

您现在可以做的是像往常一样尝试使用fromJson进行反序列化,但是捕获了“重复密钥”异常,将其反序列化为通用对象,它将忽略重复项,再次对其进行序列化,这将导致没有重复键的JSON字符串,最后使用实际上应具有的正确类型反序列化。

这是Kotlin代码示例:

fun <T> String.deserialize(gson: Gson, typeToken: TypeToken<T>): T {
    val type = typeToken.type
    return try {
        gson.fromJson<T>(this, type)
    } catch (e: JsonSyntaxException) {
        if (e.message?.contains("duplicate key") == true) {
            gson.toJson(deserialize(gson, object : TypeToken<Any>() {})).deserialize(gson, typeToken)
        } else {
            throw e
        }
    }
}

很明显,这需要2个反序列化和一个附加的序列化,这增加了(可能很重)开销,但是目前我看不到有其他方法可以这样做。如果here建议,如果Google决定添加一种内置选项来忽略重复项,则最好切换到该选项。