blob: e2c1fbf7b0d644399439e6428aa47dc9033ccbff [file] [log] [blame]
package com.fasterxml.jackson.databind.deser;
import java.lang.reflect.Type;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.cfg.MapperConfig;
import com.fasterxml.jackson.databind.deser.impl.DeserializerFactoryConfig;
import com.fasterxml.jackson.databind.deser.std.JdkDeserializers;
import com.fasterxml.jackson.databind.deser.std.ThrowableDeserializer;
import com.fasterxml.jackson.databind.introspect.*;
import com.fasterxml.jackson.databind.jsontype.TypeDeserializer;
import com.fasterxml.jackson.databind.type.ClassKey;
import com.fasterxml.jackson.databind.type.TypeFactory;
import com.fasterxml.jackson.databind.util.ArrayBuilders;
import com.fasterxml.jackson.databind.util.ClassUtil;
import com.fasterxml.jackson.databind.util.SimpleBeanPropertyDefinition;
/**
* Concrete deserializer factory class that adds full Bean deserializer
* construction logic using class introspection.
* Note that factories specifically do not implement any form of caching:
* aside from configuration they are stateless; caching is implemented
* by other components.
*<p>
* Instances of this class are fully immutable as all configuration is
* done by using "fluent factories" (methods that construct new factory
* instances with different configuration, instead of modifying instance).
*/
public class BeanDeserializerFactory
extends BasicDeserializerFactory
{
/**
* Signature of <b>Throwable.initCause</b> method.
*/
private final static Class<?>[] INIT_CAUSE_PARAMS = new Class<?>[] { Throwable.class };
/*
/**********************************************************
/* Life-cycle
/**********************************************************
*/
/**
* Globally shareable thread-safe instance which has no additional custom deserializers
* registered
*/
public final static BeanDeserializerFactory instance = new BeanDeserializerFactory(
new DeserializerFactoryConfig());
public BeanDeserializerFactory(DeserializerFactoryConfig config) {
super(config);
}
/**
* Method used by module registration functionality, to construct a new bean
* deserializer factory
* with different configuration settings.
*/
@Override
public DeserializerFactory withConfig(DeserializerFactoryConfig config)
{
if (_factoryConfig == config) {
return this;
}
/* 22-Nov-2010, tatu: Handling of subtypes is tricky if we do immutable-with-copy-ctor;
* and we pretty much have to here either choose between losing subtype instance
* when registering additional deserializers, or losing deserializers.
* Instead, let's actually just throw an error if this method is called when subtype
* has not properly overridden this method; this to indicate problem as soon as possible.
*/
if (getClass() != BeanDeserializerFactory.class) {
throw new IllegalStateException("Subtype of BeanDeserializerFactory ("+getClass().getName()
+") has not properly overridden method 'withAdditionalDeserializers': can not instantiate subtype with "
+"additional deserializer definitions");
}
return new BeanDeserializerFactory(config);
}
/*
/**********************************************************
/* Overrides for super-class methods used for finding
/* custom deserializers
/**********************************************************
*/
// Note: NOT overriding, superclass has no matching method
@SuppressWarnings("unchecked")
protected JsonDeserializer<Object> _findCustomBeanDeserializer(JavaType type, DeserializationConfig config,
BeanDescription beanDesc, BeanProperty property)
throws JsonMappingException
{
for (Deserializers d : _factoryConfig.deserializers()) {
JsonDeserializer<?> deser = d.findBeanDeserializer(type, config, beanDesc, property);
if (deser != null) {
return (JsonDeserializer<Object>) deser;
}
}
return null;
}
/*
/**********************************************************
/* DeserializerFactory API implementation
/**********************************************************
*/
/**
* Method that {@link DeserializerCache}s call to create a new
* deserializer for types other than Collections, Maps, arrays and
* enums.
*/
@Override
public JsonDeserializer<Object> createBeanDeserializer(DeserializationContext ctxt,
JavaType type, BeanDescription beanDesc, BeanProperty property)
throws JsonMappingException
{
final DeserializationConfig config = ctxt.getConfig();
// We may also have custom overrides:
JsonDeserializer<Object> custom = _findCustomBeanDeserializer(type, config, beanDesc, property);
if (custom != null) {
return custom;
}
/* One more thing to check: do we have an exception type
* (Throwable or its sub-classes)? If so, need slightly
* different handling.
*/
if (type.isThrowable()) {
return buildThrowableDeserializer(ctxt, type, beanDesc, property);
}
/* Or, for abstract types, may have alternate means for resolution
* (defaulting, materialization)
*/
if (type.isAbstract()) {
// [JACKSON-41] (v1.6): Let's make it possible to materialize abstract types.
JavaType concreteType = materializeAbstractType(config, beanDesc);
if (concreteType != null) {
/* important: introspect actual implementation (abstract class or
* interface doesn't have constructors, for one)
*/
beanDesc = config.introspect(concreteType);
return buildBeanDeserializer(ctxt, concreteType, beanDesc, property);
}
}
// Otherwise, may want to check handlers for standard types, from superclass:
JsonDeserializer<Object> deser = findStdBeanDeserializer(config, type, property);
if (deser != null) {
return deser;
}
// Otherwise: could the class be a Bean class? If not, bail out
if (!isPotentialBeanType(type.getRawClass())) {
return null;
}
// Use generic bean introspection to build deserializer
return buildBeanDeserializer(ctxt, type, beanDesc, property);
}
/**
* Method called by {@link BeanDeserializerFactory} to see if there might be a standard
* deserializer registered for given type.
*/
@SuppressWarnings("unchecked")
protected JsonDeserializer<Object> findStdBeanDeserializer(DeserializationConfig config,
JavaType type, BeanProperty property)
throws JsonMappingException
{
Class<?> cls = type.getRawClass();
// note: we do NOT check for custom deserializers here; that's for sub-class to do
JsonDeserializer<Object> deser = _simpleDeserializers.get(new ClassKey(cls));
if (deser != null) {
return deser;
}
// [JACKSON-283]: AtomicReference is a rather special type...
if (AtomicReference.class.isAssignableFrom(cls)) {
// Must find parameterization
TypeFactory tf = config.getTypeFactory();
JavaType[] params = tf.findTypeParameters(type, AtomicReference.class);
JavaType referencedType;
if (params == null || params.length < 1) { // untyped (raw)
referencedType = TypeFactory.unknownType();
} else {
referencedType = params[0];
}
JsonDeserializer<?> d2 = new JdkDeserializers.AtomicReferenceDeserializer(referencedType, property);
return (JsonDeserializer<Object>)d2;
}
// [JACKSON-386]: External/optional type handlers are handled somewhat differently
JsonDeserializer<?> d = optionalHandlers.findDeserializer(type, config);
if (d != null) {
return (JsonDeserializer<Object>)d;
}
return null;
}
protected JavaType materializeAbstractType(DeserializationConfig config,
BeanDescription beanDesc)
throws JsonMappingException
{
final JavaType abstractType = beanDesc.getType();
/* [JACKSON-502] (1.8): Now it is possible to have multiple resolvers too,
* as they are registered via module interface.
*/
for (AbstractTypeResolver r : _factoryConfig.abstractTypeResolvers()) {
JavaType concrete = r.resolveAbstractType(config, abstractType);
if (concrete != null) {
return concrete;
}
}
return null;
}
/*
/**********************************************************
/* Public construction method beyond DeserializerFactory API:
/* can be called from outside as well as overridden by
/* sub-classes
/**********************************************************
*/
/**
* Method that is to actually build a bean deserializer instance.
* All basic sanity checks have been done to know that what we have
* may be a valid bean type, and that there are no default simple
* deserializers.
*/
@SuppressWarnings("unchecked")
public JsonDeserializer<Object> buildBeanDeserializer(DeserializationContext ctxt,
JavaType type, BeanDescription beanDesc, BeanProperty property)
throws JsonMappingException
{
// First: check what creators we can use, if any
ValueInstantiator valueInstantiator = findValueInstantiator(ctxt, beanDesc);
final DeserializationConfig config = ctxt.getConfig();
// ... since often we have nothing to go on, if we have abstract type:
if (type.isAbstract()) {
if (!valueInstantiator.canInstantiate()) {
// and if so, need placeholder deserializer
return new AbstractDeserializer(type);
}
}
BeanDeserializerBuilder builder = constructBeanDeserializerBuilder(ctxt, beanDesc);
builder.setValueInstantiator(valueInstantiator);
// And then setters for deserializing from JSON Object
addBeanProps(ctxt, beanDesc, builder);
// managed/back reference fields/setters need special handling... first part
addReferenceProperties(ctxt, beanDesc, builder);
addInjectables(ctxt, beanDesc, builder);
// [JACKSON-440]: update builder now that all information is in?
if (_factoryConfig.hasDeserializerModifiers()) {
for (BeanDeserializerModifier mod : _factoryConfig.deserializerModifiers()) {
builder = mod.updateBuilder(config, beanDesc, builder);
}
}
JsonDeserializer<?> deserializer = builder.build(property);
// [JACKSON-440]: may have modifier(s) that wants to modify or replace serializer we just built:
if (_factoryConfig.hasDeserializerModifiers()) {
for (BeanDeserializerModifier mod : _factoryConfig.deserializerModifiers()) {
deserializer = mod.modifyDeserializer(config, beanDesc, deserializer);
}
}
return (JsonDeserializer<Object>) deserializer;
}
@SuppressWarnings("unchecked")
public JsonDeserializer<Object> buildThrowableDeserializer(DeserializationContext ctxt,
JavaType type, BeanDescription beanDesc, BeanProperty property)
throws JsonMappingException
{
final DeserializationConfig config = ctxt.getConfig();
// first: construct like a regular bean deserializer...
BeanDeserializerBuilder builder = constructBeanDeserializerBuilder(ctxt, beanDesc);
builder.setValueInstantiator(findValueInstantiator(ctxt, beanDesc));
addBeanProps(ctxt, beanDesc, builder);
// (and assume there won't be any back references)
// But then let's decorate things a bit
/* To resolve [JACKSON-95], need to add "initCause" as setter
* for exceptions (sub-classes of Throwable).
*/
AnnotatedMethod am = beanDesc.findMethod("initCause", INIT_CAUSE_PARAMS);
if (am != null) { // should never be null
SimpleBeanPropertyDefinition propDef = new SimpleBeanPropertyDefinition(am, "cause");
SettableBeanProperty prop = constructSettableProperty(ctxt, beanDesc, propDef,
am.getGenericParameterType(0));
if (prop != null) {
/* 21-Aug-2011, tatus: We may actually have found 'cause' property
* to set (with new 1.9 code)... but let's replace it just in case,
* otherwise can end up with odd errors.
*/
builder.addOrReplaceProperty(prop, true);
}
}
// And also need to ignore "localizedMessage"
builder.addIgnorable("localizedMessage");
/* As well as "message": it will be passed via constructor,
* as there's no 'setMessage()' method
*/
builder.addIgnorable("message");
// [JACKSON-440]: update builder now that all information is in?
if (_factoryConfig.hasDeserializerModifiers()) {
for (BeanDeserializerModifier mod : _factoryConfig.deserializerModifiers()) {
builder = mod.updateBuilder(config, beanDesc, builder);
}
}
JsonDeserializer<?> deserializer = builder.build(property);
/* At this point it ought to be a BeanDeserializer; if not, must assume
* it's some other thing that can handle deserialization ok...
*/
if (deserializer instanceof BeanDeserializer) {
deserializer = new ThrowableDeserializer((BeanDeserializer) deserializer);
}
// [JACKSON-440]: may have modifier(s) that wants to modify or replace serializer we just built:
if (_factoryConfig.hasDeserializerModifiers()) {
for (BeanDeserializerModifier mod : _factoryConfig.deserializerModifiers()) {
deserializer = mod.modifyDeserializer(config, beanDesc, deserializer);
}
}
return (JsonDeserializer<Object>) deserializer;
}
/*
/**********************************************************
/* Helper methods for Bean deserializer construction,
/* overridable by sub-classes
/**********************************************************
*/
/**
* Overridable method that constructs a {@link BeanDeserializerBuilder}
* which is used to accumulate information needed to create deserializer
* instance.
*/
protected BeanDeserializerBuilder constructBeanDeserializerBuilder(DeserializationContext ctxt,
BeanDescription beanDesc) {
return new BeanDeserializerBuilder(beanDesc, ctxt.getConfig());
}
/**
* Method called to figure out settable properties for the
* bean deserializer to use.
*<p>
* Note: designed to be overridable, and effort is made to keep interface
* similar between versions.
*/
protected void addBeanProps(DeserializationContext ctxt,
BeanDescription beanDesc, BeanDeserializerBuilder builder)
throws JsonMappingException
{
// Things specified as "ok to ignore"? [JACKSON-77]
AnnotationIntrospector intr = ctxt.getAnnotationIntrospector();
boolean ignoreAny = false;
{
Boolean B = intr.findIgnoreUnknownProperties(beanDesc.getClassInfo());
if (B != null) {
ignoreAny = B.booleanValue();
builder.setIgnoreUnknownProperties(ignoreAny);
}
}
// Or explicit/implicit definitions?
Set<String> ignored = ArrayBuilders.arrayToSet(intr.findPropertiesToIgnore(beanDesc.getClassInfo()));
for (String propName : ignored) {
builder.addIgnorable(propName);
}
// Also, do we have a fallback "any" setter?
AnnotatedMethod anySetter = beanDesc.findAnySetter();
if (anySetter != null) {
builder.setAnySetter(constructAnySetter(ctxt, beanDesc, anySetter));
}
// NOTE: we do NOT add @JsonIgnore'd properties into blocked ones if there's any setter
// Implicit ones via @JsonIgnore and equivalent?
if (anySetter == null) {
Collection<String> ignored2 = beanDesc.getIgnoredPropertyNames();
if (ignored2 != null) {
for (String propName : ignored2) {
// allow ignoral of similarly named JSON property, but do not force;
// latter means NOT adding this to 'ignored':
builder.addIgnorable(propName);
}
}
}
final boolean useGettersAsSetters = (ctxt.isEnabled(MapperConfig.Feature.USE_GETTERS_AS_SETTERS)
&& ctxt.isEnabled(MapperConfig.Feature.AUTO_DETECT_GETTERS));
// Ok: let's then filter out property definitions
List<BeanPropertyDefinition> propDefs = filterBeanProps(ctxt,
beanDesc, builder, beanDesc.findProperties(), ignored);
// After which we can let custom code change the set
if (_factoryConfig.hasDeserializerModifiers()) {
for (BeanDeserializerModifier mod : _factoryConfig.deserializerModifiers()) {
propDefs = mod.updateProperties(ctxt.getConfig(), beanDesc, propDefs);
}
}
// At which point we still have all kinds of properties; not all with mutators:
for (BeanPropertyDefinition propDef : propDefs) {
if (propDef.hasConstructorParameter()) {
/* [JACKSON-700] If property as passed via constructor parameter, we must
* handle things in special way. Not sure what is the most optimal way...
* for now, let's just call a (new) method in builder, which does nothing.
*/
// but let's call a method just to allow custom builders to be aware...
builder.addCreatorProperty(propDef);
continue;
}
SettableBeanProperty prop = null;
if (propDef.hasSetter()) {
Type propertyType = propDef.getSetter().getGenericParameterType(0);
prop = constructSettableProperty(ctxt,
beanDesc, propDef, propertyType);
} else if (propDef.hasField()) {
Type propertyType = propDef.getField().getGenericType();
prop = constructSettableProperty(ctxt, beanDesc, propDef, propertyType);
} else if (useGettersAsSetters && propDef.hasGetter()) {
/* As per [JACKSON-88], may also need to consider getters
* for Map/Collection properties; but with lowest precedence
*/
AnnotatedMethod getter = propDef.getGetter();
// should only consider Collections and Maps, for now?
Class<?> rawPropertyType = getter.getRawType();
if (Collection.class.isAssignableFrom(rawPropertyType)
|| Map.class.isAssignableFrom(rawPropertyType)) {
prop = constructSetterlessProperty(ctxt, beanDesc, propDef);
}
}
if (prop != null) {
// one more thing before adding to builder: copy any metadata
prop.setViews(propDef.getViews());
builder.addProperty(prop);
}
}
}
/**
* Helper method called to filter out explicit ignored properties,
* as well as properties that have "ignorable types".
* Note that this will not remove properties that have no
* setters.
*/
protected List<BeanPropertyDefinition> filterBeanProps(DeserializationContext ctxt,
BeanDescription beanDesc, BeanDeserializerBuilder builder,
List<BeanPropertyDefinition> propDefsIn,
Set<String> ignored)
throws JsonMappingException
{
ArrayList<BeanPropertyDefinition> result = new ArrayList<BeanPropertyDefinition>(
Math.max(4, propDefsIn.size()));
HashMap<Class<?>,Boolean> ignoredTypes = new HashMap<Class<?>,Boolean>();
// These are all valid setters, but we do need to introspect bit more
for (BeanPropertyDefinition property : propDefsIn) {
String name = property.getName();
if (ignored.contains(name)) { // explicit ignoral using @JsonIgnoreProperties needs to block entries
continue;
}
if (!property.hasConstructorParameter()) { // never skip constructor params
Class<?> rawPropertyType = null;
if (property.hasSetter()) {
rawPropertyType = property.getSetter().getRawParameterType(0);
} else if (property.hasField()) {
rawPropertyType = property.getField().getRawType();
}
// [JACKSON-429] Some types are declared as ignorable as well
if ((rawPropertyType != null)
&& (isIgnorableType(ctxt.getConfig(), beanDesc, rawPropertyType, ignoredTypes))) {
// important: make ignorable, to avoid errors if value is actually seen
builder.addIgnorable(name);
continue;
}
}
result.add(property);
}
return result;
}
/**
* Method that will find if bean has any managed- or back-reference properties,
* and if so add them to bean, to be linked during resolution phase.
*/
protected void addReferenceProperties(DeserializationContext ctxt,
BeanDescription beanDesc, BeanDeserializerBuilder builder)
throws JsonMappingException
{
// and then back references, not necessarily found as regular properties
Map<String,AnnotatedMember> refs = beanDesc.findBackReferenceProperties();
if (refs != null) {
for (Map.Entry<String, AnnotatedMember> en : refs.entrySet()) {
String name = en.getKey();
AnnotatedMember m = en.getValue();
Type genericType;
if (m instanceof AnnotatedMethod) {
genericType = ((AnnotatedMethod) m).getGenericParameterType(0);
} else {
genericType = m.getRawType();
}
SimpleBeanPropertyDefinition propDef = new SimpleBeanPropertyDefinition(m);
builder.addBackReferenceProperty(name, constructSettableProperty(
ctxt, beanDesc, propDef, genericType));
}
}
}
/**
* Method called locate all members used for value injection (if any),
* constructor {@link com.fasterxml.jackson.databind.deser.impl.ValueInjector} instances, and add them to builder.
*/
protected void addInjectables(DeserializationContext ctxt,
BeanDescription beanDesc, BeanDeserializerBuilder builder)
throws JsonMappingException
{
Map<Object, AnnotatedMember> raw = beanDesc.findInjectables();
if (raw != null) {
boolean fixAccess = ctxt.canOverrideAccessModifiers();
for (Map.Entry<Object, AnnotatedMember> entry : raw.entrySet()) {
AnnotatedMember m = entry.getValue();
if (fixAccess) {
m.fixAccess(); // to ensure we can call it
}
builder.addInjectable(m.getName(), beanDesc.resolveType(m.getGenericType()),
beanDesc.getClassAnnotations(), m, entry.getKey());
}
}
}
/**
* Method called to construct fallback {@link SettableAnyProperty}
* for handling unknown bean properties, given a method that
* has been designated as such setter.
*/
protected SettableAnyProperty constructAnySetter(DeserializationContext ctxt,
BeanDescription beanDesc, AnnotatedMethod setter)
throws JsonMappingException
{
if (ctxt.canOverrideAccessModifiers()) {
setter.fixAccess(); // to ensure we can call it
}
// we know it's a 2-arg method, second arg is the value
JavaType type = beanDesc.bindingsForBeanType().resolveType(setter.getGenericParameterType(1));
BeanProperty.Std property = new BeanProperty.Std(setter.getName(), type, beanDesc.getClassAnnotations(), setter);
type = resolveType(ctxt, beanDesc, type, setter, property);
/* AnySetter can be annotated with @JsonClass (etc) just like a
* regular setter... so let's see if those are used.
* Returns null if no annotations, in which case binding will
* be done at a later point.
*/
JsonDeserializer<Object> deser = findDeserializerFromAnnotation(ctxt, setter, property);
if (deser != null) {
return new SettableAnyProperty(property, setter, type, deser);
}
/* Otherwise, method may specify more specific (sub-)class for
* value (no need to check if explicit deser was specified):
*/
type = modifyTypeByAnnotation(ctxt, setter, type, property);
return new SettableAnyProperty(property, setter, type, null);
}
/**
* Method that will construct a regular bean property setter using
* the given setter method.
*
* @param setter Method to use to set property value; or null if none.
* Null only for "setterless" properties
*
* @return Property constructed, if any; or null to indicate that
* there should be no property based on given definitions.
*/
protected SettableBeanProperty constructSettableProperty(DeserializationContext ctxt,
BeanDescription beanDesc, BeanPropertyDefinition propDef,
Type jdkType)
throws JsonMappingException
{
// need to ensure method is callable (for non-public)
AnnotatedMember mutator = propDef.getMutator();
if (ctxt.canOverrideAccessModifiers()) {
mutator.fixAccess();
}
final String name = propDef.getName();
// note: this works since we know there's exactly one argument for methods
JavaType t0 = beanDesc.resolveType(jdkType);
BeanProperty.Std property = new BeanProperty.Std(name, t0, beanDesc.getClassAnnotations(), mutator);
JavaType type = resolveType(ctxt, beanDesc, t0, mutator, property);
// did type change?
if (type != t0) {
property = property.withType(type);
}
/* First: does the Method specify the deserializer to use?
* If so, let's use it.
*/
JsonDeserializer<Object> propDeser = findDeserializerFromAnnotation(ctxt, mutator, property);
type = modifyTypeByAnnotation(ctxt, mutator, type, property);
TypeDeserializer typeDeser = type.getTypeHandler();
SettableBeanProperty prop;
if (mutator instanceof AnnotatedMethod) {
prop = new SettableBeanProperty.MethodProperty(name, type, typeDeser,
beanDesc.getClassAnnotations(), (AnnotatedMethod) mutator);
} else {
prop = new SettableBeanProperty.FieldProperty(name, type, typeDeser,
beanDesc.getClassAnnotations(), (AnnotatedField) mutator);
}
if (propDeser != null) {
prop = prop.withValueDeserializer(propDeser);
}
// [JACKSON-235]: need to retain name of managed forward references:
AnnotationIntrospector.ReferenceProperty ref = ctxt.getAnnotationIntrospector().findReferenceType(mutator);
if (ref != null && ref.isManagedReference()) {
prop.setManagedReferenceName(ref.getName());
}
return prop;
}
/**
* Method that will construct a regular bean property setter using
* the given setter method.
*
* @param getter Method to use to get property value to modify, null if
* none. Non-null for "setterless" properties.
*/
protected SettableBeanProperty constructSetterlessProperty(DeserializationContext ctxt,
BeanDescription beanDesc, BeanPropertyDefinition propDef)
throws JsonMappingException
{
final String name = propDef.getName();
final AnnotatedMethod getter = propDef.getGetter();
// need to ensure it is callable now:
if (ctxt.canOverrideAccessModifiers()) {
getter.fixAccess();
}
/* 26-Jan-2012, tatu: Alas, this complication is still needed to handle
* (or at least work around) local type declarations...
*/
JavaType type = getter.getType(beanDesc.bindingsForBeanType());
/* First: does the Method specify the deserializer to use?
* If so, let's use it.
*/
BeanProperty.Std property = new BeanProperty.Std(name, type, beanDesc.getClassAnnotations(), getter);
// @TODO: create BeanProperty to pass?
JsonDeserializer<Object> propDeser = findDeserializerFromAnnotation(ctxt, getter, property);
type = modifyTypeByAnnotation(ctxt, getter, type, property);
TypeDeserializer typeDeser = type.getTypeHandler();
SettableBeanProperty prop = new SettableBeanProperty.SetterlessProperty(name, type, typeDeser,
beanDesc.getClassAnnotations(), getter);
if (propDeser != null) {
prop = prop.withValueDeserializer(propDeser);
}
return prop;
}
/*
/**********************************************************
/* Helper methods for Bean deserializer, other
/**********************************************************
*/
/**
* Helper method used to skip processing for types that we know
* can not be (i.e. are never consider to be) beans:
* things like primitives, Arrays, Enums, and proxy types.
*<p>
* Note that usually we shouldn't really be getting these sort of
* types anyway; but better safe than sorry.
*/
protected boolean isPotentialBeanType(Class<?> type)
{
String typeStr = ClassUtil.canBeABeanType(type);
if (typeStr != null) {
throw new IllegalArgumentException("Can not deserialize Class "+type.getName()+" (of type "+typeStr+") as a Bean");
}
if (ClassUtil.isProxyType(type)) {
throw new IllegalArgumentException("Can not deserialize Proxy class "+type.getName()+" as a Bean");
}
/* also: can't deserialize some local classes: static are ok; in-method not;
* and with [JACKSON-594], other non-static inner classes are ok
*/
typeStr = ClassUtil.isLocalType(type, true);
if (typeStr != null) {
throw new IllegalArgumentException("Can not deserialize Class "+type.getName()+" (of type "+typeStr+") as a Bean");
}
return true;
}
/**
* Helper method that will check whether given raw type is marked as always ignorable
* (for purpose of ignoring properties with type)
*/
protected boolean isIgnorableType(DeserializationConfig config, BeanDescription beanDesc,
Class<?> type, Map<Class<?>,Boolean> ignoredTypes)
{
Boolean status = ignoredTypes.get(type);
if (status == null) {
BeanDescription desc = config.introspectClassAnnotations(type);
status = config.getAnnotationIntrospector().isIgnorableType(desc.getClassInfo());
// We default to 'false', ie. not ignorable
if (status == null) {
status = Boolean.FALSE;
}
}
return status;
}
}