Jackson JsonNode
- JsonNode vs. ObjectNode
- Read JsonNode From JSON
- Write JsonNode to JSON
- Get JsonNode Field
- Get JsonNode Field At Path
- Convert JsonNode Field
- Handling Null Field Values
- Traverse JsonNode Graph
- Create an ObjectNode
- Set ObjectNode Field
- Put ObjectNode Field With Primitive Value
- Remove Field
- Iterate JsonNode Fields
- Iterate JsonNode Field Names
Jakob Jenkov |
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); }
Tweet | |
Jakob Jenkov |