Jackson 2 ObjectMapper
class defines numerous generic methods for deserializing JSON strings, byte arrays, files, etc. to given Java types.
Target type is given in an argument to those methods.
Eg. a type may be given as a Class<T>
, like in the method
public <T> T readValue(String content, Class<T> valueType)
which returns the same T
object (and thus is type-safe to use).
But it may also be given as a TypeReference<T>
(which can encode a complex generic type), so one can build eg. new TypeReference<List<Long>> { }
to tell ObjectMapper
that the input needs to be deserialized into a list of longs – it can be passed eg. into the method:
@SuppressWarnings({ "unchecked", "rawtypes" })
public <T> T readValue(String content, TypeReference valueTypeRef)
But that method takes raw TypeReference
and not a generic TypeReference<T>
, and thus one needs to manually add a generic parameter to the call:
objectMapper.<List<Long>>readValue(input, listOfLongs)
and if one makes a mistake in the provided type, the compiler cannot catch that. That would not be a problem if the method signature was
public <T> T readValue(String content, TypeReference<T> valueTypeRef)
which would tell the compiler that the returned value is always of the same type as the generic parameter of provided TypeReference
, similarly to how it works with Class<T>
.
My question is – what is the reason behind such an API? Why do Jackson methods take raw TypeReference
? Are there any valid cases when returned object is really of a different type that that referenced by generic parameter of TypeReference
?
PS: What also puzzles me is that a corresponding convertValue
method takes not a raw type, but a wildcard one:
public <T> T convertValue(Object fromValue, TypeReference<?> toValueTypeRef)
and similarly readValues
:
public <T> MappingIterator<T> readValues(JsonParser p, TypeReference<?> valueTypeRef)
and the readValue(JsonParser, TypeReference)
actually takes a fully qualified generic parameter:
public <T> T readValue(JsonParser p, TypeReference<T> valueTypeRef)
It is already reported as an issue, but was labeled as 3.x
.
There's a comment by the author of the library that explains why this hasn't been corrected yet:
Looks like
ObjectMapper
API (and perhapsObjectReader
too) omits type-variable matching withTypeReference
. This would make sense to change, but is likely to cause some source-compatibility issues (not binary), so perhaps do this in 3.0 and not earlier.