blob: 75a86d1f7458655c8124c371e12b9f515a2599c3 [file] [log] [blame]
package org.codehaus.jackson.map;
import java.text.DateFormat;
import java.util.HashMap;
import java.util.Map;
import org.codehaus.jackson.annotate.JsonAutoDetect;
import org.codehaus.jackson.annotate.JsonMethod;
import org.codehaus.jackson.map.introspect.Annotated;
import org.codehaus.jackson.map.introspect.VisibilityChecker;
import org.codehaus.jackson.map.jsontype.SubtypeResolver;
import org.codehaus.jackson.map.jsontype.TypeIdResolver;
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.type.TypeBindings;
import org.codehaus.jackson.map.type.TypeFactory;
import org.codehaus.jackson.map.util.ClassUtil;
import org.codehaus.jackson.map.util.StdDateFormat;
import org.codehaus.jackson.type.JavaType;
import org.codehaus.jackson.type.TypeReference;
/**
* Interface that defines functionality accessible through both
* serialization and deserialization configuration objects;
* accessors to mode-independent configuration settings
* and such.
*<p>
* As of version 1.9, the goal is to make this class eventually immutable.
* Because of this, existing methods that allow changing state of this
* instance are deprecated in favor of methods that create new instances
* with different configuration ("fluent factories").
* One major remaining issue is that of handling mix-in annotations, which
* still represent a bit of mutable state; may need to implement a
* functional-style immutable map for storing those.
*
* @since 1.2 -- major change in 1.8, changed from interface to
* abstract class
*/
public abstract class MapperConfig<T extends MapperConfig<T>>
implements ClassIntrospector.MixInResolver
{
/*
/**********************************************************
/* Constants, default values
/**********************************************************
*/
/**
* This is the default {@link DateFormat} used unless overridden by
* custom implementation.
*/
protected final static DateFormat DEFAULT_DATE_FORMAT = StdDateFormat.instance;
/*
/**********************************************************
/* Simple immutable basic settings
/**********************************************************
*/
/**
* Immutable container object for simple configuration settings.
*<p>
* Note: ideally this would be final, but until we can eliminate
* mutators, must keep it mutable.
*/
protected Base _base;
/*
/**********************************************************
/* Mix-in annotations
/**********************************************************
*/
/**
* 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".
*<p>
* 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<ClassKey,Class<?>> _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;
/*
/**********************************************************
/* "Late bound" settings
/**********************************************************
*/
/**
* Registered concrete subtypes that can be used instead of (or
* in addition to) ones declared using annotations.
* Unlike most other settings, it is not configured as early
* as it is set, but rather only when a non-shared instance
* is constructed by <code>ObjectMapper</code> (or -Reader
* or -Writer)
*<p>
* Note: this is the only property left as non-final, to allow
* lazy construction of the instance as necessary.
*
* @since 1.6
*/
protected SubtypeResolver _subtypeResolver;
/*
/**********************************************************
/* Life-cycle: constructors
/**********************************************************
*/
protected MapperConfig(ClassIntrospector<? extends BeanDescription> ci, AnnotationIntrospector ai,
VisibilityChecker<?> vc, SubtypeResolver str, PropertyNamingStrategy pns, TypeFactory tf,
HandlerInstantiator hi)
{
_base = new Base(ci, ai, vc, pns, tf, null, DEFAULT_DATE_FORMAT, hi);
_subtypeResolver = str;
// by default, assumed to be shared; only cleared when explicit copy is made
_mixInAnnotationsShared = true;
}
/**
* Simple copy constructor
*
* @since 1.8
*/
protected MapperConfig(MapperConfig<T> src) {
this(src, src._base, src._subtypeResolver);
}
/**
* @since 1.8
*/
protected MapperConfig(MapperConfig<T> src, MapperConfig.Base base, SubtypeResolver str)
{
_base = base;
_subtypeResolver = str;
// by default, assumed to be shared; only cleared when explicit copy is made
_mixInAnnotationsShared = true;
_mixInAnnotations = src._mixInAnnotations;
}
/*
/**********************************************************
/* Life-cycle: factory methods
/**********************************************************
*/
/**
* 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.
*
* @deprecated Since 1.9, it is preferably to explicitly configure
* instances; this method also modifies existing instance which is
* against immutable design goals of this class.
*/
@Deprecated
public abstract void fromAnnotations(Class<?> cls);
/**
* Method to use for constructing an instance that is not shared
* between multiple operations but only used for a single one
* (which may be this instance, if it is immutable; if not, a copy
* is constructed with same settings)
*
* @since 1.8
*/
public abstract T createUnshared(SubtypeResolver subtypeResolver);
/**
* Method for constructing and returning a new instance with different
* {@link ClassIntrospector}
* to use.
*<p>
* NOTE: make sure to register new instance with <code>ObjectMapper</code>
* if directly calling this method.
*
* @since 1.8
*/
public abstract T withClassIntrospector(ClassIntrospector<? extends BeanDescription> ci);
/**
* Method for constructing and returning a new instance with different
* {@link AnnotationIntrospector} to use (replacing old one).
*<p>
* NOTE: make sure to register new instance with <code>ObjectMapper</code>
* if directly calling this method.
*
* @since 1.8
*/
public abstract T withAnnotationIntrospector(AnnotationIntrospector ai);
/**
* Method for constructing and returning a new instance with different
* {@link VisibilityChecker}
* to use.
*<p>
* NOTE: make sure to register new instance with <code>ObjectMapper</code>
* if directly calling this method.
*
* @since 1.8
*/
public abstract T withVisibilityChecker(VisibilityChecker<?> vc);
/**
* Method for constructing and returning a new instance with different
* minimal visibility level for specified property type
*<p>
* NOTE: make sure to register new instance with <code>ObjectMapper</code>
* if directly calling this method.
*
* @since 1.9
*/
public abstract T withVisibility(JsonMethod forMethod, JsonAutoDetect.Visibility visibility);
/**
* Method for constructing and returning a new instance with different
* {@link TypeResolverBuilder}
* to use.
*<p>
* NOTE: make sure to register new instance with <code>ObjectMapper</code>
* if directly calling this method.
*
* @since 1.8
*/
public abstract T withTypeResolverBuilder(TypeResolverBuilder<?> trb);
/**
* Method for constructing and returning a new instance with different
* {@link SubtypeResolver}
* to use.
*<p>
* NOTE: make sure to register new instance with <code>ObjectMapper</code>
* if directly calling this method.
*
* @since 1.8
*/
public abstract T withSubtypeResolver(SubtypeResolver str);
/**
* Method for constructing and returning a new instance with different
* {@link PropertyNamingStrategy}
* to use.
*<p>
* NOTE: make sure to register new instance with <code>ObjectMapper</code>
* if directly calling this method.
*
* @since 1.8
*/
public abstract T withPropertyNamingStrategy(PropertyNamingStrategy strategy);
/**
* Method for constructing and returning a new instance with different
* {@link TypeFactory}
* to use.
*<p>
* NOTE: make sure to register new instance with <code>ObjectMapper</code>
* if directly calling this method.
*
* @since 1.8
*/
public abstract T withTypeFactory(TypeFactory typeFactory);
/**
* Method for constructing and returning a new instance with different
* {@link DateFormat}
* to use.
*<p>
* NOTE: make sure to register new instance with <code>ObjectMapper</code>
* if directly calling this method.
*
* @since 1.8
*/
public abstract T withDateFormat(DateFormat df);
/**
* Method for constructing and returning a new instance with different
* {@link HandlerInstantiator}
* to use.
*<p>
* NOTE: make sure to register new instance with <code>ObjectMapper</code>
* if directly calling this method.
*
* @since 1.8
*/
public abstract T withHandlerInstantiator(HandlerInstantiator hi);
/**
* Method for constructing and returning a new instance with additional
* {@link AnnotationIntrospector} inserted (as the highest priority one)
*
* @since 1.9
*/
public abstract T withInsertedAnnotationIntrospector(AnnotationIntrospector introspector);
/**
* Method for constructing and returning a new instance with additional
* {@link AnnotationIntrospector} appended (as the lowest priority one)
*
* @since 1.9
*/
public abstract T withAppendedAnnotationIntrospector(AnnotationIntrospector introspector);
/*
/**********************************************************
/* Configuration: simple features
/**********************************************************
*/
/**
* Method for checking whether given feature is enabled or not
*/
public abstract boolean isEnabled(ConfigFeature f);
/**
* Method for determining whether annotation processing is enabled or not
* (default settings are typically that it is enabled; must explicitly disable).
*
* @return True if annotation processing is enabled; false if not
*
* @since 1.8
*/
public abstract boolean isAnnotationProcessingEnabled();
/**
* Accessor for determining whether it is ok to try to force override of access
* modifiers to be able to get or set values of non-public Methods, Fields;
* to invoke non-public Constructors, Methods; or to instantiate non-public
* Classes. By default this is enabled, but on some platforms it needs to be
* prevented since if this would violate security constraints and cause failures.
*
* @return True if access modifier overriding is allowed (and may be done for
* any Field, Method, Constructor or Class); false to prevent any attempts
* to override.
*
* @since 1.8
*/
public abstract boolean canOverrideAccessModifiers();
/**
* Accessor for checking whether default settings for property handling
* indicate that properties should be alphabetically ordered or not.
*
* @since 1.9
*/
public abstract boolean shouldSortPropertiesAlphabetically();
/*
/**********************************************************
/* Configuration: introspectors, mix-ins
/**********************************************************
*/
public ClassIntrospector<? extends BeanDescription> getClassIntrospector() {
return _base.getClassIntrospector();
}
/**
* Method for getting {@link AnnotationIntrospector} configured
* to introspect annotation values used for configuration.
*<p>
* Non-final since it is actually overridden by sub-classes (for now?)
*/
public AnnotationIntrospector getAnnotationIntrospector() {
return _base.getAnnotationIntrospector();
}
/**
* Method for registering specified {@link AnnotationIntrospector} as the highest
* priority introspector (will be chained with existing introspector(s) which
* will be used as fallbacks for cases this introspector does not handle)
*
* @param introspector Annotation introspector to register.
*
* @since 1.7
*
* @deprecated Since 1.9 use {@link #withInsertedAnnotationIntrospector(AnnotationIntrospector)} instead;
* this method is deprecated as it changes state, preventing immutability of instances
*/
@Deprecated
public final void insertAnnotationIntrospector(AnnotationIntrospector introspector) {
_base = _base.withAnnotationIntrospector(AnnotationIntrospector.Pair.create(introspector,
getAnnotationIntrospector()));
}
/**
* Method for registering specified {@link AnnotationIntrospector} as the lowest
* priority introspector, chained with existing introspector(s) and called
* as fallback for cases not otherwise handled.
*
* @param introspector Annotation introspector to register.
*
* @since 1.7
*
* @deprecated Since 1.9 use {@link #withAppendedAnnotationIntrospector(AnnotationIntrospector)} instead;
* this method is deprecated as it changes state, preventing immutability of instances
*/
@Deprecated
public final void appendAnnotationIntrospector(AnnotationIntrospector introspector) {
_base = _base.withAnnotationIntrospector(AnnotationIntrospector.Pair.create(getAnnotationIntrospector(),
introspector));
}
/**
* Accessor for 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
*/
public VisibilityChecker<?> getDefaultVisibilityChecker() {
return _base.getVisibilityChecker();
}
/**
* @since 1.8
*/
public final PropertyNamingStrategy getPropertyNamingStrategy() {
return _base.getPropertyNamingStrategy();
}
/**
* @since 1.8
*/
public final HandlerInstantiator getHandlerInstantiator() {
return _base.getHandlerInstantiator();
}
/*
/**********************************************************
/* Configuration: mix-in annotations
/**********************************************************
*/
/**
* Method to use for defining mix-in annotations to use for augmenting
* annotations that processable (serializable / 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 <b>override</b>
* annotations that target classes (and their super-types) have.
*
* @since 1.2
*/
public final void setMixInAnnotations(Map<Class<?>, Class<?>> sourceMixins)
{
HashMap<ClassKey,Class<?>> mixins = null;
if (sourceMixins != null && sourceMixins.size() > 0) {
mixins = new HashMap<ClassKey,Class<?>>(sourceMixins.size());
for (Map.Entry<Class<?>,Class<?>> en : sourceMixins.entrySet()) {
mixins.put(new ClassKey(en.getKey()), en.getValue());
}
}
_mixInAnnotationsShared = false;
_mixInAnnotations = mixins;
}
/**
* Method to use for adding mix-in annotations to use for augmenting
* specified class or interface. All annotations from
* <code>mixinSource</code> are taken to override annotations
* that <code>target</code> (or its supertypes) has.
*
* @since 1.2
*
* @param target Class (or interface) whose annotations to effectively override
* @param mixinSource Class (or interface) whose annotations are to
* be "added" to target's annotations, overriding as necessary
*/
public final void addMixInAnnotations(Class<?> target, Class<?> mixinSource)
{
if (_mixInAnnotations == null) {
_mixInAnnotationsShared = false;
_mixInAnnotations = new HashMap<ClassKey,Class<?>>();
} else if (_mixInAnnotationsShared) {
_mixInAnnotationsShared = false;
_mixInAnnotations = new HashMap<ClassKey,Class<?>>(_mixInAnnotations);
}
_mixInAnnotations.put(new ClassKey(target), mixinSource);
}
// ClassIntrospector.MixInResolver impl:
/**
* Method that will check if there are "mix-in" classes (with mix-in
* annotations) for given class
*
* @since 1.2
*/
@Override
public final Class<?> findMixInClassFor(Class<?> cls) {
return (_mixInAnnotations == null) ? null : _mixInAnnotations.get(new ClassKey(cls));
}
/**
* @since 1.8.1
*/
public final int mixInCount() {
return (_mixInAnnotations == null) ? 0 : _mixInAnnotations.size();
}
/*
/**********************************************************
/* Configuration: type and subtype handling
/**********************************************************
*/
/**
* Method called to locate a type info handler for types that do not have
* one explicitly declared via annotations (or other configuration).
* If such default handler is configured, it is returned; otherwise
* null is returned.
*
* @since 1.5
*/
public final TypeResolverBuilder<?> getDefaultTyper(JavaType baseType) {
return _base.getTypeResolverBuilder();
}
/**
* Accessor for object used for finding out all reachable subtypes
* for supertypes; needed when a logical type name is used instead
* of class name (or custom scheme).
*
* @since 1.6
*/
public final SubtypeResolver getSubtypeResolver() {
if (_subtypeResolver == null) {
_subtypeResolver = new StdSubtypeResolver();
}
return _subtypeResolver;
}
/**
* @since 1.8
*/
public final TypeFactory getTypeFactory() {
return _base.getTypeFactory();
}
/**
* Helper method that will construct {@link JavaType} for given
* raw class.
* This is a simple short-cut for:
*<pre>
* getTypeFactory().constructType(cls);
*</pre>
*
* @since 1.8
*/
public final JavaType constructType(Class<?> cls) {
return getTypeFactory().constructType(cls, (TypeBindings) null);
}
/**
* Helper method that will construct {@link JavaType} for given
* type reference
* This is a simple short-cut for:
*<pre>
* getTypeFactory().constructType(valueTypeRef);
*</pre>
*
* @since 1.9
*/
public final JavaType constructType(TypeReference<?> valueTypeRef) {
return getTypeFactory().constructType(valueTypeRef.getType(), (TypeBindings) null);
}
/**
* @since 1.9.1
*/
public JavaType constructSpecializedType(JavaType baseType, Class<?> subclass) {
return getTypeFactory().constructSpecializedType(baseType, subclass);
}
/*
/**********************************************************
/* Configuration: other
/**********************************************************
*/
/**
* Method for accessing currently configured (textual) date format
* that will be used for reading or writing date values (in case
* of writing, only if textual output is configured; not if dates
* are to be serialized as time stamps).
*<p>
* Note that typically {@link DateFormat} instances are <b>not thread-safe</b>
* (at least ones provided by JDK):
* this means that calling code should clone format instance before
* using it.
*<p>
* This method is usually only called by framework itself, since there
* are convenience methods available via
* {@link DeserializationContext} and {@link SerializerProvider} that
* take care of cloning and thread-safe reuse.
*/
public final DateFormat getDateFormat() { return _base.getDateFormat(); }
/**
* Accessor for getting bean description that only contains class
* annotations: useful if no getter/setter/creator information is needed.
*
* @since 1.7
*/
@SuppressWarnings("unchecked")
public <DESC extends BeanDescription> DESC introspectClassAnnotations(Class<?> cls) {
return (DESC) introspectClassAnnotations(constructType(cls));
}
/**
* Accessor for getting bean description that only contains class
* annotations: useful if no getter/setter/creator information is needed.
*
* @since 1.9
*/
public abstract <DESC extends BeanDescription> DESC introspectClassAnnotations(JavaType type);
/**
* 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.
*
* @since 1.7
*/
@SuppressWarnings("unchecked")
public <DESC extends BeanDescription> DESC introspectDirectClassAnnotations(Class<?> cls) {
return (DESC) introspectDirectClassAnnotations(constructType(cls));
}
/**
* 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.
*/
public abstract <DESC extends BeanDescription> DESC introspectDirectClassAnnotations(JavaType type);
/*
/**********************************************************
/* Methods for instantiating handlers
/**********************************************************
*/
/**
* Method that can be called to obtain an instance of <code>TypeIdResolver</code> of
* specified type.
*
* @since 1.8
*/
public TypeResolverBuilder<?> typeResolverBuilderInstance(Annotated annotated,
Class<? extends TypeResolverBuilder<?>> builderClass)
{
HandlerInstantiator hi = getHandlerInstantiator();
if (hi != null) {
TypeResolverBuilder<?> builder = hi.typeResolverBuilderInstance(this, annotated, builderClass);
if (builder != null) {
return builder;
}
}
return (TypeResolverBuilder<?>) ClassUtil.createInstance(builderClass, canOverrideAccessModifiers());
}
/**
* Method that can be called to obtain an instance of <code>TypeIdResolver</code> of
* specified type.
*
* @since 1.8
*/
public TypeIdResolver typeIdResolverInstance(Annotated annotated,
Class<? extends TypeIdResolver> resolverClass)
{
HandlerInstantiator hi = getHandlerInstantiator();
if (hi != null) {
TypeIdResolver builder = hi.typeIdResolverInstance(this, annotated, resolverClass);
if (builder != null) {
return builder;
}
}
return (TypeIdResolver) ClassUtil.createInstance(resolverClass, canOverrideAccessModifiers());
}
/*
/**********************************************************
/* Deprecated methods
/**********************************************************
*/
/**
* Method for replacing existing annotation introspector(s) with specified
* introspector.
* Since this method modifies state of configuration object directly, its use
* is not recommended.
*
* @deprecated Since 1.8, use either
* {@link #withAnnotationIntrospector(AnnotationIntrospector)} or
* Module API instead
*/
@Deprecated
public final void setAnnotationIntrospector(AnnotationIntrospector ai) {
_base = _base.withAnnotationIntrospector(ai);
}
/**
* Method that will define specific date format to use for reading/writing
* Date and Calendar values.
* If null is passed, will use {@link StdDateFormat}.
* Instance is used as is, without creating a clone.
* Format object in use can be accessed using {@link #getDateFormat}.
*
* @param df Date format to use, if not null; if null, the default format
* will be used
*
* @deprecated As of version 1.8, it is preferable to call method in
* {@link ObjectMapper} instead; or construct new instance with
* {@link #withDateFormat(DateFormat)}
*/
@Deprecated
public void setDateFormat(DateFormat df) {
if (df == null) {
df = DEFAULT_DATE_FORMAT;
}
_base = _base.withDateFormat(df);
}
/*
/**********************************************************
/* Helper interface used with simple on/off features
/**********************************************************
*/
/**
* Interface that actual Feature enumerations used by
* {@link MapperConfig} implementations must implement.
* Necessary since enums can not be extended using normal
* inheritance, but can implement interfaces
*
* @since 1.9
*/
public interface ConfigFeature
{
/**
* Accessor for checking whether this feature is enabled by default.
*/
public boolean enabledByDefault();
/**
* Returns bit mask for this feature instance
*/
public int getMask();
}
/*
/**********************************************************
/* Helper class to contain basic state needed to implement
/* MapperConfig.
/**********************************************************
*/
/**
* Immutable container class used to store simple configuration
* settings. Since instances are fully immutable, instances can
* be freely shared and used without synchronization.
*/
public static class Base
{
/*
/**********************************************************
/* Configuration settings; introspection, related
/**********************************************************
*/
/**
* 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 final ClassIntrospector<? extends BeanDescription> _classIntrospector;
/**
* Introspector used for accessing annotation value based configuration.
*/
protected final AnnotationIntrospector _annotationIntrospector;
/**
* 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 final VisibilityChecker<?> _visibilityChecker;
/**
* Custom property naming strategy in use, if any.
*
* @since 1.8
*/
protected final PropertyNamingStrategy _propertyNamingStrategy;
/**
* Specific factory used for creating {@link JavaType} instances;
* needed to allow modules to add more custom type handling
* (mostly to support types of non-Java JVM languages)
*/
protected final TypeFactory _typeFactory;
/*
/**********************************************************
/* Configuration settings; type resolution
/**********************************************************
*/
/**
* Type information handler used for "untyped" values (ones declared
* to have type <code>Object.class</code>)
*
* @since 1.5
*/
protected final TypeResolverBuilder<?> _typeResolverBuilder;
/*
/**********************************************************
/* Configuration settings; other
/**********************************************************
*/
/**
* Custom date format to use for de-serialization. If specified, will be
* used instead of {@link org.codehaus.jackson.map.util.StdDateFormat}.
*<p>
* Note that the configured format object will be cloned once per
* deserialization process (first time it is needed)
*/
protected final DateFormat _dateFormat;
/**
* Object used for creating instances of handlers (serializers, deserializers,
* type and type id resolvers), given class to instantiate. This is typically
* used to do additional configuration (with dependency injection, for example)
* beyond simply construction of instances; or to use alternative constructors.
*/
protected final HandlerInstantiator _handlerInstantiator;
/*
/**********************************************************
/* Construction
/**********************************************************
*/
public Base(ClassIntrospector<? extends BeanDescription> ci, AnnotationIntrospector ai,
VisibilityChecker<?> vc, PropertyNamingStrategy pns, TypeFactory tf,
TypeResolverBuilder<?> typer, DateFormat dateFormat, HandlerInstantiator hi)
{
_classIntrospector = ci;
_annotationIntrospector = ai;
_visibilityChecker = vc;
_propertyNamingStrategy = pns;
_typeFactory = tf;
_typeResolverBuilder = typer;
_dateFormat = dateFormat;
_handlerInstantiator = hi;
}
/*
/**********************************************************
/* Factory methods
/**********************************************************
*/
public Base withClassIntrospector(ClassIntrospector<? extends BeanDescription> ci) {
return new Base(ci, _annotationIntrospector, _visibilityChecker, _propertyNamingStrategy, _typeFactory,
_typeResolverBuilder, _dateFormat, _handlerInstantiator);
}
public Base withAnnotationIntrospector(AnnotationIntrospector ai) {
return new Base(_classIntrospector, ai, _visibilityChecker, _propertyNamingStrategy, _typeFactory,
_typeResolverBuilder, _dateFormat, _handlerInstantiator);
}
public Base withInsertedAnnotationIntrospector(AnnotationIntrospector ai) {
return withAnnotationIntrospector(AnnotationIntrospector.Pair.create(ai, _annotationIntrospector));
}
public Base withAppendedAnnotationIntrospector(AnnotationIntrospector ai) {
return withAnnotationIntrospector(AnnotationIntrospector.Pair.create(_annotationIntrospector, ai));
}
public Base withVisibilityChecker(VisibilityChecker<?> vc) {
return new Base(_classIntrospector, _annotationIntrospector, vc, _propertyNamingStrategy, _typeFactory,
_typeResolverBuilder, _dateFormat, _handlerInstantiator);
}
public Base withVisibility(JsonMethod forMethod, JsonAutoDetect.Visibility visibility) {
return new Base(_classIntrospector, _annotationIntrospector,
_visibilityChecker.withVisibility(forMethod, visibility),
_propertyNamingStrategy, _typeFactory,
_typeResolverBuilder, _dateFormat, _handlerInstantiator);
}
public Base withPropertyNamingStrategy(PropertyNamingStrategy pns) {
return new Base(_classIntrospector, _annotationIntrospector, _visibilityChecker, pns, _typeFactory,
_typeResolverBuilder, _dateFormat, _handlerInstantiator);
}
public Base withTypeFactory(TypeFactory tf) {
return new Base(_classIntrospector, _annotationIntrospector, _visibilityChecker, _propertyNamingStrategy, tf,
_typeResolverBuilder, _dateFormat, _handlerInstantiator);
}
public Base withTypeResolverBuilder(TypeResolverBuilder<?> typer) {
return new Base(_classIntrospector, _annotationIntrospector, _visibilityChecker, _propertyNamingStrategy, _typeFactory,
typer, _dateFormat, _handlerInstantiator);
}
public Base withDateFormat(DateFormat df) {
return new Base(_classIntrospector, _annotationIntrospector, _visibilityChecker, _propertyNamingStrategy, _typeFactory,
_typeResolverBuilder, df, _handlerInstantiator);
}
public Base withHandlerInstantiator(HandlerInstantiator hi) {
return new Base(_classIntrospector, _annotationIntrospector, _visibilityChecker, _propertyNamingStrategy, _typeFactory,
_typeResolverBuilder, _dateFormat, hi);
}
/*
/**********************************************************
/* API
/**********************************************************
*/
public ClassIntrospector<? extends BeanDescription> getClassIntrospector() {
return _classIntrospector;
}
public AnnotationIntrospector getAnnotationIntrospector() {
return _annotationIntrospector;
}
public VisibilityChecker<?> getVisibilityChecker() {
return _visibilityChecker;
}
public PropertyNamingStrategy getPropertyNamingStrategy() {
return _propertyNamingStrategy;
}
public TypeFactory getTypeFactory() {
return _typeFactory;
}
public TypeResolverBuilder<?> getTypeResolverBuilder() {
return _typeResolverBuilder;
}
public DateFormat getDateFormat() {
return _dateFormat;
}
public HandlerInstantiator getHandlerInstantiator() {
return _handlerInstantiator;
}
}
/*
/**********************************************************
/* Basic extension; added to avoid having to change generic
/* signature of MapperConfig
/*
/* NOTE: May be merge in MapperConfig for 2.0, depending
/* on how much we value backwards compatibility
/**********************************************************
*/
static abstract class Impl<CFG extends MapperConfig.ConfigFeature,
T extends Impl<CFG,T>>
extends MapperConfig<T>
{
/**
*<p>
* Note: moved to base class in 1.9; was stored by sub-class earlier
*/
protected int _featureFlags;
/*
/**********************************************************
/* Construction
/**********************************************************
*/
protected Impl(ClassIntrospector<? extends BeanDescription> ci, AnnotationIntrospector ai,
VisibilityChecker<?> vc, SubtypeResolver str, PropertyNamingStrategy pns, TypeFactory tf,
HandlerInstantiator hi,
int defaultFeatures)
{
super(ci, ai, vc, str, pns, tf, hi);
_featureFlags = defaultFeatures;
}
protected Impl(Impl<CFG,T> src) {
super(src);
_featureFlags = src._featureFlags;
}
protected Impl(Impl<CFG,T> src, int features) {
super(src);
_featureFlags = features;
}
/**
* @since 1.8
*/
protected Impl(Impl<CFG,T> src, MapperConfig.Base base, SubtypeResolver str)
{
super(src, base, str);
_featureFlags = src._featureFlags;
}
/**
* Method that calculates bit set (flags) of all features that
* are enabled by default.
*/
static <F extends Enum<F> & MapperConfig.ConfigFeature> int collectFeatureDefaults(Class<F> enumClass)
{
int flags = 0;
for (F value : enumClass.getEnumConstants()) {
if (value.enabledByDefault()) {
flags |= value.getMask();
}
}
return flags;
}
/*
/**********************************************************
/* Additional fluent-factory methods
/**********************************************************
*/
/**
* Fluent factory method that will construct and return a new configuration
* object instance with specified features enabled.
*
* @since 1.9
*/
public abstract T with(CFG... features);
/**
* Fluent factory method that will construct and return a new configuration
* object instance with specified features disabled.
*
* @since 1.9
*/
public abstract T without(CFG... features);
/*
/**********************************************************
/* Configuration: simple features
/**********************************************************
*/
/* NOTE: this method was added in 1.9, but should be
* removed from 2.0 -- overloads do not work nicely with
* enums, so we better not try
*<p>
* Also note that we can NOT use type variable CFG here, because
* non-generic base class had to use base type.
*
* @Deprecated
*/
@Override
public boolean isEnabled(MapperConfig.ConfigFeature f) {
return (_featureFlags & f.getMask()) != 0;
}
/*
/**********************************************************
/* Configuration: deprecated methods
/**********************************************************
*/
/**
* Method for enabling specified feature.
*
* @deprecated Since 1.9, it is preferable to use {@link #with} instead;
* this method is deprecated as it modifies current instance instead of
* creating a new one (as the goal is to make this class immutable)
*/
@Deprecated
public void enable(CFG f) {
_featureFlags |= f.getMask();
}
/**
* Method for disabling specified feature.
*
* @deprecated Since 1.9, it is preferable to use {@link #without} instead;
* this method is deprecated as it modifies current instance instead of
* creating a new one (as the goal is to make this class immutable)
*/
@Deprecated
public void disable(CFG f) {
_featureFlags &= ~f.getMask();
}
/**
* Method for enabling or disabling specified feature.
*
* @deprecated Since 1.9, it is preferable to use {@link #with} and
* {@link #without} methods instead;
* this method is deprecated as it modifies current instance instead of
* creating a new one (as the goal is to make this class immutable)
*/
@SuppressWarnings("deprecation")
@Deprecated
public void set(CFG f, boolean state)
{
if (state) {
enable(f);
} else {
disable(f);
}
}
}
}