60

How can I receive the node names from a JSON tree using Jackson? The JSON-File looks something like this:

{  
    node1:"value1",
    node2:"value2",
    node3:{  
        node3.1:"value3.1",
        node3.2:"value3.2"
    }
}

I have

JsonNode rootNode = mapper.readTree(fileReader);

and need something like

for (JsonNode node : rootNode){
    if (node.getName().equals("foo"){
        //bar
  }
}

thanks.

mkobit
  • 43,979
  • 12
  • 156
  • 150
Oskar Alfons
  • 655
  • 1
  • 6
  • 8

5 Answers5

84

For Jackson 2+ (com.fasterxml.jackson), the methods are little bit different:

Iterator<Entry<String, JsonNode>> nodes = rootNode.get("foo").fields();

while (nodes.hasNext()) {
  Map.Entry<String, JsonNode> entry = (Map.Entry<String, JsonNode>) nodes.next();

  logger.info("key --> " + entry.getKey() + " value-->" + entry.getValue());
}
Dave Jarvis
  • 30,436
  • 41
  • 178
  • 315
Supun Sameera
  • 2,683
  • 3
  • 17
  • 14
76

This answer applies to Jackson versions prior to 2+ (originally written for 1.8). See @SupunSameera's answer for a version that works with newer versions of Jackson.


The JSON terms for "node name" is "key." Since JsonNode#iterator() does not include keys, you need to iterate differently:

for (Map.Entry<String, JsonNode> elt : rootNode.fields())
{
    if ("foo".equals(elt.getKey()))
    {
        // bar
    }
}

If you only need to see the keys, you can simplify things a bit with JsonNode#fieldNames():

for (String key : rootNode.fieldNames())
{
    if ("foo".equals(key))
    {
        // bar
    }
}

And if you just want to find the node with key "foo", you can access it directly. This will yield better performance (constant-time lookup) and cleaner/clearer code than using a loop:

JsonNode foo = rootNode.get("foo");
if (foo != null)
{
    // frob that widget
}
Community
  • 1
  • 1
Matt Ball
  • 354,903
  • 100
  • 647
  • 710
  • 12
    It looks as though `getFields()` changed to `fields()` in Jackson 2.0.0. – i_am_jorf Jun 20 '12 at 22:53
  • 2
    Iterating through `String key : rootNode.fieldNames()` gives me `Can only iterate over an array or an instance of java.lang.Iterable` error. Any idea? – THIS USER NEEDS HELP Aug 10 '16 at 17:37
  • 4
    Actually iterating through `Map.Entry entry : rootNode.fields()` also gives the same error for me – THIS USER NEEDS HELP Aug 10 '16 at 17:50
  • 8
    Given that both `fieldNames` and `fields` return `iterator`, which is [not iterable](http://stackoverflow.com/questions/2598219/java-why-cant-iterate-over-an-iterator), the [answer below](http://stackoverflow.com/a/18342245/3831137) seem to be the correct solution, which iterates using `hasNext`. – THIS USER NEEDS HELP Aug 10 '16 at 18:05
  • 1
    I use fasterxml 2.6.7 and all the iterator methods cause infinite loop. – ampofila Sep 07 '16 at 08:20
  • 1. Try this http://pastebin.com/r85AXVm9. It prints "{"type":"http","http":{"binding":"text","url":"http://localhost:9992","httpHeaders":{"Content-Type":"text/plain"},"httpMethod":"GET"},"template":{"rtemplate":"R template","ptemplate":"P template"},"var1":"true","var2":"true"}" forever, instead of 2 times as it is supposed to. – ampofila Sep 14 '16 at 09:05
  • 1
    2. Try this: http://pastebin.com/KR5NKfqy It prints "id="first.item" indefinately. 3. This "for (Map.Entry elt : rootNode.fields())"&"for (String key : rootNode.fieldNames())" do not compile. (foreach does not apply to java.util.Iterator) – ampofila Sep 14 '16 at 09:12
  • 1
    I'm not sure if this was valid prior to Jackson 2+, but it definitely is not anymore (it doesn't compile). Though the gist is correct. But, you need to store off and use the Iterator directly. Fast enumeration works on Iterable objects, not Iterators directly. – stuckj Mar 21 '17 at 17:42
  • @stuckj my original answer is over 5 years old at this point and has been edited multiple times to bring it up to date. And yes, it was originally written in reference to Jackson 1.8. :) Please do feel free to suggest another edit to improve the answer! – Matt Ball Mar 21 '17 at 20:47
  • @MattBall Sure thing. Just having the version specified would be helpful. :) Edit coming... – stuckj Mar 22 '17 at 16:46
  • @stuckj sorry the reviewers rejected your edit :( I edited myself. Thanks again! – Matt Ball Mar 22 '17 at 19:42
  • is null check for elt variable needed ? – Mandar Autade Oct 20 '20 at 03:20
15

fields() and fieldNames() both were not working for me. And I had to spend quite sometime to find a way to iterate over the keys. There are two ways by which it can be done.

One is by converting it into a map (takes up more space):

ObjectMapper mapper = new ObjectMapper();
Map<String, Object> result = mapper.convertValue(jsonNode, Map.class);
for (String key : result.keySet())
{
    if(key.equals(foo))
    {
        //code here
    }
}

Another, by using a String iterator:

Iterator<String> it = jsonNode.getFieldNames();
while (it.hasNext())
{
    String key = it.next();
    if (key.equals(foo))
    {
         //code here
    }
}
Anna Shekhawat
  • 181
  • 2
  • 7
13

Clarification Here:

While this will work:

 JsonNode rootNode = objectMapper.readTree(file);
 Iterator<Map.Entry<String, JsonNode>> fields = rootNode.fields();
 while (fields.hasNext()) {
    Map.Entry<String, JsonNode> entry = fields.next();
    log.info(entry.getKey() + ":" + entry.getValue())
 }

This will not:

JsonNode rootNode = objectMapper.readTree(file);

while (rootNode.fields().hasNext()) {
    Map.Entry<String, JsonNode> entry = rootNode.fields().next();
    log.info(entry.getKey() + ":" + entry.getValue())
}

So be careful to declare the Iterator as a variable and use that.

Be sure to use the fasterxml library rather than codehaus.

ChrisGeo
  • 3,807
  • 13
  • 54
  • 92
  • rootNode.fields() does not compile (Java 7)? – boardtc Jan 15 '19 at 16:20
  • 1
    Then your version of the Jackson library does not support it. – ChrisGeo Jan 15 '19 at 21:58
  • This solution did not compile for me and in my ignorance, I downvoted it which I should not have done. I since learned via another post (https://stackoverflow.com/questions/54205005/how-to-read-the-root-nodes-when-they-only-have-a-value-using-jackson) that it was due to me using the older codehaus jackson when I should have been using the newer fasterxml. However, @ChrisGeo retaliated nastily: http://oi65.tinypic.com/dypp5k.jpg Admin reversed his faux paus. – boardtc Jan 17 '19 at 12:15
  • I tried a bunch of times but I get "You last voted on this answer yesterday. Your vote is now locked in unless this answer is edited.". Can you please edit to say you should use the new fasterxml version of jackson and not the codehaus? – boardtc Jan 17 '19 at 14:39
  • 1
    Man you saved my day. Your `While this will work:` was exactly I was looking for and was struggling around that. – Ajay Kumar Dec 09 '21 at 16:58
7
JsonNode root = mapper.readTree(json);
root.at("/some-node").fields().forEachRemaining(e -> {
                              System.out.println(e.getKey()+"---"+ e.getValue());

        });

In one line Jackson 2+

nash
  • 79
  • 1
  • 1
  • 2
    Welcome to Stack Overflow! Please don't answer just with source code. Try to provide a nice description about how your solution works. See: [How do I write a good answer?](https://stackoverflow.com/help/how-to-answer). Thanks – sɐunıɔןɐqɐp Aug 26 '18 at 20:19
  • 7
    Well, the solution is obvious, what kind of description should he add? – Angel O'Sphere Nov 05 '19 at 13:50