AnkeyNigam
AnkeyNigam

Reputation: 2820

Check whether a key exists or not in a nested JSON

I am stuck in a situation where I need to check whether a key exists in a nested JSON object. By nested JSON Object that I am having a JSON object inside the parent JSON object as the value of one of its key. So i need to check whether this key exists in entire JSON object. I am getting the below data as a String object. I know I can parse this String object to get JSON object.

{
"claim_loss_type_cd": "TEL",
"claim_type": "002",
"claim_reason": "001",
"policy_number": "1234kk3366ff664",
"info": {
    "ApplicationContext": {
        "country": "US"
    }
  }
}

I have used containsKey() method to check the key existence in the main JSON object and it works. But for checking any internal JSON object like "info" I need to parse that Object again to JSON object and then check the key again.

        String jsonString = "My JSON String here";
        JSONObject finalResponse = new JSONObject(jsonString);
        finalResponse.containsKey("country"); // will return false
        JSONObject intermediateResponse = (JSONObject)finalResponse.get("info");
        intermediateResponse.containsKey("country"); // will return true

So is there any better way, any API or method which can check inside any internal JSON object as well without the need of parsing the internal JSON object. I am using com.ibm.json.java.JSONObject.JSONObject() native IBM library for Websphere Application Server and No additional JSON parsers I am using.

Considering the above JSON, like "claim_type" is a key in parent JSON object but "info" in itself a JSON object. So what i need to do is to check whether a key exists in complete JSON, either in parent or any of its child JSON object like key "country" here in example.

EDIT:

Thanks to @chsdk I came to a solution. But if anyone else came to any solution using some other API, please respond, because below solution is taking recursion into account & might have big Space/Time Complexity.

public static boolean checkKey(JSONObject object, String searchedKey) {
    boolean exists = object.containsKey(searchedKey);
    if(!exists) {      
         Set<String> keys = object.keySet();
         for(String key : keys){
             if ( object.get(key) instanceof JSONObject ) {
                    exists = checkKey((JSONObject)object.get(key), searchedKey);
            }
         }
    }
    return exists;
}

Upvotes: 8

Views: 41097

Answers (4)

raguraman
raguraman

Reputation: 1

I faced similar issue to overcome, converted JSON to Map and collecting key value pair and iterating over them to get the values which i required (its kind of calling same method again and again but feels better than recursive programming.hopefully it helps).

public static void jsonToMap(String t) throws JSONException {

    Map<String,String> map = new HashMap<>();
    getJsonObjectMap(t).entrySet()
        .stream()
        .filter(s->s.getKey().equals("info"))
        .forEach(u -> {
            try {
                getJsonObjectMap(u.getValue()).forEach(map::put);
            } catch (JSONException e) {
                e.printStackTrace();
            }
        });
        
    map.entrySet().forEach(System.out::println);

}

private static Map<String,String> getJsonObjectMap(String t) throws JSONException {

    HashMap<String,String>  map = new HashMap<>();
    JSONObject jObject = new JSONObject(t);
    Iterator<?> keys = jObject.keys();
    while( keys.hasNext() ){
        String key = (String)keys.next();
        String value = jObject.getString(key);
        map.put(key, value);
    }
    return map;
}

Upvotes: 0

RuWi89
RuWi89

Reputation: 1

Both solutions, which suggest to iterate the JsonObject recursively, have a little bug: they don't break the iteration when they finally find the searched key. So you have to break the while-loop, otherwise the loop will continue and if there is a next key, it will check this key and so on. The code example, which searches for the "country"-key only works, because 'country' is coincidentally the last key in its JsonObject.

Example:

 /* ... */
    while (keys.hasNext()) {
          nextKey = (String) keys.next();

          try {
            if (json.get(nextKey) instanceof JSONObject) {
              exists = hasKey(json.getJSONObject(nextKey), key);

              if(exists){
                  break;
              }

            }
          } catch (JSONException e) {
            e.printStackTrace();
          }
        }
    /* ... */

Upvotes: 0

Zon
Zon

Reputation: 19880

A ready-to-go method with correct casting of types:

/**
 * JSONObject contains the given key. Search is also done in nested 
 * objects recursively.
 *
 * @param json JSONObject to serach in.
 * @param key Key name to search for.
 * @return Key is found.
 */
public static boolean hasKey(
  JSONObject json,
  String key) {

  boolean exists = json.has(key);
  Iterator<?> keys;
  String nextKey;

  if (!exists) {

    keys = json.keys();

    while (keys.hasNext()) {
      nextKey = (String) keys.next();

      try {
        if (json.get(nextKey) instanceof JSONObject) {
          exists =
            hasKey(
              json.getJSONObject(nextKey),
              key);
        }
      } catch (JSONException e) {
        e.printStackTrace();
      }
    }
  }

  return exists;
}

Upvotes: 0

cнŝdk
cнŝdk

Reputation: 32145

You can use JSONObject to parse your json and use its has(String key) method to check wether a key exists in this Json or not:

 String str="{\"claim_loss_type_cd\": \"TEL\",\"claim_type\":\"002\",\"claim_reason\": \"001\",\"policy_number\":\"1234kk3366ff664\",\"info\": {\"ApplicationContext\":{\"country\": \"US\"}}}";
 Object obj=JSONValue.parse(str);
 JSONObject json = (JSONObject) obj;
 //Then use has method to check if this key exists or not
 System.out.println(json.has("claim_type")); //Returns true

EDIT:

Or better you can simply check if the JSON String contains this key value, for example with indexOf() method:

String str="{\"claim_loss_type_cd\": \"TEL\",\"claim_type\":\"002\",\"claim_reason\": \"001\",\"policy_number\":\"1234kk3366ff664\",\"info\": {\"ApplicationContext\":{\"country\": \"US\"}}}";
System.out.println(str.indexOf("claim_type")>-1); //Returns true

EDIT 2:

Take a look at this method, it iterates over the nested objects to check if the key exists.

public boolean keyExists(JSONObject  object, String searchedKey) {
    boolean exists = object.has(searchedKey);
    if(!exists) {      
        Iterator<?> keys = object.keys();
        while( keys.hasNext() ) {
            String key = (String)keys.next();
            if ( object.get(key) instanceof JSONObject ) {
                    exists = keyExists(object.get(key), searchedKey);
            }
        }
    }
    return exists;
}

Object obj=JSONValue.parse(str);
JSONObject json = (JSONObject) obj;
System.out.println(keyExists(json, "country")); //Returns true

Upvotes: 8

Related Questions