Jackson JsonNode

Jakob Jenkov
Last update: 2020-06-02

The Jackson JsonNode class, com.fasterxml.jackson.databind.JsonNode is Jackson's tree model (object graph model) for JSON. Jackson can read JSON into a JsonNode instance, and write a JsonNode out to JSON. This Jackson JsonNode tutorial will explain how to deserialize JSON into a JsonNode and serialize a JsonNode to JSON. This Jackson JsonNode tutorial will also explain how to build JsonNode object graphs from scratch, so you can serialize them to JSON later.

JsonNode vs. ObjectNode

The Jackson JsonNode class is immutable. That means, that you cannot actually build an object graph of JsonNode instances directly. Instead, you create an object graph of the JsonNode subclass ObjectNode. Being a subclass of JsonNode you can use the ObjectNode everywhere you can use a JsonNode. You will see how to do build ObjectNode graphs later in this tutorial.

Read JsonNode From JSON

To read JSON into a JsonNode with Jackson, you start by creating a Jackson ObjectMapper instance. On the ObjectMapper instance you call readTree() passing the JSON source as parameter. Here is an example of deserializing JSON into a JsonNode:

String json = "{ \"f1\" : \"v1\" } ";

ObjectMapper objectMapper = new ObjectMapper();

JsonNode jsonNode = objectMapper.readTree(json);

System.out.println(jsonNode.get("f1").asText());

Write JsonNode to JSON

To write a JsonNode into JSON with Jackson, you also need a Jackson ObjectMapper instance. On the ObjectMapper you call the writeValueAsString() method, or whatever write method that fits your needs. Here is an example of writing a JsonNode to JSON:

ObjectMapper objectMapper = new ObjectMapper();

JsonNode jsonNode = readJsonIntoJsonNode();

String json = objectMapper.writeValueAsString(jsonNode);

The readJsonIntoJsonNode() method is just a method I have created which parses a JSON string into a JsonNode - just so we have a JsonNode to write. The exact contents of readJsonIntoJsonNode() is not really important for this example, as long as you know it produces a JsonNode object. What matters is the following line that calls the ObjectWriter writeValueAsString() method, which writes the JsonNode into a JSON string.

The Jackson ObjectMapper has many more write methods you can use than writeValueAsString(). You can see these methods in the Jackson ObjectMapper Tutorial.

Get JsonNode Field

A JsonNode can have fields just like a JSON object has. Imagine you have parsed the following JSON into a JsonNode:

{
    "field1" : "value1",
    "field2" : 999
}

This JSON object has two fields named field1 and field2. If you had a Jackson JsonNode representing the above JSON object, you could obtain the two fields like this:

JsonNode jsonNode = ... //parse above JSON into a JsonNode

JsonNode field1 = jsonNode.get("field1");
JsonNode field2 = jsonNode.get("field2");

Notice, that even if the two fields are String fields, the get() method always returns a JsonNode to represent the field.

Get JsonNode Field At Path

The Jackson JsonNode has a special method called at() . The at() method can access a JSON field from anywhere in the JSON graph which the given JsonNode is the root of. Imagine that the JSON structure looks like this:

{
  "identification" :  {
        "name" : "James",
        "ssn: "ABC123552"
    }
}

If this JSON was parsed into a JsonNode you could access the name field using the at() method, like this:

JsonNode nameNode = jsonNode.at("/identification/name");

Notice the parameter passed to the at() method: The string /identification/name . This is a JSON path expression. This path expression specifies the complete path from the root JsonNode and down to the field you want to access the value of. This is similar to the path to a file from the root of the file system down to the file in a Unix file system.

Notice the JSON path expression must start with a slash character ( the / character).

The at() method returns a JsonNode which represents the JSON field you requested. To get the actual value of the field you need to call one of the methods covered in the next section. If no node matches the given path expression, null will be returned.

Convert JsonNode Field

The Jackson JsonNode class contains a set of methods that can convert a field value to another data type. For instance, convert a String field value to a long, or the other way around. Here is an example of converting a JsonNode field to some of the more common data types:

String f2Str = jsonNode.get("f2").asText();
double f2Dbl = jsonNode.get("f2").asDouble();
int    f2Int = jsonNode.get("f2").asInt();
long   f2Lng = jsonNode.get("f2").asLong();

Imagine the f2 field contains the value 123456, then it is possible to convert that value to a String, double, int and long as shown above.

Convert With Default Value

In case a field can be null inside a JsonNode, then you can provide a default value when you try to convert it. Here is an example of calling the conversion methods with default values:

ObjectMapper objectMapper = new ObjectMapper();

String json = "{ \"f1\":\"Hello\", \"f2\":null }";

JsonNode jsonNode = objectMapper.readTree(json);

String f2Value = jsonNode.get("f2").asText("Default");

As you can see in the JSON string in the example, the f2 field is declared, but set to null. In that case, the call jsonNode.get("f2").asText("Default") will return the default value, which in this example is the string Default.

The asDouble(), asInt() and asLong() methods can also take default parameter values, which are returned in case the field you try to get the value from is null.

Please note, that if the field is not explicitly set to null in the JSON, but is missing from the JSON, then the call jsonNode.get("fieldName") will return a Java null value, on which you cannot call asInt(), asDouble(), asLong() or asText(). If you try that, you will get a NullPointerException. Here is an example illustrating that situation:

 ObjectMapper objectMapper = new ObjectMapper();

String json = "{ \"f1\":\"Hello\" }";

JsonNode jsonNode = objectMapper.readTree(json);

JsonNode f2FieldNode = jsonNode.get("f2");

After running this code, the f2FieldNode variable will point to null.

Handling Null Field Values

Let me just spend a moment to explore how you handle null values in the Jackson JsonNode. There are two ways in which a field inside a JsonNode can be null. The first way is, if the field is completely missing from the JSON from which the JsonNode was created. Here is an example of a simple JSON string that only contains a single field:

ObjectMapper objectMapper = new ObjectMapper();

String json = "{ \"f1\":\"Hello\" }";

JsonNode jsonNode = objectMapper.readTree(json);

JsonNode f2FieldNode = jsonNode.get("f2");

In the example above, there is no field named f2 . Thus, the jsonNode.get("f2") method call will return null. Look at this example instead:

ObjectMapper objectMapper = new ObjectMapper();

String json = "{ \"f1\":\"Hello\" \"f2\":null }";

JsonNode jsonNode = objectMapper.readTree(json);

JsonNode f2FieldNode = jsonNode.get("f2");

In this example the JSON string contains a field named f2 but its value is null. This time the jsonNode.get("f2") method call will return a valid JsonNode which represents the value null. You can check if a JsonNode represents the null value by calling its isNull() method, like this:

boolean isFieldValueNull = f2FieldNode.isNull();

In order to do a proper null check of a JsonNode field, you must do like this:

JsonNode fieldNode = parentNode.get("fieldName");

if(fieldNode == null || fieldNode.isNull()) {
    // the field is either not present in parentNode, or explicitly set to null .
}

This if - statement will catch both when the field is missing in the parentNode and when the field is present but set to null.

Traverse JsonNode Graph

A JsonNode that represents a JSON object or JSON array can be traversed like any other object graph. You do so by iterating its nested fields (or nested elements in case of an array). Here is an example of traversing all nested fields of a JsonNode representing a JSON object or JSON array:

public static void traverse(JsonNode root){
    
    if(root.isObject()){
        Iterator<String> fieldNames = root.fieldNames();

        while(fieldNames.hasNext()) {
            String fieldName = fieldNames.next();
            JsonNode fieldValue = root.get(fieldName);
            traverse(fieldValue);
        }
    } else if(root.isArray()){
        ArrayNode arrayNode = (ArrayNode) root;
        for(int i = 0; i < arrayNode.size(); i++) {
            JsonNode arrayElement = arrayNode.get(i);
            traverse(arrayElement);
        }
    } else {
        // JsonNode root represents a single value field - do something with it.
        
    }
}

Note, that you will probably have to modify this example to fit your own use case. The exact implementation will depend a bit on what you need to do with the traversed nodes. However, you can use the example above as template, and then modify it until it does what you need it to.

Create an ObjectNode

As mentioned earlier, the JsonNode class immutable. To create a JsonNode object graph you must be able to mutate the JsonNode instances in the graph, e.g. setting property values and child JsonNode instances etc. Being immutable, you cannot do that directly with a JsonNode.

Instead you create an ObjectNode instance which is a subclass of JsonNode. Here is an example of creating an ObjectNode via the Jackson ObjectMapper createObjectNode() method:

ObjectMapper objectMapper = new ObjectMapper();

ObjectNode objectNode = objectMapper.createObjectNode();

Set ObjectNode Field

To set a field on a Jackson ObjectNode you can call its set() method, passing a field name String and JsonNode as parameters. Here is an example of setting a field on an Jackson ObjectNode :

ObjectMapper objectMapper = new ObjectMapper();
ObjectNode parentNode = objectMapper.createObjectNode();

JsonNode childNode = readJsonIntoJsonNode();

parentNode.set("child1", childNode);

Again, just imagine that the readJsonIntoJsonNode() produces some JsonNode object which we would like to set as child on the ObjectNode parent object.

Put ObjectNode Field With Primitive Value

The ObjectNode class also has a set of methods that enables you to put (set) primitive values for fields. This is easier than trying to convert a primitive value to a JsonNode and set it with set(). Here is an example of setting a string value for a field on an ObjectNode with the put() method:

objectNode.put("field1", "value1");
objectNode.put("field2", 123);
objectNode.put("field3", 999.999);

Remove Field

The ObjectNode class has a method called remove() which can be used to remove fields from the ObjectNode. Here is an example that removes a field from a Jackson ObjectNode via its remove() method:

objectNode.remove("fieldName");

Iterate JsonNode Fields

You can obtain all fields from a JsonNode using the JsonNode fields() method. Here is an example of obtaining and iterating all fields from a JsonNode using fields() :

Iterator<Map.Entry<String, JsonNode>> fields = jsonNode.fields();

while(fields.hasNext()) {
    Map.Entry<String, JsonNode> field = fields.next();
    String   fieldName  = field.getKey();
    JsonNode fieldValue = field.getValue();

    System.out.println(fieldName + " = " + fieldValue.asText());
}

Iterate JsonNode Field Names

The JsonNode class has a method named fieldNames() which returns an Iterator that enables you to iterate all the field names of the JsonNode. You can use the field names to get the field values. Here is an example of iterating all the field names and values of a Jackson JsonNode:

Iterator<String> fieldNames = jsonNode.fieldNames();

while(fieldNames.hasNext()) {
    String fieldName = fieldNames.next();

    JsonNode field = jsonNode.get(fieldName);
}

Jakob Jenkov

Featured Videos

Java ConcurrentMap + ConcurrentHashMap

Java Generics

Java ForkJoinPool

P2P Networks Introduction

















Close TOC
All Tutorial Trails
All Trails
Table of contents (TOC) for this tutorial trail
Trail TOC
Table of contents (TOC) for this tutorial
Page TOC
Previous tutorial in this tutorial trail
Previous
Next tutorial in this tutorial trail
Next