blob: 9c146de34f06a335ed83a8e93c7814e1da343417 [file] [log] [blame]
package org.codehaus.jackson.map;
import java.lang.annotation.Annotation;
import java.util.*;
import org.codehaus.jackson.type.JavaType;
import org.codehaus.jackson.map.JsonDeserializer;
import org.codehaus.jackson.map.JsonSerializer;
import org.codehaus.jackson.map.annotate.JsonSerialize;
import org.codehaus.jackson.map.deser.ValueInstantiator;
import org.codehaus.jackson.map.introspect.*;
import org.codehaus.jackson.map.jsontype.NamedType;
import org.codehaus.jackson.map.jsontype.TypeResolverBuilder;
/**
* Abstract class that defines API used for introspecting annotation-based
* configuration for serialization and deserialization. Separated
* so that different sets of annotations can be supported, and support
* plugged-in dynamically.
*<p>
* NOTE: due to rapid addition of new methods (and changes to existing methods),
* it is <b>strongly</b> recommended that custom implementations should not directly
* extend this class, but rather extend {@link NopAnnotationIntrospector}.
* This way added methods will not break backwards compatibility of custom annotation
* introspectors.
*/
public abstract class AnnotationIntrospector
{
/*
/**********************************************************
/* Helper types
/**********************************************************
*/
/**
* Value type used with managed and back references; contains type and
* logic name, used to link related references
*
* @since 1.6
*/
public static class ReferenceProperty
{
public enum Type {
/**
* Reference property that Jackson manages and that is serialized normally (by serializing
* reference object), but is used for resolving back references during
* deserialization.
* Usually this can be defined by using
* {@link org.codehaus.jackson.annotate.JsonManagedReference}
*/
MANAGED_REFERENCE
/**
* Reference property that Jackson manages by suppressing it during serialization,
* and reconstructing during deserialization.
* Usually this can be defined by using
* {@link org.codehaus.jackson.annotate.JsonBackReference}
*/
,BACK_REFERENCE
;
}
private final Type _type;
private final String _name;
public ReferenceProperty(Type t, String n) {
_type = t;
_name = n;
}
public static ReferenceProperty managed(String name) { return new ReferenceProperty(Type.MANAGED_REFERENCE, name); }
public static ReferenceProperty back(String name) { return new ReferenceProperty(Type.BACK_REFERENCE, name); }
public Type getType() { return _type; }
public String getName() { return _name; }
public boolean isManagedReference() { return _type == Type.MANAGED_REFERENCE; }
public boolean isBackReference() { return _type == Type.BACK_REFERENCE; }
}
/*
/**********************************************************
/* Factory methods
/**********************************************************
*/
/**
* Factory method for accessing "no operation" implementation
* of introspector: instance that will never find any annotation-based
* configuration.
*
* @since 1.3
*/
public static AnnotationIntrospector nopInstance() {
return NopAnnotationIntrospector.instance;
}
public static AnnotationIntrospector pair(AnnotationIntrospector a1, AnnotationIntrospector a2) {
return new Pair(a1, a2);
}
/*
/**********************************************************
/* Access to possibly chained introspectors (1.7)
/**********************************************************
*/
/**
* Method that can be used to collect all "real" introspectors that
* this introspector contains, if any; or this introspector
* if it is not a container. Used to get access to all container
* introspectors in their priority order.
*<p>
* Default implementation returns a Singleton list with this introspector
* as contents.
* This usually works for sub-classes, except for proxy or delegating "container
* introspectors" which need to override implementation.
*/
public Collection<AnnotationIntrospector> allIntrospectors() {
return Collections.singletonList(this);
}
/**
* Method that can be used to collect all "real" introspectors that
* this introspector contains, if any; or this introspector
* if it is not a container. Used to get access to all container
* introspectors in their priority order.
*<p>
* Default implementation adds this introspector in result; this usually
* works for sub-classes, except for proxy or delegating "container
* introspectors" which need to override implementation.
*/
public Collection<AnnotationIntrospector> allIntrospectors(Collection<AnnotationIntrospector> result) {
result.add(this);
return result;
}
/*
/**********************************************************
/* Generic annotation properties, lookup
/**********************************************************
*/
/**
* Method called by framework to determine whether given annotation
* is handled by this introspector.
*/
public abstract boolean isHandled(Annotation ann);
/*
/**********************************************************
/* General class annotations
/**********************************************************
*/
/**
* Method that checks whether specified class has annotations
* that indicate that it is (or is not) cachable. Exact
* semantics depend on type of class annotated and using
* class (factory or provider).
*<p>
* Currently only used
* with deserializers, to determine whether provider
* should cache instances, and if no annotations are found,
* assumes non-cachable instances.
*
* @return True, if class is considered cachable within context,
* False if not, and null if introspector does not care either
* way.
*/
public Boolean findCachability(AnnotatedClass ac) {
return null;
}
/**
* Method for locating name used as "root name" (for use by
* some serializers when outputting root-level object -- mostly
* for XML compatibility purposes) for given class, if one
* is defined. Returns null if no declaration found; can return
* explicit empty String, which is usually ignored as well as null.
*
* @since 1.3
*/
public abstract String findRootName(AnnotatedClass ac);
/**
* Method for finding list of properties to ignore for given class
* (null is returned if not specified).
* List of property names is applied
* after other detection mechanisms, to filter out these specific
* properties from being serialized and deserialized.
*
* @since 1.4
*/
public abstract String[] findPropertiesToIgnore(AnnotatedClass ac);
/**
* Method for checking whether an annotation indicates that all unknown properties
*
* @since 1.4
*/
public abstract Boolean findIgnoreUnknownProperties(AnnotatedClass ac);
/**
* Method for checking whether properties that have specified type
* (class, not generics aware) should be completely ignored for
* serialization and deserialization purposes.
*
* @param ac Type to check
*
* @return Boolean.TRUE if properties of type should be ignored;
* Boolean.FALSE if they are not to be ignored, null for default
* handling (which is 'do not ignore')
*
* @since 1.7
*/
public Boolean isIgnorableType(AnnotatedClass ac) {
return null;
}
/**
* Method for finding if annotated class has associated filter; and if so,
* to return id that is used to locate filter.
*
* @return Id of the filter to use for filtering properties of annotated
* class, if any; or null if none found.
*/
public Object findFilterId(AnnotatedClass ac) {
return null;
}
/*
/**********************************************************
/* Property auto-detection
/**********************************************************
*/
/**
* Method for checking if annotations indicate changes to minimum visibility levels
* needed for auto-detecting property elements (fields, methods, constructors).
* A baseline checker is given, and introspector is to either return it as is (if
* no annotations are found), or build and return a derived instance (using checker's build
* methods).
*
* @since 1.5
*/
public VisibilityChecker<?> findAutoDetectVisibility(AnnotatedClass ac, VisibilityChecker<?> checker) {
return checker;
}
/*
/**********************************************************
/* Class annotations for Polymorphic type handling (1.5+)
/**********************************************************
*/
/**
* Method for checking if given class has annotations that indicate
* that specific type resolver is to be used for handling instances.
* This includes not only
* instantiating resolver builder, but also configuring it based on
* relevant annotations (not including ones checked with a call to
* {@link #findSubtypes}
*
* @param config Configuration settings in effect (for serialization or deserialization)
* @param ac Annotated class to check for annotations
* @param baseType Base java type of value for which resolver is to be found
*
* @return Type resolver builder for given type, if one found; null if none
*
* @since 1.5 -- although changed in 1.8 to pass configuration object
*/
public TypeResolverBuilder<?> findTypeResolver(MapperConfig<?> config,
AnnotatedClass ac, JavaType baseType) {
return null;
}
/**
* Method for checking if given property entity (field or method) has annotations
* that indicate that specific type resolver is to be used for handling instances.
* This includes not only
* instantiating resolver builder, but also configuring it based on
* relevant annotations (not including ones checked with a call to
* {@link #findSubtypes}
*
* @param config Configuration settings in effect (for serialization or deserialization)
* @param am Annotated member (field or method) to check for annotations
* @param baseType Base java type of property for which resolver is to be found
*
* @return Type resolver builder for properties of given entity, if one found;
* null if none
*
* @since 1.5 -- although changed in 1.8 to pass configuration object
*/
public TypeResolverBuilder<?> findPropertyTypeResolver(MapperConfig<?> config,
AnnotatedMember am, JavaType baseType) {
return null;
}
/**
* Method for checking if given structured property entity (field or method that
* has nominal value of Map, Collection or array type) has annotations
* that indicate that specific type resolver is to be used for handling type
* information of contained values.
* This includes not only
* instantiating resolver builder, but also configuring it based on
* relevant annotations (not including ones checked with a call to
* {@link #findSubtypes}
*
* @param config Configuration settings in effect (for serialization or deserialization)
* @param am Annotated member (field or method) to check for annotations
* @param containerType Type of property for which resolver is to be found (must be a container type)
*
* @return Type resolver builder for values contained in properties of given entity,
* if one found; null if none
*
* @since 1.5 -- although changed in 1.8 to pass configuration object
*/
public TypeResolverBuilder<?> findPropertyContentTypeResolver(MapperConfig<?> config,
AnnotatedMember am, JavaType containerType) {
return null;
}
/**
* Method for locating annotation-specified subtypes related to annotated
* entity (class, method, field). Note that this is only guaranteed to be
* a list of directly
* declared subtypes, no recursive processing is guarantees (i.e. caller
* has to do it if/as necessary)
*
* @param a Annotated entity (class, field/method) to check for annotations
*
* @since 1.5
*/
public List<NamedType> findSubtypes(Annotated a) {
return null;
}
/**
* Method for checking if specified type has explicit name.
*
* @param ac Class to check for type name annotations
*
* @since 1.5
*/
public String findTypeName(AnnotatedClass ac) {
return null;
}
/*
/**********************************************************
/* General member (field, method/constructor) annotations
/**********************************************************
*/
/**
* Note: defined as non-abstract to reduce fragility between
* versions.
*
* @since 1.6
*/
public ReferenceProperty findReferenceType(AnnotatedMember member) {
return null;
}
/**
* Method called to check whether given property is marked to be "unwrapped"
* when being serialized (and appropriately handled in reverse direction,
* i.e. expect unwrapped representation during deserialization)
*
* @since 1.9
*/
public Boolean shouldUnwrapProperty(AnnotatedMember member) {
return null;
}
/**
* Method called to check whether given property is marked to
* be ignored; but NOT to determine if it should necessarily
* be ignored, since that may depend on other factors.
*<p>
* Default implementation calls existing 'isIgnored' methods
* such as {@link #isIgnorableField(AnnotatedField)} and
* {@link #isIgnorableMethod(AnnotatedMethod)}.
*
* @since 1.9
*/
public boolean hasIgnoreMarker(AnnotatedMember m)
{
/* For maximum backwards compatibility, we better call
* existing methods.
*/
/* TODO: For 2.0, replace with simple 'return false;'
*/
if (m instanceof AnnotatedMethod) {
return isIgnorableMethod((AnnotatedMethod) m);
}
if (m instanceof AnnotatedField) {
return isIgnorableField((AnnotatedField) m);
}
if (m instanceof AnnotatedConstructor) {
return isIgnorableConstructor((AnnotatedConstructor) m);
}
return false;
}
/**
* Method called to find out whether given member expectes a value
* to be injected, and if so, what is the identifier of the value
* to use during injection.
* Type if identifier needs to be compatible with provider of
* values (of type {@link InjectableValues}); often a simple String
* id is used.
*
* @param m Member to check
*
* @return Identifier of value to inject, if any; null if no injection
* indicator is found
*/
public Object findInjectableValueId(AnnotatedMember m) {
return null;
}
/*
/**********************************************************
/* General method annotations
/**********************************************************
*/
/**
* Method for checking whether there is an annotation that
* indicates that given method should be ignored for all
* operations (serialization, deserialization).
*<p>
* Note that this method should <b>ONLY</b> return true for such
* explicit ignoral cases; and not if method just happens not to
* be visible for annotation processor.
*
* @return True, if an annotation is found to indicate that the
* method should be ignored; false if not.
*/
public abstract boolean isIgnorableMethod(AnnotatedMethod m);
/**
* @since 1.2
*/
public abstract boolean isIgnorableConstructor(AnnotatedConstructor c);
/*
/**********************************************************
/* General field annotations
/**********************************************************
*/
/**
* Method for checking whether there is an annotation that
* indicates that given field should be ignored for all
* operations (serialization, deserialization).
*
* @return True, if an annotation is found to indicate that the
* field should be ignored; false if not.
*/
public abstract boolean isIgnorableField(AnnotatedField f);
/*
/**********************************************************
/* Serialization: general annotations
/**********************************************************
*/
/**
* Method for getting a serializer definition on specified method
* or field. Type of definition is either instance (of type
* {@link JsonSerializer}) or Class (of type
* <code>Class<JsonSerializer></code>); if value of different
* type is returned, a runtime exception may be thrown by caller.
*<p>
* Note: this variant was briefly deprecated for 1.7; should not be
*/
public abstract Object findSerializer(Annotated am);
/**
* Method for getting a serializer definition for keys of associated <code>Map</code> property.
* Type of definition is either instance (of type
* {@link JsonSerializer}) or Class (of type
* <code>Class<JsonSerializer></code>); if value of different
* type is returned, a runtime exception may be thrown by caller.
*
* @since 1.8
*/
public Class<? extends JsonSerializer<?>> findKeySerializer(Annotated am) {
return null;
}
/**
* Method for getting a serializer definition for content (values) of
* associated <code>Collection</code>, <code>array</code> or <code>Map</code> property.
* Type of definition is either instance (of type
* {@link JsonSerializer}) or Class (of type
* <code>Class<JsonSerializer></code>); if value of different
* type is returned, a runtime exception may be thrown by caller.
*
* @since 1.8
*/
public Class<? extends JsonSerializer<?>> findContentSerializer(Annotated am) {
return null;
}
/**
* Method for checking whether given annotated entity (class, method,
* field) defines which Bean/Map properties are to be included in
* serialization.
* If no annotation is found, method should return given second
* argument; otherwise value indicated by the annotation
*
* @return Enumerated value indicating which properties to include
* in serialization
*/
public JsonSerialize.Inclusion findSerializationInclusion(Annotated a, JsonSerialize.Inclusion defValue) {
return defValue;
}
/**
* Method for accessing annotated type definition that a
* method/field can have, to be used as the type for serialization
* instead of the runtime type.
* Type returned (if any) needs to be widening conversion (super-type).
* Declared return type of the method is also considered acceptable.
*
* @return Class to use instead of runtime type
*/
public abstract Class<?> findSerializationType(Annotated a);
/**
* Method for finding possible widening type definition that a property
* value can have, to define less specific key type to use for serialization.
* It should be only be used with {@link java.util.Map} types.
*
* @return Class specifying more general type to use instead of
* declared type, if annotation found; null if not
*/
public Class<?> findSerializationKeyType(Annotated am, JavaType baseType) {
return null;
}
/**
* Method for finding possible widening type definition that a property
* value can have, to define less specific key type to use for serialization.
* It should be only used with structured types (arrays, collections, maps).
*
* @return Class specifying more general type to use instead of
* declared type, if annotation found; null if not
*/
public Class<?> findSerializationContentType(Annotated am, JavaType baseType) {
return null;
}
/**
* Method for accessing declared typing mode annotated (if any).
* This is used for type detection, unless more granular settings
* (such as actual exact type; or serializer to use which means
* no type information is needed) take precedence.
*
* @since 1.2
*
* @return Typing mode to use, if annotation is found; null otherwise
*/
public abstract JsonSerialize.Typing findSerializationTyping(Annotated a);
/**
* Method for checking if annotated serializable property (represented by
* field or getter method) has definitions for views it is to be included
* in. If null is returned, no view definitions exist and property is always
* included; otherwise it will only be included for views included in returned
* array. View matches are checked using class inheritance rules (sub-classes
* inherit inclusions of super-classes)
*
* @param a Annotated serializable property (field or getter method)
* @return Array of views (represented by classes) that the property is included in;
* if null, always included (same as returning array containing <code>Object.class</code>)
*/
public abstract Class<?>[] findSerializationViews(Annotated a);
/*
/**********************************************************
/* Serialization: class annotations
/**********************************************************
*/
/**
* Method for accessing defined property serialization order (which may be
* partial). May return null if no ordering is defined.
*
* @since 1.4
*/
public abstract String[] findSerializationPropertyOrder(AnnotatedClass ac);
/**
* Method for checking whether an annotation indicates that serialized properties
* for which no explicit is defined should be alphabetically (lexicograpically)
* ordered
*
* @since 1.4
*/
public abstract Boolean findSerializationSortAlphabetically(AnnotatedClass ac);
/*
/**********************************************************
/* Serialization: method annotations
/**********************************************************
*/
/**
* Method for checking whether given method has an annotation
* that suggests property name associated with method that
* may be a "getter". Should return null if no annotation
* is found; otherwise a non-null String.
* If non-null value is returned, it is used as the property
* name, except for empty String ("") which is taken to mean
* "use standard bean name detection if applicable;
* method name if not".
*/
public abstract String findGettablePropertyName(AnnotatedMethod am);
/**
* Method for checking whether given method has an annotation
* that suggests that the return value of annotated method
* should be used as "the value" of the object instance; usually
* serialized as a primitive value such as String or number.
*
* @return True if such annotation is found (and is not disabled);
* false if no enabled annotation is found
*/
public abstract boolean hasAsValueAnnotation(AnnotatedMethod am);
/**
* Method for determining the String value to use for serializing
* given enumeration entry; used when serializing enumerations
* as Strings (the standard method).
*
* @return Serialized enum value.
*/
public abstract String findEnumValue(Enum<?> value);
/*
/**********************************************************
/* Serialization: field annotations
/**********************************************************
*/
/**
* Method for checking whether given member field represent
* a serializable logical property; and if so, returns the
* name of that property.
* Should return null if no annotation is found (indicating it
* is not a serializable field); otherwise a non-null String.
* If non-null value is returned, it is used as the property
* name, except for empty String ("") which is taken to mean
* "use the field name as is".
*/
public abstract String findSerializablePropertyName(AnnotatedField af);
/*
/**********************************************************
/* Deserialization: general annotations
/**********************************************************
*/
/**
* Method for getting a deserializer definition on specified method
* or field.
* Type of definition is either instance (of type
* {@link JsonDeserializer}) or Class (of type
* <code>Class<JsonDeserializer></code>); if value of different
* type is returned, a runtime exception may be thrown by caller.
*<p>
* Note: this variant was briefly deprecated for 1.7; but it turns out
* we really should not try to push BeanProperty through at this point
*/
public abstract Object findDeserializer(Annotated am);
/**
* Method for getting a deserializer definition for keys of
* associated <code>Map</code> property.
* Type of definition is either instance (of type
* {@link JsonDeserializer}) or Class (of type
* <code>Class<JsonDeserializer></code>); if value of different
* type is returned, a runtime exception may be thrown by caller.
*
* @since 1.3
*/
public abstract Class<? extends KeyDeserializer> findKeyDeserializer(Annotated am);
/**
* Method for getting a deserializer definition for content (values) of
* associated <code>Collection</code>, <code>array</code> or
* <code>Map</code> property.
* Type of definition is either instance (of type
* {@link JsonDeserializer}) or Class (of type
* <code>Class<JsonDeserializer></code>); if value of different
* type is returned, a runtime exception may be thrown by caller.
*
* @since 1.3
*/
public abstract Class<? extends JsonDeserializer<?>> findContentDeserializer(Annotated am);
/**
* Method for accessing annotated type definition that a
* method can have, to be used as the type for serialization
* instead of the runtime type.
* Type must be a narrowing conversion
* (i.e.subtype of declared type).
* Declared return type of the method is also considered acceptable.
*
* @param baseType Assumed type before considering annotations
* @param propName Logical property name of the property that uses
* type, if known; null for types not associated with property
*
* @return Class to use for deserialization instead of declared type
*/
public abstract Class<?> findDeserializationType(Annotated am, JavaType baseType,
String propName);
/**
* Method for accessing additional narrowing type definition that a
* method can have, to define more specific key type to use.
* It should be only be used with {@link java.util.Map} types.
*
* @param baseKeyType Assumed key type before considering annotations
* @param propName Logical property name of the property that uses
* type, if known; null for types not associated with property
*
* @return Class specifying more specific type to use instead of
* declared type, if annotation found; null if not
*/
public abstract Class<?> findDeserializationKeyType(Annotated am, JavaType baseKeyType,
String propName);
/**
* Method for accessing additional narrowing type definition that a
* method can have, to define more specific content type to use;
* content refers to Map values and Collection/array elements.
* It should be only be used with Map, Collection and array types.
*
* @param baseContentType Assumed content (value) type before considering annotations
* @param propName Logical property name of the property that uses
* type, if known; null for types not associated with property
*
* @return Class specifying more specific type to use instead of
* declared type, if annotation found; null if not
*/
public abstract Class<?> findDeserializationContentType(Annotated am, JavaType baseContentType,
String propName);
/*
/**********************************************************
/* Deserialization: class annotations
/**********************************************************
*/
/**
* Method getting {@link ValueInstantiator} to use for given
* type (class): return value can either be an instance of
* instantiator, or class of instantiator to create.
*
* @since 1.9
*/
public Object findValueInstantiator(AnnotatedClass ac) {
return null;
}
/*
/**********************************************************
/* Deserialization: method annotations
/**********************************************************
*/
/**
* Method for checking whether given method has an annotation
* that suggests property name associated with method that
* may be a "setter". Should return null if no annotation
* is found; otherwise a non-null String.
* If non-null value is returned, it is used as the property
* name, except for empty String ("") which is taken to mean
* "use standard bean name detection if applicable;
* method name if not".
*/
public abstract String findSettablePropertyName(AnnotatedMethod am);
/**
* Method for checking whether given method has an annotation
* that suggests that the method is to serve as "any setter";
* method to be used for setting values of any properties for
* which no dedicated setter method is found.
*
* @return True if such annotation is found (and is not disabled),
* false otherwise
*/
public boolean hasAnySetterAnnotation(AnnotatedMethod am) {
return false;
}
/**
* Method for checking whether given method has an annotation
* that suggests that the method is to serve as "any setter";
* method to be used for accessing set of miscellaneous "extra"
* properties, often bound with matching "any setter" method.
*
* @return True if such annotation is found (and is not disabled),
* false otherwise
*
* @since 1.6
*/
public boolean hasAnyGetterAnnotation(AnnotatedMethod am) {
return false;
}
/**
* Method for checking whether given annotated item (method, constructor)
* has an annotation
* that suggests that the method is a "creator" (aka factory)
* method to be used for construct new instances of deserialized
* values.
*
* @return True if such annotation is found (and is not disabled),
* false otherwise
*/
public boolean hasCreatorAnnotation(Annotated a) {
return false;
}
/*
/**********************************************************
/* Deserialization: field annotations
/**********************************************************
*/
/**
* Method for checking whether given member field represent
* a deserializable logical property; and if so, returns the
* name of that property.
* Should return null if no annotation is found (indicating it
* is not a deserializable field); otherwise a non-null String.
* If non-null value is returned, it is used as the property
* name, except for empty String ("") which is taken to mean
* "use the field name as is".
*/
public abstract String findDeserializablePropertyName(AnnotatedField af);
/*
/**********************************************************
/* Deserialization: parameter annotations (for
/* creator method parameters)
/**********************************************************
*/
/**
* Method for checking whether given set of annotations indicates
* property name for associated parameter.
* No actual parameter object can be passed since JDK offers no
* representation; just annotations.
*/
public abstract String findPropertyNameForParam(AnnotatedParameter param);
/*
/**********************************************************
/* Helper classes
/**********************************************************
*/
/**
* Helper class that allows using 2 introspectors such that one
* introspector acts as the primary one to use; and second one
* as a fallback used if the primary does not provide conclusive
* or useful result for a method.
*<p>
* An obvious consequence of priority is that it is easy to construct
* longer chains of introspectors by linking multiple pairs.
* Currently most likely combination is that of using the default
* Jackson provider, along with JAXB annotation introspector (available
* since version 1.1).
*/
public static class Pair
extends AnnotationIntrospector
{
protected final AnnotationIntrospector _primary, _secondary;
public Pair(AnnotationIntrospector p,
AnnotationIntrospector s)
{
_primary = p;
_secondary = s;
}
/**
* Helper method for constructing a Pair from two given introspectors (if
* neither is null); or returning non-null introspector if one is null
* (and return just null if both are null)
*
* @since 1.7
*/
public static AnnotationIntrospector create(AnnotationIntrospector primary,
AnnotationIntrospector secondary)
{
if (primary == null) {
return secondary;
}
if (secondary == null) {
return primary;
}
return new Pair(primary, secondary);
}
@Override
public Collection<AnnotationIntrospector> allIntrospectors() {
return allIntrospectors(new ArrayList<AnnotationIntrospector>());
}
@Override
public Collection<AnnotationIntrospector> allIntrospectors(Collection<AnnotationIntrospector> result)
{
_primary.allIntrospectors(result);
_secondary.allIntrospectors(result);
return result;
}
// // // Generic annotation properties, lookup
@Override
public boolean isHandled(Annotation ann)
{
return _primary.isHandled(ann) || _secondary.isHandled(ann);
}
/*
/******************************************************
/* General class annotations
/******************************************************
*/
@Override
public Boolean findCachability(AnnotatedClass ac)
{
Boolean result = _primary.findCachability(ac);
if (result == null) {
result = _secondary.findCachability(ac);
}
return result;
}
@Override
public String findRootName(AnnotatedClass ac)
{
String name1 = _primary.findRootName(ac);
if (name1 == null) {
return _secondary.findRootName(ac);
} else if (name1.length() > 0) {
return name1;
}
// name1 is empty; how about secondary?
String name2 = _secondary.findRootName(ac);
return (name2 == null) ? name1 : name2;
}
@Override
public String[] findPropertiesToIgnore(AnnotatedClass ac)
{
String[] result = _primary.findPropertiesToIgnore(ac);
if (result == null) {
result = _secondary.findPropertiesToIgnore(ac);
}
return result;
}
@Override
public Boolean findIgnoreUnknownProperties(AnnotatedClass ac)
{
Boolean result = _primary.findIgnoreUnknownProperties(ac);
if (result == null) {
result = _secondary.findIgnoreUnknownProperties(ac);
}
return result;
}
@Override
public Boolean isIgnorableType(AnnotatedClass ac)
{
Boolean result = _primary.isIgnorableType(ac);
if (result == null) {
result = _secondary.isIgnorableType(ac);
}
return result;
}
@Override
public Object findFilterId(AnnotatedClass ac)
{
Object id = _primary.findFilterId(ac);
if (id == null) {
id = _secondary.findFilterId(ac);
}
return id;
}
/*
/******************************************************
/* Property auto-detection
/******************************************************
*/
@Override
public VisibilityChecker<?> findAutoDetectVisibility(AnnotatedClass ac,
VisibilityChecker<?> checker)
{
/* Note: to have proper priorities, we must actually call delegatees
* in reverse order:
*/
checker = _secondary.findAutoDetectVisibility(ac, checker);
return _primary.findAutoDetectVisibility(ac, checker);
}
/*
/******************************************************
/* Type handling
/******************************************************
*/
@Override
public TypeResolverBuilder<?> findTypeResolver(MapperConfig<?> config,
AnnotatedClass ac, JavaType baseType)
{
TypeResolverBuilder<?> b = _primary.findTypeResolver(config, ac, baseType);
if (b == null) {
b = _secondary.findTypeResolver(config, ac, baseType);
}
return b;
}
@Override
public TypeResolverBuilder<?> findPropertyTypeResolver(MapperConfig<?> config,
AnnotatedMember am, JavaType baseType)
{
TypeResolverBuilder<?> b = _primary.findPropertyTypeResolver(config, am, baseType);
if (b == null) {
b = _secondary.findPropertyTypeResolver(config, am, baseType);
}
return b;
}
@Override
public TypeResolverBuilder<?> findPropertyContentTypeResolver(MapperConfig<?> config,
AnnotatedMember am, JavaType baseType)
{
TypeResolverBuilder<?> b = _primary.findPropertyContentTypeResolver(config, am, baseType);
if (b == null) {
b = _secondary.findPropertyContentTypeResolver(config, am, baseType);
}
return b;
}
@Override
public List<NamedType> findSubtypes(Annotated a)
{
List<NamedType> types1 = _primary.findSubtypes(a);
List<NamedType> types2 = _secondary.findSubtypes(a);
if (types1 == null || types1.isEmpty()) return types2;
if (types2 == null || types2.isEmpty()) return types1;
ArrayList<NamedType> result = new ArrayList<NamedType>(types1.size() + types2.size());
result.addAll(types1);
result.addAll(types2);
return result;
}
@Override
public String findTypeName(AnnotatedClass ac)
{
String name = _primary.findTypeName(ac);
if (name == null || name.length() == 0) {
name = _secondary.findTypeName(ac);
}
return name;
}
// // // General member (field, method/constructor) annotations
@Override
public ReferenceProperty findReferenceType(AnnotatedMember member)
{
ReferenceProperty ref = _primary.findReferenceType(member);
if (ref == null) {
ref = _secondary.findReferenceType(member);
}
return ref;
}
@Override
public Boolean shouldUnwrapProperty(AnnotatedMember member)
{
Boolean value = _primary.shouldUnwrapProperty(member);
if (value == null) {
value = _secondary.shouldUnwrapProperty(member);
}
return value;
}
@Override
public Object findInjectableValueId(AnnotatedMember m)
{
Object value = _primary.findInjectableValueId(m);
if (value == null) {
value = _secondary.findInjectableValueId(m);
}
return value;
}
@Override
public boolean hasIgnoreMarker(AnnotatedMember m) {
return _primary.hasIgnoreMarker(m) || _secondary.hasIgnoreMarker(m);
}
// // // General method annotations
@Override
public boolean isIgnorableMethod(AnnotatedMethod m) {
return _primary.isIgnorableMethod(m) || _secondary.isIgnorableMethod(m);
}
@Override
public boolean isIgnorableConstructor(AnnotatedConstructor c) {
return _primary.isIgnorableConstructor(c) || _secondary.isIgnorableConstructor(c);
}
// // // General field annotations
@Override
public boolean isIgnorableField(AnnotatedField f)
{
return _primary.isIgnorableField(f) || _secondary.isIgnorableField(f);
}
// // // Serialization: general annotations
@Override
public Object findSerializer(Annotated am)
{
Object result = _primary.findSerializer(am);
if (result == null) {
result = _secondary.findSerializer(am);
}
return result;
}
@Override
public Class<? extends JsonSerializer<?>> findKeySerializer(Annotated a)
{
Class<? extends JsonSerializer<?>> result = _primary.findKeySerializer(a);
if (result == null || result == JsonSerializer.None.class) {
result = _secondary.findKeySerializer(a);
}
return result;
}
@Override
public Class<? extends JsonSerializer<?>> findContentSerializer(Annotated a)
{
Class<? extends JsonSerializer<?>> result = _primary.findContentSerializer(a);
if (result == null || result == JsonSerializer.None.class) {
result = _secondary.findContentSerializer(a);
}
return result;
}
@Override
public JsonSerialize.Inclusion findSerializationInclusion(Annotated a,
JsonSerialize.Inclusion defValue)
{
/* This is bit trickier: need to combine results in a meaningful
* way. Seems like it should be a disjoint; that is, most
* restrictive value should be returned.
* For enumerations, comparison is done by indexes, which
* works: largest value is the last one, which is the most
* restrictive value as well.
*/
/* 09-Mar-2010, tatu: Actually, as per [JACKSON-256], it is probably better to just
* use strict overriding. Simpler, easier to understand.
*/
// note: call secondary first, to give lower priority
defValue = _secondary.findSerializationInclusion(a, defValue);
defValue = _primary.findSerializationInclusion(a, defValue);
return defValue;
}
@Override
public Class<?> findSerializationType(Annotated a)
{
Class<?> result = _primary.findSerializationType(a);
if (result == null) {
result = _secondary.findSerializationType(a);
}
return result;
}
@Override
public Class<?> findSerializationKeyType(Annotated am, JavaType baseType)
{
Class<?> result = _primary.findSerializationKeyType(am, baseType);
if (result == null) {
result = _secondary.findSerializationKeyType(am, baseType);
}
return result;
}
@Override
public Class<?> findSerializationContentType(Annotated am, JavaType baseType)
{
Class<?> result = _primary.findSerializationContentType(am, baseType);
if (result == null) {
result = _secondary.findSerializationContentType(am, baseType);
}
return result;
}
@Override
public JsonSerialize.Typing findSerializationTyping(Annotated a)
{
JsonSerialize.Typing result = _primary.findSerializationTyping(a);
if (result == null) {
result = _secondary.findSerializationTyping(a);
}
return result;
}
@Override
public Class<?>[] findSerializationViews(Annotated a)
{
/* Theoretically this could be trickier, if multiple introspectors
* return non-null entries. For now, though, we'll just consider
* first one to return non-null to win.
*/
Class<?>[] result = _primary.findSerializationViews(a);
if (result == null) {
result = _secondary.findSerializationViews(a);
}
return result;
}
// // // Serialization: class annotations
@Override
public String[] findSerializationPropertyOrder(AnnotatedClass ac) {
String[] result = _primary.findSerializationPropertyOrder(ac);
if (result == null) {
result = _secondary.findSerializationPropertyOrder(ac);
}
return result;
}
/**
* Method for checking whether an annotation indicates that serialized properties
* for which no explicit is defined should be alphabetically (lexicograpically)
* ordered
*/
@Override
public Boolean findSerializationSortAlphabetically(AnnotatedClass ac) {
Boolean result = _primary.findSerializationSortAlphabetically(ac);
if (result == null) {
result = _secondary.findSerializationSortAlphabetically(ac);
}
return result;
}
// // // Serialization: method annotations
@Override
public String findGettablePropertyName(AnnotatedMethod am)
{
String result = _primary.findGettablePropertyName(am);
if (result == null) {
result = _secondary.findGettablePropertyName(am);
} else if (result.length() == 0) {
/* Empty String is a default; can be overridden by
* more explicit answer from secondary entry
*/
String str2 = _secondary.findGettablePropertyName(am);
if (str2 != null) {
result = str2;
}
}
return result;
}
@Override
public boolean hasAsValueAnnotation(AnnotatedMethod am)
{
return _primary.hasAsValueAnnotation(am) || _secondary.hasAsValueAnnotation(am);
}
@Override
public String findEnumValue(Enum<?> value)
{
String result = _primary.findEnumValue(value);
if (result == null) {
result = _secondary.findEnumValue(value);
}
return result;
}
// // // Serialization: field annotations
@Override
public String findSerializablePropertyName(AnnotatedField af)
{
String result = _primary.findSerializablePropertyName(af);
if (result == null) {
result = _secondary.findSerializablePropertyName(af);
} else if (result.length() == 0) {
/* Empty String is a default; can be overridden by
* more explicit answer from secondary entry
*/
String str2 = _secondary.findSerializablePropertyName(af);
if (str2 != null) {
result = str2;
}
}
return result;
}
// // // Deserialization: general annotations
@Override
public Object findDeserializer(Annotated am)
{
Object result = _primary.findDeserializer(am);
if (result == null) {
result = _secondary.findDeserializer(am);
}
return result;
}
@Override
public Class<? extends KeyDeserializer> findKeyDeserializer(Annotated am)
{
Class<? extends KeyDeserializer> result = _primary.findKeyDeserializer(am);
if (result == null || result == KeyDeserializer.None.class) {
result = _secondary.findKeyDeserializer(am);
}
return result;
}
@Override
public Class<? extends JsonDeserializer<?>> findContentDeserializer(Annotated am)
{
Class<? extends JsonDeserializer<?>> result = _primary.findContentDeserializer(am);
if (result == null || result == JsonDeserializer.None.class) {
result = _secondary.findContentDeserializer(am);
}
return result;
}
@Override
public Class<?> findDeserializationType(Annotated am, JavaType baseType,
String propName)
{
Class<?> result = _primary.findDeserializationType(am, baseType, propName);
if (result == null) {
result = _secondary.findDeserializationType(am, baseType, propName);
}
return result;
}
@Override
public Class<?> findDeserializationKeyType(Annotated am, JavaType baseKeyType,
String propName)
{
Class<?> result = _primary.findDeserializationKeyType(am, baseKeyType, propName);
if (result == null) {
result = _secondary.findDeserializationKeyType(am, baseKeyType, propName);
}
return result;
}
@Override
public Class<?> findDeserializationContentType(Annotated am, JavaType baseContentType,
String propName)
{
Class<?> result = _primary.findDeserializationContentType(am, baseContentType, propName);
if (result == null) {
result = _secondary.findDeserializationContentType(am, baseContentType, propName);
}
return result;
}
// // // Deserialization: class annotations
@Override
public Object findValueInstantiator(AnnotatedClass ac)
{
Object result = _primary.findValueInstantiator(ac);
if (result == null) {
result = _secondary.findValueInstantiator(ac);
}
return result;
}
// // // Deserialization: method annotations
@Override
public String findSettablePropertyName(AnnotatedMethod am)
{
String result = _primary.findSettablePropertyName(am);
if (result == null) {
result = _secondary.findSettablePropertyName(am);
} else if (result.length() == 0) {
/* Empty String is a default; can be overridden by
* more explicit answer from secondary entry
*/
String str2 = _secondary.findSettablePropertyName(am);
if (str2 != null) {
result = str2;
}
}
return result;
}
@Override
public boolean hasAnySetterAnnotation(AnnotatedMethod am)
{
return _primary.hasAnySetterAnnotation(am) || _secondary.hasAnySetterAnnotation(am);
}
@Override
public boolean hasAnyGetterAnnotation(AnnotatedMethod am)
{
return _primary.hasAnyGetterAnnotation(am) || _secondary.hasAnyGetterAnnotation(am);
}
@Override
public boolean hasCreatorAnnotation(Annotated a)
{
return _primary.hasCreatorAnnotation(a) || _secondary.hasCreatorAnnotation(a);
}
// // // Deserialization: field annotations
@Override
public String findDeserializablePropertyName(AnnotatedField af)
{
String result = _primary.findDeserializablePropertyName(af);
if (result == null) {
result = _secondary.findDeserializablePropertyName(af);
} else if (result.length() == 0) {
/* Empty String is a default; can be overridden by
* more explicit answer from secondary entry
*/
String str2 = _secondary.findDeserializablePropertyName(af);
if (str2 != null) {
result = str2;
}
}
return result;
}
// // // Deserialization: parameter annotations (for creators)
@Override
public String findPropertyNameForParam(AnnotatedParameter param)
{
String result = _primary.findPropertyNameForParam(param);
if (result == null) {
result = _secondary.findPropertyNameForParam(param);
}
return result;
}
}
}