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

pin*_*rty 5 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。读(MapTypeAdapterFactory.java:141)

如何让它忽略重复条目,而只是将其解析为包含重复条目中任何一个的映射?

010*_*101 2

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

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

看起来 MapTypeAdapterFactory 检查重复项

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

但是 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;
Run Code Online (Sandbox Code Playgroud)

您现在可以做的是尝试像往常一样使用反序列化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
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

显然,这需要两次反序列化和一次额外的序列化,从而增加(可能会很重)开销,但目前我没有看到任何其他方法可以做到这一点。如果 Google 决定添加一个内置方式的选项来忽略重复项(如此处建议的那样)最好切换到该选项。