-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Deserializer Discovery 2.x
This page describes the process of discovering JsonDeserializers for POJO (aka Bean) types in Jackson 2.x
JsonDeserializers are needed for reading JSON (and other supported formats) from JsonParser and constructing desired Java Objects. Discovery process is initiated by 3 entities:
-
ObjectMapperto locate deserializer to use for target type indicated forreadValue()method (andreadValues(),convertValue()) -
ObjectReader(similar toObjectMapper) - Deserializers themselves, to locate "child deserializers": for example when deserializing
Lists, deserializer for elements contained is separate from deserializer forListitself (and similarly for other structured types likejava.util.Maps, Arrays, POJOs)
Discovery process for these cases is almost identical (and in fact, (1) and (2) are identical), differing only in that for (3), contextualization (via method DeserializationContext._handleSecondaryContextualization(...)) passes referring property definition (BeanProperty) whereas one does not exist for "root" values.
Two terms for deserializers (as defined by ResolvableDeserializer and ContextualDeserializer) are:
- Resolution is needed to handle cyclic dependencies between deserialializers: this is mostly relevant for
BeanDeserializer. - Contextualization is needed to give initially context-free (only based on Type) deserializers access to annotations added to property (that is, on Field and/or Method and/or Constructor parameter).
Understanding this processing is not strictly necessary to understand call flow, but is useful to know since these are referenced in couple of places.
The first step to trigger discovery is ObjectMapper (and other entities mentioned earlier) calling one of:
- Explicit
findXxxDeserializer()method such asfindRootValueDeserializer() - One of
readXxxValue()convenience methods likereadValue()which will need to call one offindXxxDeserializer()methods
Either way method like findRootValueDeserializer() is called; and this is the call path we will focus on.
Big part of actual discovery is handled by DeserializerCache: the main entry point is method findValueDeserializer().
It will not only handle caching of constructed and resolved (but not contextualized) deserializers but also:
- Mapping of
abstractJava types (as well asMapandCollectiontypes) into concrete (forabstract) and default (Map,Collection) implementation types - Introspecting
BeanDescription(of typeBasicBeanDescription) for type indicated - Handling annotations on Java types (Classes) that directly indicate
JsonDeserializerto use (@JsonDeserialize(using = IMPL_CLASS)) - Refinement of actual type to use (
@JsonDeserialize(as = CONCRETE_TYPE)); and re-introspectingBeanDescriptionfor refined type - Use of "converting" deserializers indicated by annotation (and directly constructing
StdDelegatingDeserializeras needed) - Calling appropriate method of configured
DeserializerFactoryto actually constructJsonDeserializerto use - Resolution of
ResolveDeserializers, to avoidStackOverflowErrorfor cyclic types (put another way: allowing use of cyclic type definitions)
and last but not least:
- Calling type-specific method in
DeserializerFactoryas necessary to actually construct deserializer.
With given target JavaType and introspected BeanDescription, cache will call one of following methods of DeserializerFactory (selected in following order)
-
createEnumDeserializer()(ifJavaType.isEnumType()returnstrue) -
createArrayDeserializer()(JavaType.isArrayType()) -
createMapDeserializer()/createMapLikeDeserializer()("Map-like" types refer to Scala (f.ex) types that act likejava.util.Mapbut do not implement that interface) -
createCollectionDeserializer()/createCollectionLikeDeserializer()("Collection-like" types similarly refer to Scala's collection types that work similar tojava.util.Collectionbut do not implement it) -
createReferenceDeserializer()for types likeAtomicReference<>(JDK),Optional(JDK 8+, Guava),Option(Scala) -
createTreeDeserializer()forJsonNode(and subtypes) -
createBeanDeserializer()if none of above matches
We will focus on the last case, in which general POJO (aka "Bean") deserializers are constructed.
Actual DeserializerFactory used is BeanDeserializerFactory, which extends BasicDeserializerFactory (which implements DeserializerFactory except for createBeanDeserializer()).
Here we will focus on BeanDeserializerFactory.createBeanDeserializer() implementation.