amorfis amorfis - 6 months ago 32
JSON Question

Make Gson throw exception on parsing JSON with duplicated key

I'm parsing simple JSON object with Gson. I want it to throw some error when key name is duplicated. E.g.

{
a: 2,
a: 3
}


In my case, Gson parses such JSON and sets a to 3. I want it to throw some exception.

I know I can parse JSON as map, and then Gson throws exception in such case, but only if the duplicated key is not nested in the map. If I have e.g. JSON like this:

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


Still, it is parsed without any exception and I have only one "dup" with value 2.

Can I somehow setup Gson to throw error in such case? Or to have duplicated entries in
JsonObject
instance, so that I can detect it myself (but I doubt that, as it would be invalid
JsonObject
)

Reproducible example

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


prints out

{"a":3}

Answer

1) You may edit the source of gson a little bit. This is just a suggestion to understand how things work. I don't advice you to use this on a real/production environment.

Gson uses com.google.gson.internal.LinkedTreeMap while parsing a json string to a JsonObject. For testing issues you can copy that class into your project with the same name and package name. And edit its put method to not allow duplicate keys.

    @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) Another clean solution is to define custom classes which are going to map to your json strings. Then write their custom TypeAdapters

3) Do it by using a Deserializer? I don't think it is possible. If you try to use it you'll see that you already have a jsonObject there which your duplicate keys are handled as one.