Some notes on Jackson’s ObjectMapper
, when using it without any custom POJO classes, to deserialize an arbitrary piece of JSON to a Java Map
.
I have some arbitrary JSON:
|
|
I can use these classes to deserialize this JSON to an object:
I can use ObjectMapper
on its own using a raw, untyped java.util.Map
:
|
|
This gives me all the Java data types I expect:
But it uses a raw Map
. This is not the right approach - not type-safe and not self-documenting.
Or, I can use Jackson’s TypeReference
with my ObjectMapper
:
|
|
This new TypeReference<Map<String, Object>>() {}
means the map is no longer untyped. It creates the exact same end result as the first example.
This is still not ideal, because you will be dealing with unknown types at runtime, for those Object
values. But it avoids the need for customized POJO classes, as well as avoiding the raw Map
.
Another way to use TypeReference
is as follows:
|
|
Note the use of {}
in the syntax for declaring the new TypeReference
. TypeReference
is an abstract class. The {}
provides an empty implementation via an anonymous class, without which you would get a compile-time error:
TypeReference is abstract; cannot be instantiated
Digression…
You may sometimes (rarely?) see {{}}
syntax - this is Java’s double brace initialization. Consider this code:
|
|
This creates a list containing two values.
The outer braces create an anonymous class derived from the specified class (ArrayList
in this case). The inner braces define an initialiser block within the inner class.
So, when we have single {}
braces like we do in the TypeReference
usage, that means there is no initializer block in the inner class. In fact there is nothing at all in the anonymous class - it is completely empty.
I think this double-brace syntax is relatively rare. I have never seen it outside of tutorials and Stack Overflow questions. And blog posts discouraging its use.
…end digression.
You cannot execute this code:
|
|
It will throw a runtime error:
IllegalArgumentException TypeReference constructed without actual type information
You can see how this is caught in the source code here:
|
|
Final note: The TypeReference
class implements Comparable
. The javadoc states that this is because doing so forces a compile-time check to ensure you have provided a type when instantiating a new TypeReference
object:
The class uses a…
…bogus implementation of Comparable (any such generic interface would do, as long as it forces a method with generic type to be implemented), to ensure that a Type argument is indeed given.
and:
compareTo(): The only reason we define this method (and require implementation of Comparable) is to prevent constructing a reference without type information.
In reality, however, none of this appears to be the case. As we have already seen, there is no compile time error for the following code:
|
|
The javadoc does not appear to be correct, here. Maybe it was in an earlier version of Java.
This is how they do it:
|
|