8

I have a json string which I need to validate and find any other keys other than in a list is there in the json string. The sample json string is

{
    "required" : true,
    "requiredMsg" : "Title needed",
    "choices" : [ "a", "b", "c", "d" ],
    "choiceSettings" : {
        "a" : {
            "exc" : true
        },
        "b" : { },
        "c" : { },
        "d" : {
            "textbox" : {
                "required" : true
            }
        }
    },
    "Settings" : {
        "type" : "none"
    }
}

To allow only predifined keys is exsist in the json string I want to get all the keys in the json string. How can I obtain all the keys in the json string. I am using jsonNode. My code till now is

        JsonNode rootNode = mapper.readTree(option);
        JsonNode reqiredMessage = rootNode.path("reqiredMessage");             
        System.out.println("msg   : "+  reqiredMessage.asText());            
        JsonNode drNode = rootNode.path("choices");
        Iterator<JsonNode> itr = drNode.iterator();
        System.out.println("\nchoices:");
        while (itr.hasNext()) {
            JsonNode temp = itr.next();
            System.out.println(temp.asText());
        }    

How to get all the keys from the json string using JsonNode

iAmOren
  • 2,760
  • 2
  • 11
  • 23
Senchu Thomas
  • 518
  • 3
  • 9
  • 24

4 Answers4

16

forEach will iterate over children of a JsonNode (converted to String when printed) and fieldNames() gets an Iterator<String> over keys. Here are some examples for printing elements of the example JSON:

JsonNode rootNode = mapper.readTree(option);

System.out.println("\nchoices:");
rootNode.path("choices").forEach(System.out::println);

System.out.println("\nAllKeys:");
rootNode.fieldNames().forEachRemaining(System.out::println);

System.out.println("\nChoiceSettings:");
rootNode.path("choiceSettings").fieldNames().forEachRemaining(System.out::println);

You'll probably need fields() at some point that returns an Iterator<Entry<String, JsonNode>> so you can iterate over key, value pairs.

Manos Nikolaidis
  • 21,608
  • 12
  • 74
  • 82
6

This should do it.

Map<String, Object> treeMap = mapper.readValue(json, Map.class);

List<String> keys  = Lists.newArrayList();
List<String> result = findKeys(treeMap, keys);
System.out.println(result);

private List<String> findKeys(Map<String, Object> treeMap , List<String> keys) {
    treeMap.forEach((key, value) -> {
      if (value instanceof LinkedHashMap) {
        Map<String, Object> map = (LinkedHashMap) value;
        findKeys(map, keys);
      }
      keys.add(key);
    });

    return keys;
  }

This will print out result as

[required, requiredMsg, choices, exc, a, b, c, required, textbox, d, choiceSettings, type, Settings]
pvpkiran
  • 25,582
  • 8
  • 87
  • 134
3

The accepted answer works out great but issues a warning, "Type safety: The expression of type Map needs unchecked conversion to conform to Map <String, Object>"

This answer led me to change that line to the following to eliminate the warning:

Map<String, Object> treeMap = mapper.readValue(json, new TypeReference<Map<String, Object>>() {}); 
Dave
  • 31
  • 4
0

List in the json was not supported in the accepted solution. Here is what I propose:

public List<String> getAllNodeKeys(String json) throws JsonProcessingException {
    Map<String, Object> treeMap = objectMapper.readValue(json, new TypeReference<>() {
    });
    return findKeys(treeMap, new ArrayList<>());
}

private List<String> findKeys(Map<String, Object> treeMap, List<String> keys) {
    treeMap.forEach((key, value) -> {
        if (value instanceof LinkedHashMap) {
            LinkedHashMap map = (LinkedHashMap) value;
            findKeys(map, keys);
        } else if (value instanceof List) {
            ArrayList list = (ArrayList) value;
            list.forEach(map -> findKeys((LinkedHashMap) map, keys));

        }
        keys.add(key);
    });

    return keys;
}
Eric
  • 1
  • - While your answer may solve the question, [including an explanation](https://meta.stackexchange.com/q/114762) of how and why this solves the problem would really help to improve the quality of your post, and probably result in more up-votes. Remember that you are answering the question for readers in the future, not just the person asking now. You can edit your answer to add explanations and give an indication of what limitations and assumptions apply. - [From Review]() – Adam Marshall Feb 02 '21 at 15:53