【问题标题】:Make Gson throw exception on parsing JSON with duplicated key使 Gson 在解析带有重复键的 JSON 时抛出异常
【发布时间】:2014-02-28 15:35:01
【问题描述】:

我正在使用 Gson 解析简单的 JSON 对象。我希望它在键名重复时抛出一些错误。例如

{
  a: 2,
  a: 3
}

在我的例子中,Gson 解析这样的 JSON 并将 a 设置为 3。我希望它抛出一些异常。

我知道我可以将 JSON 解析为映射,然后 Gson 在这种情况下抛出异常,但前提是重复的键没有嵌套在映射中。如果我有例如像这样的 JSON:

{
  a: 2,
  b: {
    dup: 1,
    dup: 2
  }
}

尽管如此,它还是毫无例外地被解析,我只有一个值为 2 的“dup”。

我可以以某种方式设置 Gson 在这种情况下抛出错误吗?或者在JsonObject 实例中有重复的条目,以便我自己检测到它(但我怀疑这一点,因为它是无效的JsonObject

可重现的例子

String json = "{\"a\":2, \"a\":3}";
Gson gson = new Gson();
JsonObject jsonObject = gson.fromJson(json, JsonObject.class);
System.out.println(jsonObject);

打印出来

{"a":3}

【问题讨论】:

  • 您可以添加SSCCE 以便我们复制您所描述的内容吗?
  • @dimo414 根据我的理解,我已经为他们做到了。
  • 在我看来你应该让另一端发送有效的 JSON。
  • 当然,这样的 JSON 是无效的。问题是我们将配置保留在其中 - 人类编写它。这很重要,所以我需要这个错误检测。 JSON 似乎真的很适合它,因为我们需要键值、对象数组等。我也在考虑 YAML,但它似乎有同样的问题,我在 instantyaml.appspot.com 上进行测试
  • @SotiriosDelimanolis - 好吧,至少还有十几个要去。

标签: java json parsing gson


【解决方案1】:

1) 您可以稍微编辑一下 gson 的源代码。这只是一个了解事物如何运作的建议。我不建议您在真实/生产环境中使用它。

Gson 在将 json 字符串解析为 JsonObject 时使用 com.google.gson.internal.LinkedTreeMap。对于测试问题,您可以将该类复制到具有相同名称和包名称的项目中。并编辑其 put 方法以不允许重复键。

    @Override
    public V put(K key, V value) {
    if (key == null) {
      throw new NullPointerException("key == null");
    }

    // my edit here
    if(find(key, false) != null) {
        throw new IllegalArgumentException("'" + key.toString() + "' is duplicate key for json!");
    }

    Node<K, V> created = find(key, true);
    V result = created.value;
    created.value = value;
    return result;
  }

2) 另一个干净的解决方案是定义将映射到您的 json 字符串的自定义类。然后写他们自定义的TypeAdapters

3) 使用Deserializer 来实现吗?我不认为这是可能的。如果你尝试使用它,你会看到你已经有一个 jsonObject 在那里你的重复键被处理为一个。

【讨论】:

  • 是的,我已经在考虑 TypeAdapter,我会试试这个。
  • 好主意,但是添加一个 TypeAdapter,好吧,那么您需要一个用于任何自定义类吗?这是不可持续的。
【解决方案2】:

你可以试试这个方法:

String json = "{\"a\":2, \"a\":3}";
Gson gson = new Gson();
Type mapType = new TypeToken<Map<String, String>>() {}.getType();
Map<String, String> map = gson.fromJson(json, mapType);

如果 json 比 JsonObject 更复杂,可以作为映射值类型:

Type mapType = new TypeToken<Map<String, JsonObject>>() {}.getType();

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-23
    • 1970-01-01
    相关资源
    最近更新 更多