org.codehaus.jackson.map.DeserializationConfig Maven / Gradle / Ivy
package org.codehaus.jackson.map;
import java.text.DateFormat;
import java.util.*;
import org.codehaus.jackson.Base64Variant;
import org.codehaus.jackson.Base64Variants;
import org.codehaus.jackson.annotate.*;
import org.codehaus.jackson.map.introspect.AnnotatedClass;
import org.codehaus.jackson.map.introspect.NopAnnotationIntrospector;
import org.codehaus.jackson.map.introspect.VisibilityChecker;
import org.codehaus.jackson.map.jsontype.SubtypeResolver;
import org.codehaus.jackson.map.jsontype.TypeResolverBuilder;
import org.codehaus.jackson.map.jsontype.impl.StdSubtypeResolver;
import org.codehaus.jackson.map.type.ClassKey;
import org.codehaus.jackson.map.util.LinkedNode;
import org.codehaus.jackson.map.util.StdDateFormat;
import org.codehaus.jackson.node.JsonNodeFactory;
import org.codehaus.jackson.type.JavaType;
/**
* Object that contains baseline configuration for deserialization
* process. An instance is owned by {@link ObjectMapper}, which makes
* a copy that is passed during serialization process to
* {@link DeserializerProvider} and {@link DeserializerFactory}.
*
* Note: although configuration settings can be changed at any time
* (for factories and instances), they are not guaranteed to have
* effect if called after constructing relevant mapper or deserializer
* instance. This because some objects may be configured, constructed and
* cached first time they are needed.
*/
public class DeserializationConfig
implements MapperConfig
{
/**
* Enumeration that defines togglable features that guide
* the serialization feature.
*/
public enum Feature {
/*
/******************************************************
* Introspection features
/******************************************************
*/
/**
* Feature that determines whether annotation introspection
* is used for configuration; if enabled, configured
* {@link AnnotationIntrospector} will be used: if disabled,
* no annotations are considered.
*
* Feature is enabled by default.
*
* @since 1.2
*/
USE_ANNOTATIONS(true),
/**
* Feature that determines whether "setter" methods are
* automatically detected based on standard Bean naming convention
* or not. If yes, then all public one-argument methods that
* start with prefix "set"
* are considered setters. If disabled, only methods explicitly
* annotated are considered setters.
*
* Note that this feature has lower precedence than per-class
* annotations, and is only used if there isn't more granular
* configuration available.
*
* Feature is enabled by default.
*/
AUTO_DETECT_SETTERS(true),
/**
* Feature that determines whether "creator" methods are
* automatically detected by consider public constructors,
* and static single argument methods with name "valueOf".
* If disabled, only methods explicitly annotated are considered
* creator methods (except for the no-arg default constructor which
* is always considered a factory method).
*
* Note that this feature has lower precedence than per-class
* annotations, and is only used if there isn't more granular
* configuration available.
*
* Feature is enabled by default.
*/
AUTO_DETECT_CREATORS(true),
/**
* Feature that determines whether non-static fields are recognized as
* properties.
* If yes, then all public member fields
* are considered as properties. If disabled, only fields explicitly
* annotated are considered property fields.
*
* Note that this feature has lower precedence than per-class
* annotations, and is only used if there isn't more granular
* configuration available.
*
* Feature is enabled by default.
*
* @since 1.1
*/
AUTO_DETECT_FIELDS(true),
/**
* Feature that determines whether otherwise regular "getter"
* methods (but only ones that handle Collections and Maps,
* not getters of other type)
* can be used for purpose of getting a reference to a Collection
* and Map to modify the property, without requiring a setter
* method.
* This is similar to how JAXB framework sets Collections and
* Maps: no setter is involved, just setter.
*
* Note that such getters-as-setters methods have lower
* precedence than setters, so they are only used if no
* setter is found for the Map/Collection property.
*
* Feature is enabled by default.
*/
USE_GETTERS_AS_SETTERS(true),
/**
* Feature that determines whether method and field access
* modifier settings can be overridden when accessing
* properties. If enabled, method
* {@link java.lang.reflect.AccessibleObject#setAccessible}
* may be called to enable access to otherwise unaccessible
* objects.
*/
CAN_OVERRIDE_ACCESS_MODIFIERS(true),
/*
/******************************************************
* Type conversion features
/******************************************************
*/
/**
* Feature that determines whether Json floating point numbers
* are to be deserialized into {@link java.math.BigDecimal}s
* if only generic type description (either {@link Object} or
* {@link Number}, or within untyped {@link java.util.Map}
* or {@link java.util.Collection} context) is available.
* If enabled such values will be deserialized as {@link java.math.BigDecimal}s;
* if disabled, will be deserialized as {@link Double}s.
*
* Feature is disabled by default, meaning that "untyped" floating
* point numbers will by default be deserialized as {@link Double}s
* (choice is for performance reason -- BigDecimals are slower than
* Doubles)
*/
USE_BIG_DECIMAL_FOR_FLOATS(false),
/**
* Feature that determines whether Json integral (non-floating-point)
* numbers are to be deserialized into {@link java.math.BigInteger}s
* if only generic type description (either {@link Object} or
* {@link Number}, or within untyped {@link java.util.Map}
* or {@link java.util.Collection} context) is available.
* If enabled such values will be deserialized as
* {@link java.math.BigInteger}s;
* if disabled, will be deserialized as "smallest" available type,
* which is either {@link Integer}, {@link Long} or
* {@link java.math.BigInteger}, depending on number of digits.
*
* Feature is disabled by default, meaning that "untyped" floating
* point numbers will by default be deserialized using whatever
* is the most compact integral type, to optimize efficiency.
*/
USE_BIG_INTEGER_FOR_INTS(false),
/**
* Feature that determines standard deserialization mechanism used for
* Enum values: if enabled, Enums are assumed to have been serialized using
* return value of Enum.toString()
;
* if disabled, return value of Enum.name()
is assumed to have been used.
* Since pre-1.6 method was to use Enum name, this is the default.
*
* Note: this feature should usually have same value
* as {@link SerializationConfig.Feature#WRITE_ENUMS_USING_TO_STRING}.
*
* For further details, check out [JACKSON-212]
*
* @since 1.6
*/
READ_ENUMS_USING_TO_STRING(false),
/*
/******************************************************
* Error handling features
/******************************************************
*/
/**
* Feature that determines whether encountering of unknown
* properties (ones that do not map to a property, and there is
* no "any setter" or handler that can handle it)
* should result in a failure (by throwing a
* {@link JsonMappingException}) or not.
* This setting only takes effect after all other handling
* methods for unknown properties have been tried, and
* property remains unhandled.
*
* Feature is enabled by default, meaning that
* {@link JsonMappingException} is thrown if an unknown property
* is encountered. This is the implicit default prior to
* introduction of the feature.
*
* @since 1.2
*/
FAIL_ON_UNKNOWN_PROPERTIES(true),
/**
* Feature that determines whether encountering of JSON null
* is an error when deserializing into Java primitive types
* (like 'int' or 'double'). If it is, a JsonProcessingException
* is thrown to indicate this; if not, default value is used
* (0 for 'int', 0.0 for double, same defaulting as what JVM uses).
*
* Feature is disabled by default (to be consistent with behavior
* of Jackson 1.6),
* i.e. to allow use of nulls for primitive properties.
*
* @since 1.7
*/
FAIL_ON_NULL_FOR_PRIMITIVES(false),
/**
* Feature that determines whether JSON integer numbers are valid
* values to be used for deserializing Java enum values.
* If set to 'false' numbers are acceptable and are used to map to
* ordinal() of matching enumeration value; if 'true', numbers are
* not allowed and a {@link JsonMappingException} will be thrown.
* Latter behavior makes sense if there is concern that accidental
* mapping from integer values to enums might happen (and when enums
* are always serialized as JSON Strings)
*
* Feature is disabled by default (to be consistent with behavior
* of Jackson 1.6),
* i.e. to allow use of JSON integers for Java enums.
*
* @since 1.7
*/
FAIL_ON_NUMBERS_FOR_ENUMS(false),
/**
* Feature that determines whether Jackson code should catch
* and wrap {@link Exception}s (but never {@link Error}s!)
* to add additional information about
* location (within input) of problem or not. If enabled,
* most exceptions will be caught and re-thrown (exception
* specifically being that {@link java.io.IOException}s may be passed
* as is, since they are declared as throwable); this can be
* convenient both in that all exceptions will be checked and
* declared, and so there is more contextual information.
* However, sometimes calling application may just want "raw"
* unchecked exceptions passed as is.
*
* Feature is enabled by default, and is similar in behavior
* to default prior to 1.7.
*
* @since 1.7
*/
WRAP_EXCEPTIONS(true),
/*
/******************************************************
* Structural conversion features
/******************************************************
*/
/**
* Feature that was planned to be enabled to handle "wrapped" values
* (see {@link SerializationConfig.Feature#WRAP_ROOT_VALUE}
* for details).
* NOTE: Not implemented (unlike its counterpart for serialization
* which was implemented in 1.7)
*
* @deprecated Never implemented; plus, incorrectly named: should be
* "UNWRAP_ROOT_VALUE" to be of use. Feature such named may be added in future.
*/
@Deprecated
WRAP_ROOT_VALUE(false)
;
final boolean _defaultState;
/**
* Method that calculates bit set (flags) of all features that
* are enabled by default.
*/
public static int collectDefaults()
{
int flags = 0;
for (Feature f : values()) {
if (f.enabledByDefault()) {
flags |= f.getMask();
}
}
return flags;
}
private Feature(boolean defaultState) {
_defaultState = defaultState;
}
public boolean enabledByDefault() { return _defaultState; }
public int getMask() { return (1 << ordinal()); }
}
/**
* Bitfield (set of flags) of all Features that are enabled
* by default.
*/
protected final static int DEFAULT_FEATURE_FLAGS = Feature.collectDefaults();
protected final static DateFormat DEFAULT_DATE_FORMAT = StdDateFormat.instance;
/*
/**********************************************************
/* Configuration settings
/**********************************************************
*/
/**
* Introspector used to figure out Bean properties needed for bean serialization
* and deserialization. Overridable so that it is possible to change low-level
* details of introspection, like adding new annotation types.
*/
protected ClassIntrospector extends BeanDescription> _classIntrospector;
/**
* Introspector used for accessing annotation value based configuration.
*/
protected AnnotationIntrospector _annotationIntrospector;
/**
* Bit set that contains all enabled features
*/
protected int _featureFlags = DEFAULT_FEATURE_FLAGS;
/**
* Linked list that contains all registered problem handlers.
* Implementation as front-added linked list allows for sharing
* of the list (tail) without copying the list.
*/
protected LinkedNode _problemHandlers;
/**
* Custom date format to use for de-serialization. If specified, will be
* used instead of {@link org.codehaus.jackson.map.util.StdDateFormat}.
*
* Note that the configured format object will be cloned once per
* deserialization process (first time it is needed)
*/
protected DateFormat _dateFormat = DEFAULT_DATE_FORMAT;
/**
* Mapping that defines how to apply mix-in annotations: key is
* the type to received additional annotations, and value is the
* type that has annotations to "mix in".
*
* Annotations associated with the value classes will be used to
* override annotations of the key class, associated with the
* same field or method. They can be further masked by sub-classes:
* you can think of it as injecting annotations between the target
* class and its sub-classes (or interfaces)
*
* @since 1.2
*/
protected HashMap> _mixInAnnotations;
/**
* Flag used to detect when a copy if mix-in annotations is
* needed: set when current copy is shared, cleared when a
* fresh copy is made
*
* @since 1.2
*/
protected boolean _mixInAnnotationsShared;
/**
* Type information handler used for "untyped" values (ones declared
* to have type Object.class
)
*
* @since 1.5
*/
protected final TypeResolverBuilder> _typer;
/**
* Object used for determining whether specific property elements
* (method, constructors, fields) can be auto-detected based on
* their visibility (access modifiers). Can be changed to allow
* different minimum visibility levels for auto-detection. Note
* that this is the global handler; individual types (classes)
* can further override active checker used (using
* {@link JsonAutoDetect} annotation)
*
* @since 1.5
*/
protected VisibilityChecker> _visibilityChecker;
/**
* Registered concrete subtypes that can be used instead of (or
* in addition to) ones declared using annotations.
*
* @since 1.6
*/
protected SubtypeResolver _subtypeResolver;
/**
* To support on-the-fly class generation for interface and abstract classes
* it is possible to register "abstract type resolver".
*
* @since 1.6
*/
protected AbstractTypeResolver _abstractTypeResolver;
/**
* Factory used for constructing {@link org.codehaus.jackson.JsonNode} instances.
*
* @since 1.6
*/
protected JsonNodeFactory _nodeFactory;
/*
/**********************************************************
/* Life-cycle
/**********************************************************
*/
public DeserializationConfig(ClassIntrospector extends BeanDescription> intr,
AnnotationIntrospector annIntr, VisibilityChecker> vc,
SubtypeResolver subtypeResolver)
{
_classIntrospector = intr;
_annotationIntrospector = annIntr;
_typer = null;
_visibilityChecker = vc;
_subtypeResolver = subtypeResolver;
_nodeFactory = JsonNodeFactory.instance;
}
protected DeserializationConfig(DeserializationConfig src,
HashMap> mixins,
TypeResolverBuilder> typer,
VisibilityChecker> vc,
SubtypeResolver subtypeResolver)
{
_classIntrospector = src._classIntrospector;
_annotationIntrospector = src._annotationIntrospector;
_abstractTypeResolver = src._abstractTypeResolver;
_featureFlags = src._featureFlags;
_problemHandlers = src._problemHandlers;
_dateFormat = src._dateFormat;
_nodeFactory = src._nodeFactory;
_mixInAnnotations = mixins;
_typer = typer;
_visibilityChecker = vc;
_subtypeResolver = subtypeResolver;
}
/*
/**********************************************************
/* Configuration: on/off features
/**********************************************************
*/
/**
* Method for enabling specified feature.
*/
public void enable(Feature f) {
_featureFlags |= f.getMask();
}
/**
* Method for disabling specified feature.
*/
public void disable(Feature f) {
_featureFlags &= ~f.getMask();
}
/**
* Method for enabling or disabling specified feature.
*/
public void set(Feature f, boolean state)
{
if (state) {
enable(f);
} else {
disable(f);
}
}
/**
* Method for checking whether given feature is enabled or not
*/
public final boolean isEnabled(Feature f) {
return (_featureFlags & f.getMask()) != 0;
}
//protected int getFeatures() { return _generatorFeatures; }
/*
/**********************************************************
/* MapperConfig implementation
/**********************************************************
*/
/**
* Method that checks class annotations that the argument Object has,
* and modifies settings of this configuration object accordingly,
* similar to how those annotations would affect actual value classes
* annotated with them, but with global scope. Note that not all
* annotations have global significance, and thus only subset of
* Jackson annotations will have any effect.
*
* Ones that are known to have effect are:
*
* - {@link JsonAutoDetect}
*
*
* @param cls Class of which class annotations to use
* for changing configuration settings
*/
//@Override
public void fromAnnotations(Class> cls)
{
/* no class annotation for:
*
* - CAN_OVERRIDE_ACCESS_MODIFIERS
* - USE_BIG_DECIMAL_FOR_FLOATS
* - USE_BIG_INTEGER_FOR_INTS
* - USE_GETTERS_AS_SETTERS
*/
/* 10-Jul-2009, tatu: Should be able to just pass null as
* 'MixInResolver'; no mix-ins set at this point
*/
AnnotatedClass ac = AnnotatedClass.construct(cls, _annotationIntrospector, null);
// visibility checks handled via separate checker object...
_visibilityChecker = _annotationIntrospector.findAutoDetectVisibility(ac, _visibilityChecker);
}
/**
* Method that is called to create a non-shared copy of the configuration
* to be used for a deserialization operation.
* Note that if sub-classing
* and sub-class has additional instance methods,
* this method must be overridden to produce proper sub-class
* instance.
*/
//@Override
public DeserializationConfig createUnshared(TypeResolverBuilder> typer,
VisibilityChecker> vc, SubtypeResolver subtypeResolver)
{
HashMap> mixins = _mixInAnnotations;
_mixInAnnotationsShared = true;
return new DeserializationConfig(this, mixins, typer, vc, subtypeResolver);
}
/**
* Alternative "copy factory" that creates an unshared copy that uses
* different node factory than this instance.
*
* @since 1.6
*/
public DeserializationConfig createUnshared(JsonNodeFactory nf)
{
DeserializationConfig config = createUnshared(_typer, _visibilityChecker, _subtypeResolver);
config.setNodeFactory(nf);
return config;
}
//@Override
public void setIntrospector(ClassIntrospector extends BeanDescription> i) {
_classIntrospector = i;
}
/**
* Method for getting {@link AnnotationIntrospector} configured
* to introspect annotation values used for configuration.
*/
//@Override
public AnnotationIntrospector getAnnotationIntrospector()
{
/* 29-Jul-2009, tatu: it's now possible to disable use of
* annotations; can be done using "no-op" introspector
*/
if (isEnabled(Feature.USE_ANNOTATIONS)) {
return _annotationIntrospector;
}
return NopAnnotationIntrospector.instance;
}
//@Override
public void setAnnotationIntrospector(AnnotationIntrospector introspector)
{
_annotationIntrospector = introspector;
}
//@Override
public void insertAnnotationIntrospector(AnnotationIntrospector introspector)
{
_annotationIntrospector = AnnotationIntrospector.Pair.create(introspector, _annotationIntrospector);
}
//@Override
public void appendAnnotationIntrospector(AnnotationIntrospector introspector)
{
_annotationIntrospector = AnnotationIntrospector.Pair.create(_annotationIntrospector, introspector);
}
/**
* Method to use for defining mix-in annotations to use for augmenting
* annotations that deserializable classes have.
* Mixing in is done when introspecting class annotations and properties.
* Map passed contains keys that are target classes (ones to augment
* with new annotation overrides), and values that are source classes
* (have annotations to use for augmentation).
* Annotations from source classes (and their supertypes)
* will override
* annotations that target classes (and their super-types) have.
*
* Note: a copy of argument Map is created; the original Map is
* not modified or retained by this config object.
*
* @since 1.2
*/
//@Override
public void setMixInAnnotations(Map, Class>> sourceMixins)
{
HashMap> mixins = null;
if (sourceMixins != null && sourceMixins.size() > 0) {
mixins = new HashMap>(sourceMixins.size());
for (Map.Entry,Class>> en : sourceMixins.entrySet()) {
mixins.put(new ClassKey(en.getKey()), en.getValue());
}
}
_mixInAnnotationsShared = false;
_mixInAnnotations = mixins;
}
//@Override
public void addMixInAnnotations(Class> target, Class> mixinSource)
{
if (_mixInAnnotations == null || _mixInAnnotationsShared) {
_mixInAnnotationsShared = false;
_mixInAnnotations = new HashMap>();
}
_mixInAnnotations.put(new ClassKey(target), mixinSource);
}
/**
* @since 1.2
*/
//@Override
public Class> findMixInClassFor(Class> cls) {
return (_mixInAnnotations == null) ? null : _mixInAnnotations.get(new ClassKey(cls));
}
//@Override
public DateFormat getDateFormat() { return _dateFormat; }
/**
* Method that will set the textual deserialization to use for
* deserializing Dates (and Calendars). If null is passed, will
* use {@link StdDateFormat}.
*/
//@Override
public void setDateFormat(DateFormat df) {
_dateFormat = (df == null) ? StdDateFormat.instance : df;
}
//@Override
public VisibilityChecker> getDefaultVisibilityChecker() {
return _visibilityChecker;
}
//@Override
public TypeResolverBuilder> getDefaultTyper(JavaType baseType) {
return _typer;
}
/**
* @since 1.6
*/
public SubtypeResolver getSubtypeResolver() {
if (_subtypeResolver == null) {
_subtypeResolver = new StdSubtypeResolver();
}
return _subtypeResolver;
}
/**
* @since 1.6
*/
public void setSubtypeResolver(SubtypeResolver r) {
_subtypeResolver = r;
}
/**
* Accessor for getting bean description that only contains class
* annotations: useful if no getter/setter/creator information is needed.
*
* Note: part of {@link MapperConfig} since 1.7
*/
@SuppressWarnings("unchecked")
public T introspectClassAnnotations(Class> cls) {
return (T) _classIntrospector.forClassAnnotations(this, cls, this);
}
/**
* Accessor for getting bean description that only contains immediate class
* annotations: ones from the class, and its direct mix-in, if any, but
* not from super types.
*
* Note: part of {@link MapperConfig} since 1.7
*/
@SuppressWarnings("unchecked")
public T introspectDirectClassAnnotations(Class> cls) {
return (T) _classIntrospector.forDirectClassAnnotations(this, cls, this);
}
/*
/**********************************************************
/* Problem handlers
/**********************************************************
*/
/**
* Method for getting head of the problem handler chain. May be null,
* if no handlers have been added.
*/
public LinkedNode getProblemHandlers()
{
return _problemHandlers;
}
/**
* Method that can be used to add a handler that can (try to)
* resolve non-fatal deserialization problems.
*/
public void addHandler(DeserializationProblemHandler h)
{
/* Sanity check: let's prevent adding same handler multiple
* times
*/
if (!LinkedNode.contains(_problemHandlers, h)) {
_problemHandlers = new LinkedNode(h, _problemHandlers);
}
}
/**
* Method for removing all configuring problem handlers; usually done to replace
* existing handler(s) with different one(s)
*
* @since 1.1
*/
public void clearHandlers()
{
_problemHandlers = null;
}
/*
/**********************************************************
/* Introspection methods
/**********************************************************
*/
/**
* Method that will introspect full bean properties for the purpose
* of building a bean deserializer
*
* @param type Type of class to be introspected
*/
@SuppressWarnings("unchecked")
public T introspect(JavaType type) {
return (T) _classIntrospector.forDeserialization(this, type, this);
}
/**
* Method that will introspect subset of bean properties needed to
* construct bean instance.
*/
@SuppressWarnings("unchecked")
public T introspectForCreation(JavaType type) {
return (T) _classIntrospector.forCreation(this, type, this);
}
/*
/**********************************************************
/* Polymorphic type handling configuration
/**********************************************************
*/
/**
* Method for accessing {@link AbstractTypeResolver} configured, if any
* (no default) used for resolving abstract types into concrete
* types (either by mapping or materializing new classes).
*
* @since 1.6
*/
public AbstractTypeResolver getAbstractTypeResolver() {
return _abstractTypeResolver;
}
/**
* @since 1.6
*/
public void setAbstractTypeResolver(AbstractTypeResolver atr) {
_abstractTypeResolver = atr;
}
/*
/**********************************************************
/* Other configuration
/**********************************************************
*/
/**
* Method called during deserialization if Base64 encoded content
* needs to be decoded. Default version just returns default Jackson
* uses, which is modified-mime which does not add linefeeds (because
* those would have to be escaped in Json strings).
*/
public Base64Variant getBase64Variant() {
return Base64Variants.getDefaultVariant();
}
/**
* @since 1.6
*/
public void setNodeFactory(JsonNodeFactory nf) {
_nodeFactory = nf;
}
/**
* @since 1.6
*/
public final JsonNodeFactory getNodeFactory() {
return _nodeFactory;
}
}