'How do you tree walk JSON via Jackson 2 JsonNode?

This was a bit of an exercise in frustration made worse by the fact that I couldn't find any answers to this question. So I'm going to answer the question here.

What I find most difficult to understand was that JsonNode doesn't have any getName() or similar method which I was expecting given that JSON is a name:value data type. Though I realised after working out this solution that arrays aren't name:value.

See answer below.



Solution 1:[1]

This is just an updated variation on HankCa's excellent answer. Under Java 8 and later, you can use Iterator.forEachRemaining() to loop through and you can externalize the consumer. Here's an updated version:

package treeWalker;

import java.io.IOException;
import java.util.function.BiConsumer;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

public class TreeWalker
{
    public JsonNode convertJSONToNode(String json) throws JsonProcessingException, IOException
    {
        ObjectMapper mapper = new ObjectMapper();
        JsonNode jsonNode = mapper.readTree(json);

        return jsonNode;
    }

    public void walkTree(JsonNode root, BiConsumer<String, String> consumer)
    {
        walker(null, root, consumer);
    }

    private void walker(String nodename, JsonNode node, BiConsumer<String, String> consumer)
    {
        String nameToPrint = nodename != null ? nodename : "must_be_root";
        if (node.isObject())
        {
            node.fields().forEachRemaining(e->walker(e.getKey(), e.getValue(), consumer));
        }
        else if (node.isArray())
        {
            node.elements().forEachRemaining(n->walker("array item of '" + nameToPrint + "'", n, consumer));
        }
        else
        {
            if (node.isValueNode())
            {
                consumer.accept(nameToPrint, node.asText());
            }
            else
            {
                throw new IllegalStateException("Node must be one of value, array or object.");
            }
        }
    }
}

Here's the unit test class (Now in Junit5):

package treeWalker;

import java.io.IOException;

import org.junit.jupiter.api.Test;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;


public class TreeWalkerTest
{
    TreeWalker treeWalker = new TreeWalker();

    private String getJSON()
    {
        String json = "{\"a\":\"val_a\",\"b\":\"val_b\",\"c\":[1,2,3]}";
        return json;
    }

    @Test
    public void testConvertJSONToNode() throws JsonProcessingException, IOException
    {
        String json = getJSON();

        JsonNode jNode = treeWalker.convertJSONToNode(json);

        System.out.println("jnode:" + jNode);

    }

    @Test
    public void testWalkTree() throws JsonProcessingException, IOException
    {
        JsonNode jNode = treeWalker.convertJSONToNode(getJSON());

        treeWalker.walkTree(jNode, (a,b)->System.out.println("name='" + a + "', value='" + b + "'."));
    }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Rob McDougall