ValueDeserializer.java
package tools.jackson.databind;
import java.util.Collection;
import tools.jackson.core.*;
import tools.jackson.databind.deser.*;
import tools.jackson.databind.deser.impl.ObjectIdReader;
import tools.jackson.databind.jsontype.TypeDeserializer;
import tools.jackson.databind.type.LogicalType;
import tools.jackson.databind.util.AccessPattern;
import tools.jackson.databind.util.NameTransformer;
/**
* Abstract class that defines API used by {@link ObjectMapper} and {@link ObjectReader}
* to deserialize Objects of arbitrary types from JSON, using
* provided {@link JsonParser} (within current read context of {@link DeserializationContext}.
* Deserializers use delegation so that calls typically end up as a stack of calls
* through deserializer hierarchy based on POJO properties.
*<p>
* Custom deserializers should usually not directly extend this class,
* but instead extend {@link tools.jackson.databind.deser.std.StdDeserializer}
* (or its subtypes like {@link tools.jackson.databind.deser.std.StdScalarDeserializer}).
*<p>
* If deserializer is an aggregate one -- meaning it delegates handling of some
* of its contents by using other deserializer(s) -- it typically also needs
* to implement {@link #resolve}
* which can locate dependent deserializers. This is important to allow dynamic
* overrides of deserializers; separate call interface is needed to separate
* resolution of dependent deserializers (which may have cyclic link back
* to deserializer itself, directly or indirectly).
*<p>
* In addition, to support per-property annotations (to configure aspects
* of deserialization on per-property basis), deserializers may want
* to override
* {@link #createContextual} which allows specialization of deserializers:
* it is passed information on property, and can create a newly configured
* deserializer for handling that particular property.
*<br>
* Resolution of deserializers occurs before contextualization.
*<p>
* NOTE: In Jackson 2.x was named {@code JsonDeserializer}
*/
public abstract class ValueDeserializer<T>
implements NullValueProvider
{
/*
/**********************************************************************
/* Initialization, with former `ResolvableDeserializer`, `ContextualDeserializer`
/**********************************************************************
*/
/**
* Method called after deserializer instance has been constructed
* (and registered as necessary by provider objects),
* but before it has returned it to the caller.
* Called object can then resolve its dependencies to other types,
* including self-references (direct or indirect).
*
* @param ctxt Context to use for accessing configuration, resolving
* secondary deserializers
*/
public void resolve(DeserializationContext ctxt) {
// Default implementation does nothing
}
/**
* Method called to see if a different (or differently configured) deserializer
* is needed to deserialize values of specified property.
* Note that instance that this method is called on is typically shared one and
* as a result method should <b>NOT</b> modify this instance but rather construct
* and return a new instance. This instance should only be returned as-is, in case
* it is already suitable for use.
*
* @param ctxt Deserialization context to access configuration, additional
* deserializers that may be needed by this deserializer
* @param property Method, field or constructor parameter that represents the property
* (and is used to assign deserialized value).
* Should be available; but there may be cases where caller cannot provide it and
* null is passed instead (in which case impls usually pass 'this' deserializer as is)
*
* @return Deserializer to use for deserializing values of specified property;
* may be this instance or a new instance.
*/
public ValueDeserializer<?> createContextual(DeserializationContext ctxt,
BeanProperty property) {
// default implementation returns instance unmodified
return this;
}
/*
/**********************************************************************
/* Main deserialization methods
/**********************************************************************
*/
/**
* Method that can be called to ask implementation to deserialize
* JSON content into the value type this serializer handles.
* Returned instance is to be constructed by method itself.
*<p>
* Pre-condition for this method is that the parser points to the
* first event that is part of value to deserializer (and which
* is never JSON 'null' literal, more on this below): for simple
* types it may be the only value; and for structured types the
* Object start marker or a FIELD_NAME.
* </p>
* <p>
* The two possible input conditions for structured types result
* from polymorphism via fields. In the ordinary case, Jackson
* calls this method when it has encountered an OBJECT_START,
* and the method implementation must advance to the next token to
* see the first field name. If the application configures
* polymorphism via a field, then the object looks like the following.
* <pre>
* {
* "@class": "class name",
* ...
* }
* </pre>
* Jackson consumes the two tokens (the {@code @class} field name
* and its value) in order to learn the class and select the deserializer.
* Thus, the stream is pointing to the FIELD_NAME for the first field
* after the @class. Thus, if you want your method to work correctly
* both with and without polymorphism, you must begin your method with:
* <pre>
* if (p.currentToken() == JsonToken.START_OBJECT) {
* p.nextToken();
* }
* </pre>
* This results in the stream pointing to the field name, so that
* the two conditions align.
* <p>
* Post-condition is that the parser will point to the last
* event that is part of deserialized value (or in case deserialization
* fails, event that was not recognized or usable, which may be
* the same event as the one it pointed to upon call).
*<p>
* <strong>Handling null values (JsonToken.VALUE_NULL)</strong>
* <br>
* : Note that this method is never called for the JSON {@code null} literal to avoid
* every deserializer from having to handle null values. Instead, the
* {@link ValueDeserializer#getNullValue(DeserializationContext)} method
* is called to produce a null value. To influence null handling,
* custom deserializers should override
* {@link ValueDeserializer#getNullValue(DeserializationContext)}
* and usually also {@link ValueDeserializer#getNullAccessPattern()}.
*
* @param p Parser used for reading JSON content
* @param ctxt Context that can be used to access information about
* this deserialization activity.
*
* @return Deserialized value
*/
public abstract T deserialize(JsonParser p, DeserializationContext ctxt)
throws JacksonException;
/**
* Alternate deserialization method (compared to the most commonly
* used, {@link #deserialize(JsonParser, DeserializationContext)}),
* which takes in initialized value instance, to be
* configured and/or populated by deserializer.
* Method is not necessarily used (or supported) by all types
* (it will not work for immutable types, for obvious reasons):
* most commonly it is used for Collections and Maps.
* It may be used both with "updating readers" (for POJOs) and
* when Collections and Maps use "getter as setter".
*<p>
* Default implementation just throws
* {@link UnsupportedOperationException}, to indicate that types
* that do not explicitly add support do not necessarily support
* update-existing-value operation (esp. immutable types)
*/
public T deserialize(JsonParser p, DeserializationContext ctxt, T intoValue)
throws JacksonException
{
ctxt.handleBadMerge(this);
return deserialize(p, ctxt);
}
/**
* Deserialization called when type being deserialized is defined to
* contain additional type identifier, to allow for correctly
* instantiating correct subtype. This can be due to annotation on
* type (or its supertype), or due to global settings without
* annotations.
*<p>
* Default implementation may work for some types, but ideally subclasses
* should not rely on current default implementation.
* Implementation is mostly provided to avoid compilation errors with older
* code.
*
* @param typeDeserializer Deserializer to use for handling type information
*/
public Object deserializeWithType(JsonParser p, DeserializationContext ctxt,
TypeDeserializer typeDeserializer)
throws JacksonException
{
// We could try calling
return typeDeserializer.deserializeTypedFromAny(p, ctxt);
}
/**
* Method similar to {@link #deserializeWithType(JsonParser,DeserializationContext,TypeDeserializer)}
* but called when merging value. Considered "bad merge" by default implementation,
* but if {@link MapperFeature#IGNORE_MERGE_FOR_UNMERGEABLE} is enabled will simple delegate to
* {@link #deserializeWithType(JsonParser, DeserializationContext, TypeDeserializer)}.
*/
public Object deserializeWithType(JsonParser p, DeserializationContext ctxt,
TypeDeserializer typeDeserializer, T intoValue)
throws JacksonException
{
ctxt.handleBadMerge(this);
return deserializeWithType(p, ctxt, typeDeserializer);
}
/*
/**********************************************************************
/* Fluent factory methods for constructing decorated versions
/**********************************************************************
*/
/**
* Method that will return deserializer instance that is able
* to handle "unwrapped" value instances
* If no unwrapped instance can be constructed, will simply
* return this object as-is.
*<p>
* Default implementation just returns 'this'
* indicating that no unwrapped variant exists
*/
public ValueDeserializer<T> unwrappingDeserializer(DeserializationContext ctxt,
NameTransformer unwrapper) {
return this;
}
/**
* Method that can be called to try to replace deserializer this deserializer
* delegates calls to. If not supported (either this deserializer does not
* delegate anything; or it does not want any changes), should either
* throw {@link UnsupportedOperationException} (if operation does not
* make sense or is not allowed); or return this deserializer as is.
*/
public ValueDeserializer<?> replaceDelegatee(ValueDeserializer<?> delegatee) {
throw new UnsupportedOperationException();
}
/*
/**********************************************************************
/* Introspection methods for figuring out configuration/setup
/* of this deserializer instance and/or type it handles
/**********************************************************************
*/
/**
* Method for accessing concrete physical type of values this deserializer produces.
* Note that this information is not guaranteed to be exact -- it
* may be a more generic (super-type) -- but it should not be
* incorrect (return a non-related type).
*<p>
* Default implementation will return null, which means almost same
* same as returning <code>Object.class</code> would; that is, that
* nothing is known about handled type.
*
* @return Physical type of values this deserializer produces, if known;
* {@code null} if not
*/
public Class<?> handledType() { return null; }
/**
* Method for accessing logical type of values this deserializer produces.
* Typically used for further configuring handling of values, for example,
* to find which coercions are legal.
*
* @return Logical type of values this deserializer produces, if known;
* {@code null} if not
*/
public LogicalType logicalType() { return null; }
/**
* Method called to see if deserializer instance is cachable and
* usable for other properties of same type (type for which instance
* was created).
*<p>
* Note that cached instances are still contextualized on per-property basis
* (but note that {@link ValueDeserializer#resolve(DeserializationContext)}d
* just once!)
* This means that in most cases it is safe to
* cache instances; however, it only makes sense to cache instances
* if instantiation is expensive, or if instances are heavy-weight.
*<p>
* Default implementation returns false, to indicate that no caching is done.
*/
public boolean isCachable() { return false; }
/**
* Accessor that can be used to determine if this deserializer uses
* another deserializer for actual deserialization, by delegating
* calls. If so, will return immediate delegate (which itself may
* delegate to further deserializers); otherwise will return null.
*
* @return Deserializer this deserializer delegates calls to, if null;
* null otherwise.
*/
public ValueDeserializer<?> getDelegatee() {
return null;
}
/**
* Method that will
* either return null to indicate that type being deserializers
* has no concept of properties; or a collection of identifiers
* for which <code>toString</code> will give external property
* name.
* This is only to be used for error reporting and diagnostics
* purposes (most commonly, to accompany "unknown property"
* exception).
*/
public Collection<Object> getKnownPropertyNames() {
return null;
}
/*
/**********************************************************************
/* Default NullValueProvider implementation
/**********************************************************************
*/
/**
* Method that can be called to determine value to be used for
* representing null values (values deserialized when JSON token
* is {@link JsonToken#VALUE_NULL}). Usually this is simply
* Java null, but for some types (especially primitives) it may be
* necessary to use non-null values.
*<p>
*<p>
* This method may be called once, or multiple times, depending on what
* {@link #getNullAccessPattern()} returns.
*<p>
* Default implementation simply returns null.
*/
@Override
public Object getNullValue(DeserializationContext ctxt) {
return null;
}
/**
* This method may be called in conjunction with calls to
* {@link #getNullValue(DeserializationContext)}, to check whether it needs
* to be called just once (static values), or each time empty value is
* needed.
*<p>
* Default implementation indicates that the "null value" to use for input null
* does not vary across uses so that {@link #getNullValue(DeserializationContext)}
* need not be called more than once per deserializer instance.
* This information may be used as optimization.
*/
@Override
public AccessPattern getNullAccessPattern() {
// Default implementation assumes that the null value does not vary, which
// is usually the case for most implementations. But it is not necessarily
// `null`; so sub-classes may want to refine further.
return AccessPattern.CONSTANT;
}
/**
* Method called to determine placeholder value to be used for cases
* where no value was obtained from input but we must pass a value
* nonetheless: the common case is that of Creator methods requiring
* passing a value for every parameter.
* Usually this is same as {@link #getNullValue} (which in turn
* is usually simply Java {@code null}), but it can be overridden
* for specific types: most notable scalar types must use "default"
* values.
*<p>
* This method needs to be called every time a determination is made.
*<p>
* Default implementation simply calls {@link #getNullValue} and
* returns value.
*
* @since 2.13
*/
@Override
public Object getAbsentValue(DeserializationContext ctxt) {
return getNullValue(ctxt);
}
/*
/**********************************************************************
/* Accessors for other replacement/placeholder values
/**********************************************************************
*/
/**
* Method called to determine value to be used for "empty" values
* (most commonly when deserializing from empty JSON Strings).
* Usually this is same as {@link #getNullValue} (which in turn
* is usually simply Java null), but it can be overridden
* for specific types. Or, if type should never be converted from empty
* String, method can also throw an exception.
*<p>
* This method may be called once, or multiple times, depending on what
* {@link #getEmptyAccessPattern()} returns.
*<p>
* Default implementation simply calls {@link #getNullValue} and
* returns value.
*/
public Object getEmptyValue(DeserializationContext ctxt) {
return getNullValue(ctxt);
}
/**
* This method may be called in conjunction with calls to
* {@link #getEmptyValue(DeserializationContext)}, to check whether it needs
* to be called just once (static values), or each time empty value is
* needed.
*/
public AccessPattern getEmptyAccessPattern() {
return AccessPattern.DYNAMIC;
}
/*
/**********************************************************************
/* Other accessors
/**********************************************************************
*/
/**
* Accessor that can be used to check whether this deserializer
* is expecting to possibly get an Object Identifier value instead of full value
* serialization, and if so, should be able to resolve it to actual
* Object instance to return as deserialized value.
*<p>
* Default implementation returns null, as support cannot be implemented
* generically. Some standard deserializers (most notably
* {@link tools.jackson.databind.deser.bean.BeanDeserializer})
* do implement this feature, and may return reader instance, depending on exact
* configuration of instance (which is based on type, and referring property).
*
* @return ObjectIdReader used for resolving possible Object Identifier
* value, instead of full value serialization, if deserializer can do that;
* null if no Object Id is expected.
*/
public ObjectIdReader getObjectIdReader(DeserializationContext ctxt) { return null; }
/**
* Method needed by {@link BeanDeserializerFactory} to properly link
* managed- and back-reference pairs.
*/
public SettableBeanProperty findBackReference(String refName)
{
throw new IllegalArgumentException("Cannot handle managed/back reference '"+refName
+"': type: value deserializer of type "+getClass().getName()+" does not support them");
}
/**
* Introspection method that may be called to see whether deserializer supports
* update of an existing value (aka "merging") or not. Return value should either
* be {@link Boolean#FALSE} if update is not supported at all (immutable values);
* {@link Boolean#TRUE} if update should usually work (regular POJOs, for example),
* or <code>null</code> if this is either not known, or may sometimes work.
*<p>
* Information gathered is typically used to either prevent merging update for
* property (either by skipping, if based on global defaults; or by exception during
* deserializer construction if explicit attempt made) if {@link Boolean#FALSE}
* returned, or inclusion if {@link Boolean#TRUE} is specified. If "unknown" case
* (<code>null</code> returned) behavior is to exclude property if global defaults
* used; or to allow if explicit per-type or property merging is defined.
*<p>
* Default implementation returns <code>null</code> to allow explicit per-type
* or per-property attempts.
*/
public Boolean supportsUpdate(DeserializationConfig config) {
return null;
}
/*
/**********************************************************************
/* Helper classes
/**********************************************************************
*/
/**
* This marker class is only to be used with annotations, to
* indicate that <b>no deserializer is configured</b>.
*<p>
* Specifically, this class is to be used as the marker for
* annotation {@link tools.jackson.databind.annotation.JsonDeserialize}
*/
public abstract static class None extends ValueDeserializer<Object> {
private None() { } // not to be instantiated
}
}