3

I have a String which is in JSON Format

String str = "{\"innerkey1\":\"innervalue1\",
\"innerkey2\":\"innervalue2\",\"innerkey1\":\"innervalue3\"}";

When I am trying to create a object from this string

try  {
    JSONObject obj = new JSONObject(str); 
} catch(Exception e) {
     e.printStackTrace();
}

I am getting an error

org.json.JSONException: Duplicate key "innerkey1"

Is there any way we can create the JSONObject by ignoring the last key from the string?

Ashish Bhumkar
  • 95
  • 1
  • 3
  • 12

5 Answers5

5

You can use objectMapper to skip this error

ObjectMapper mapper = new ObjectMapper();
String json = "{\"name\":\"test\", \"name\":\"new test\"}";

Map<String, Object> map = new HashMap<String, Object>();

map = mapper.readValue(json, new TypeReference<Map<String, String>>(){});

Now you can easily convert to JSONObject from map

new JSONObject(map);
Aristo Michael
  • 2,166
  • 3
  • 35
  • 43
1

This is a problem of the JSON specification. Depending on which specification is used, one can interpret whether duplicate keys are permissible at all. In this thread, it has been widely agreed that the definition is that a key must be unique in a JSONObject.

For this reason, you should not try to parse a probably invalid JSON object, but use a valid one.

But I would have a small suggestion for a solution: However you put it into practice, you could use the (multiple occurring) key and assign all the objects stored there as an array to this (now unique) key. So you merge several identical keys and also merge the linked objects into an array. This would at least make the JSON object valid:

{
    "a" : "x",
    "a" : "y"
}
// becomes
{
    "a" : ["x", "y"]
}
DeBukkIt
  • 86
  • 1
  • 7
0

Unfortunately no. While it isn't technically against JSON standards, it isn't something that can be easily worked with/you'll be hard pressed to find a library that can parse it.

See here: https://stackoverflow.com/a/21833017/8972283

I'd recommend updating how your JSON is being created if possible.

Francis Bartkowiak
  • 1,374
  • 2
  • 11
  • 28
0

It is not the easiest solution, but it allows you to have duplicates in your input string and choose what to do with them (rename, drop, etc). You should use Gson library and register your own TypeAdapter responsible for serialization/deserialization of objects. It would look like this:

class NoDuplicatesAdapter extends TypeAdapter<HashMap<String, String>> {
    @Override
    public void write(JsonWriter out, HashMap<String, String> value) throws IOException {
        out.beginObject();
        for (Map.Entry<String, String> e: value.entrySet()) {
            out.name(e.getKey()).value(e.getValue());
        }
        out.endObject();
    }
    @Override
    public HashMap<String, String> read(JsonReader in) throws IOException {
        final HashMap<String, String> map = new HashMap<>();
        in.beginObject();
        while (in.hasNext()) {
            String name = in.nextName();
            // putting value to the map only if this key is not present;
            // here you can actually find duplicate keys and decide what to do with them
            map.putIfAbsent(name, in.nextString());
        }
        in.endObject();
        return map;
    }
}

It was the most complex part, now we just need to read the JSON string:

String str = "{\"innerkey1\":\"innervalue1\", \"innerkey2\":\"innervalue2\",\"innerkey1\":\"innervalue3\"}";

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

Map<String, String> map = new GsonBuilder()
        .registerTypeAdapter(mapType, new NoDuplicatesAdapter())
        .create()
        .fromJson(str, mapType);

The map will contain only the first "innerkey1".

Kirill Simonov
  • 8,257
  • 3
  • 18
  • 42
0

I have a JSON parser which allows the using code to treat duplicate keys as elements in an array. Refer to the section, "Document Builder Code".

Lawrence Dol
  • 63,018
  • 25
  • 139
  • 189