1. Introduction
In this short post, I would like to explain the difference between the NullNode and null value when working with Jackson library.
Although these two seem nearly exactly the same, we should be aware of the difference between them and apply appropriate handling in our codebase. Without this knowledge, we may introduce an unexpected behavior to application, which might be hard to track down later.
2. NullNode vs null value
So without further ado, let’s clarify the difference between a NullNode and null:
- the NullNode is a singleton class used to contain an explicit JSON null value
- null value, in terms of dealing with JsonNode, simply means that name/value pair does not exist for a given name
To better visualize this, let’s see the following example:
val mapper = ObjectMapper() val someObject = mapper.readTree(""" { "id": 1, "age": null } """) val id = someObject.get("id") // IntNode val age = someObject.get("age") // NullNode val name = someObject.get("name") // null
As we can see, the age value set explicitly to null results in a NullNode instance being created. On the other hand, a missing name field will lead to a null value on get().
3. Unexpected Behavior Example
With that being said, let’s imagine that we are working with some external REST API in our application and we would like to perform some action based on whether the age is set for user. For the simplicity, we will print the age value to the output in our example.
Given these requirements, we’ve decided to simply check if the value is not null and based on that perform the action:
val age = someObject.get("age") if(age != null) { println("User age is set to $age") }
Alternatively, we’ve decided to make our Kotlin code even more Kotlin-like with let:
someObject.get("age") ?.let { ageValue -> println("User age is set to [$ageValue]") }
As we can see, the above code will result in totally different behavior depending on whether the age property was set as null explicitly, or not.
To be even more specific, missing value won’t produce any output, whereas "age" : null
will print “User age is set to [null].”.
4. Solution
Although the above example is harmless, we should never let that happen and handle appropriately depending on our needs.
One of the possible ways to work with Nullnode and null value in Kotlin could be an additional type check:
if(age != null && age !is NullNode) { println("User age is set to $age") }
Although this is not the most beautiful solution, it makes our code insensitive to the way external API serialized age value.
Alternatively, Jackson library comes with plenty of handy methods, like isXYZ (example: isBoolean()
, isLong()
, isNumber()
etc.):
if (age.isNumber) { println("User age is set to $age") }
This way, we can make sure that our code will be invoked only if the node represents a numeric JSON value.
As I’ve mentioned above, JsonNode class comes with plenty of methods, which can help us to prevent our code from failure and I highly encourage you to check out the documentation.
5. Summary
And that would be all for this short article covering NullNode and null value differences in Jackson. I am more than sure, that this knowledge, will keep you from making mistakes in the future.
Have you ever encountered similar “tricky” situations in your code with Jackson or any other library? If so, could you please share it with others in the comment section or by using a contact form?
Have a great week!