package com.fasterxml.jackson.databind.deser;
import java.io.Serializable;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicReference;
import com.fasterxml.jackson.annotation.*;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.cfg.ConfigOverride;
import com.fasterxml.jackson.databind.cfg.ConstructorDetector;
import com.fasterxml.jackson.databind.cfg.DeserializerFactoryConfig;
import com.fasterxml.jackson.databind.cfg.HandlerInstantiator;
import com.fasterxml.jackson.databind.deser.impl.CreatorCandidate;
import com.fasterxml.jackson.databind.deser.impl.CreatorCollector;
import com.fasterxml.jackson.databind.deser.impl.JDKValueInstantiators;
import com.fasterxml.jackson.databind.deser.impl.JavaUtilCollectionsDeserializers;
import com.fasterxml.jackson.databind.deser.std.*;
import com.fasterxml.jackson.databind.exc.InvalidDefinitionException;
import com.fasterxml.jackson.databind.ext.OptionalHandlerFactory;
import com.fasterxml.jackson.databind.introspect.*;
import com.fasterxml.jackson.databind.jdk14.JDK14Util;
import com.fasterxml.jackson.databind.jsontype.NamedType;
import com.fasterxml.jackson.databind.jsontype.TypeDeserializer;
import com.fasterxml.jackson.databind.jsontype.TypeResolverBuilder;
import com.fasterxml.jackson.databind.type.*;
import com.fasterxml.jackson.databind.util.*;
@SuppressWarnings("serial")
public abstract class BasicDeserializerFactory
extends DeserializerFactory
implements java.io.Serializable
{
private final static Class<?> CLASS_OBJECT = Object.class;
private final static Class<?> CLASS_STRING = String.class;
private final static Class<?> CLASS_CHAR_SEQUENCE = CharSequence.class;
private final static Class<?> CLASS_ITERABLE = Iterable.class;
private final static Class<?> CLASS_MAP_ENTRY = Map.Entry.class;
private final static Class<?> CLASS_SERIALIZABLE = Serializable.class;
protected final static PropertyName UNWRAPPED_CREATOR_PARAM_NAME = new PropertyName("@JsonUnwrapped");
protected final DeserializerFactoryConfig _factoryConfig;
protected BasicDeserializerFactory(DeserializerFactoryConfig config) {
_factoryConfig = config;
}
public DeserializerFactoryConfig getFactoryConfig() {
return _factoryConfig;
}
protected abstract DeserializerFactory withConfig(DeserializerFactoryConfig config);
@Override
public final DeserializerFactory withAdditionalDeserializers(Deserializers additional) {
return withConfig(_factoryConfig.withAdditionalDeserializers(additional));
}
@Override
public final DeserializerFactory withAdditionalKeyDeserializers(KeyDeserializers additional) {
return withConfig(_factoryConfig.withAdditionalKeyDeserializers(additional));
}
@Override
public final DeserializerFactory withDeserializerModifier(BeanDeserializerModifier modifier) {
return withConfig(_factoryConfig.withDeserializerModifier(modifier));
}
@Override
public final DeserializerFactory withAbstractTypeResolver(AbstractTypeResolver resolver) {
return withConfig(_factoryConfig.withAbstractTypeResolver(resolver));
}
@Override
public final DeserializerFactory withValueInstantiators(ValueInstantiators instantiators) {
return withConfig(_factoryConfig.withValueInstantiators(instantiators));
}
@Override
public JavaType mapAbstractType(DeserializationConfig config, JavaType type) throws JsonMappingException
{
while (true) {
JavaType next = _mapAbstractType2(config, type);
if (next == null) {
return type;
}
Class<?> prevCls = type.getRawClass();
Class<?> nextCls = next.getRawClass();
if ((prevCls == nextCls) || !prevCls.isAssignableFrom(nextCls)) {
throw new IllegalArgumentException("Invalid abstract type resolution from "+type+" to "+next+": latter is not a subtype of former");
}
type = next;
}
}
private JavaType _mapAbstractType2(DeserializationConfig config, JavaType type)
throws JsonMappingException
{
Class<?> currClass = type.getRawClass();
if (_factoryConfig.hasAbstractTypeResolvers()) {
for (AbstractTypeResolver resolver : _factoryConfig.abstractTypeResolvers()) {
JavaType concrete = resolver.findTypeMapping(config, type);
if ((concrete != null) && !concrete.hasRawClass(currClass)) {
return concrete;
}
}
}
return null;
}
@Override
public ValueInstantiator findValueInstantiator(DeserializationContext ctxt,
BeanDescription beanDesc)
throws JsonMappingException
{
final DeserializationConfig config = ctxt.getConfig();
ValueInstantiator instantiator = null;
AnnotatedClass ac = beanDesc.getClassInfo();
Object instDef = ctxt.getAnnotationIntrospector().findValueInstantiator(ac);
if (instDef != null) {
instantiator = _valueInstantiatorInstance(config, ac, instDef);
}
if (instantiator == null) {
instantiator = JDKValueInstantiators.findStdValueInstantiator(config, beanDesc.getBeanClass());
if (instantiator == null) {
instantiator = _constructDefaultValueInstantiator(ctxt, beanDesc);
}
}
if (_factoryConfig.hasValueInstantiators()) {
for (ValueInstantiators insts : _factoryConfig.valueInstantiators()) {
instantiator = insts.findValueInstantiator(config, beanDesc, instantiator);
if (instantiator == null) {
ctxt.reportBadTypeDefinition(beanDesc,
"Broken registered ValueInstantiators (of type %s): returned null ValueInstantiator",
insts.getClass().getName());
}
}
}
if (instantiator != null) {
instantiator = instantiator.createContextual(ctxt, beanDesc);
}
return instantiator;
}
protected ValueInstantiator _constructDefaultValueInstantiator(DeserializationContext ctxt,
BeanDescription beanDesc)
throws JsonMappingException
{
final CreatorCollectionState ccState;
final ConstructorDetector ctorDetector;
{
final DeserializationConfig config = ctxt.getConfig();
final VisibilityChecker<?> vchecker = config.getDefaultVisibilityChecker(beanDesc.getBeanClass(),
beanDesc.getClassInfo());
ctorDetector = config.getConstructorDetector();
final CreatorCollector creators = new CreatorCollector(beanDesc, config);
Map<AnnotatedWithParams,BeanPropertyDefinition[]> creatorDefs = _findCreatorsFromProperties(ctxt,
beanDesc);
ccState = new CreatorCollectionState(ctxt, beanDesc, vchecker,
creators, creatorDefs);
}
_addExplicitFactoryCreators(ctxt, ccState, !ctorDetector.requireCtorAnnotation());
if (beanDesc.getType().isConcrete()) {
if (beanDesc.getType().isRecordType()) {
final List<String> names = new ArrayList<>();
AnnotatedConstructor canonical = JDK14Util.findRecordConstructor(ctxt, beanDesc, names);
if (canonical != null) {
_addRecordConstructor(ctxt, ccState, canonical, names);
return ccState.creators.constructValueInstantiator(ctxt);
}
}
final boolean isNonStaticInnerClass = beanDesc.isNonStaticInnerClass();
if (isNonStaticInnerClass) {
;
} else {
final boolean findImplicit = ctorDetector.shouldIntrospectorImplicitConstructors(beanDesc.getBeanClass());
_addExplicitConstructorCreators(ctxt, ccState, findImplicit);
if (ccState.hasImplicitConstructorCandidates()
&& !ccState.hasExplicitConstructors()) {
_addImplicitConstructorCreators(ctxt, ccState, ccState.implicitConstructorCandidates());
}
}
}
if (ccState.hasImplicitFactoryCandidates()
&& !ccState.hasExplicitFactories() && !ccState.hasExplicitConstructors()) {
_addImplicitFactoryCreators(ctxt, ccState, ccState.implicitFactoryCandidates());
}
return ccState.creators.constructValueInstantiator(ctxt);
}
protected Map<AnnotatedWithParams,BeanPropertyDefinition[]> _findCreatorsFromProperties(DeserializationContext ctxt,
BeanDescription beanDesc) throws JsonMappingException
{
Map<AnnotatedWithParams,BeanPropertyDefinition[]> result = Collections.emptyMap();
for (BeanPropertyDefinition propDef : beanDesc.findProperties()) {
Iterator<AnnotatedParameter> it = propDef.getConstructorParameters();
while (it.hasNext()) {
AnnotatedParameter param = it.next();
AnnotatedWithParams owner = param.getOwner();
BeanPropertyDefinition[] defs = result.get(owner);
final int index = param.getIndex();
if (defs == null) {
if (result.isEmpty()) {
result = new LinkedHashMap<AnnotatedWithParams,BeanPropertyDefinition[]>();
}
defs = new BeanPropertyDefinition[owner.getParameterCount()];
result.put(owner, defs);
} else {
if (defs[index] != null) {
ctxt.reportBadTypeDefinition(beanDesc,
"Conflict: parameter #%d of %s bound to more than one property; %s vs %s",
index, owner, defs[index], propDef);
}
}
defs[index] = propDef;
}
}
return result;
}
public ValueInstantiator _valueInstantiatorInstance(DeserializationConfig config,
Annotated annotated, Object instDef)
throws JsonMappingException
{
if (instDef == null) {
return null;
}
ValueInstantiator inst;
if (instDef instanceof ValueInstantiator) {
return (ValueInstantiator) instDef;
}
if (!(instDef instanceof Class)) {
throw new IllegalStateException("AnnotationIntrospector returned key deserializer definition of type "
+instDef.getClass().getName()
+"; expected type KeyDeserializer or Class<KeyDeserializer> instead");
}
Class<?> instClass = (Class<?>)instDef;
if (ClassUtil.isBogusClass(instClass)) {
return null;
}
if (!ValueInstantiator.class.isAssignableFrom(instClass)) {
throw new IllegalStateException("AnnotationIntrospector returned Class "+instClass.getName()
+"; expected Class<ValueInstantiator>");
}
HandlerInstantiator hi = config.getHandlerInstantiator();
if (hi != null) {
inst = hi.valueInstantiatorInstance(config, annotated, instClass);
if (inst != null) {
return inst;
}
}
return (ValueInstantiator) ClassUtil.createInstance(instClass,
config.canOverrideAccessModifiers());
}
protected void _addRecordConstructor(DeserializationContext ctxt, CreatorCollectionState ccState,
AnnotatedConstructor canonical, List<String> implicitNames)
throws JsonMappingException
{
final int argCount = canonical.getParameterCount();
final AnnotationIntrospector intr = ctxt.getAnnotationIntrospector();
final SettableBeanProperty[] properties = new SettableBeanProperty[argCount];
for (int i = 0; i < argCount; ++i) {
final AnnotatedParameter param = canonical.getParameter(i);
JacksonInject.Value injectable = intr.findInjectableValue(param);
PropertyName name = intr.findNameForDeserialization(param);
if (name == null || name.isEmpty()) {
name = PropertyName.construct(implicitNames.get(i));
}
properties[i] = constructCreatorProperty(ctxt, ccState.beanDesc, name, i, param, injectable);
}
ccState.creators.addPropertyCreator(canonical, false, properties);
}
protected void _addExplicitConstructorCreators(DeserializationContext ctxt,
CreatorCollectionState ccState, boolean findImplicit)
throws JsonMappingException
{
final BeanDescription beanDesc = ccState.beanDesc;
final CreatorCollector creators = ccState.creators;
final AnnotationIntrospector intr = ccState.annotationIntrospector();
final VisibilityChecker<?> vchecker = ccState.vchecker;
final Map<AnnotatedWithParams, BeanPropertyDefinition[]> creatorParams = ccState.creatorParams;
AnnotatedConstructor defaultCtor = beanDesc.findDefaultConstructor();
if (defaultCtor != null) {
if (!creators.hasDefaultCreator() || _hasCreatorAnnotation(ctxt, defaultCtor)) {
creators.setDefaultCreator(defaultCtor);
}
}
for (AnnotatedConstructor ctor : beanDesc.getConstructors()) {
JsonCreator.Mode creatorMode = intr.findCreatorAnnotation(ctxt.getConfig(), ctor);
if (JsonCreator.Mode.DISABLED == creatorMode) {
continue;
}
if (creatorMode == null) {
if (findImplicit && vchecker.isCreatorVisible(ctor)) {
ccState.addImplicitConstructorCandidate(CreatorCandidate.construct(intr,
ctor, creatorParams.get(ctor)));
}
continue;
}
switch (creatorMode) {
case DELEGATING:
_addExplicitDelegatingCreator(ctxt, beanDesc, creators,
CreatorCandidate.construct(intr, ctor, null));
break;
case PROPERTIES:
_addExplicitPropertyCreator(ctxt, beanDesc, creators,
CreatorCandidate.construct(intr, ctor, creatorParams.get(ctor)));
break;
default:
_addExplicitAnyCreator(ctxt, beanDesc, creators,
CreatorCandidate.construct(intr, ctor, creatorParams.get(ctor)),
ctxt.getConfig().getConstructorDetector());
break;
}
ccState.increaseExplicitConstructorCount();
}
}
protected void _addImplicitConstructorCreators(DeserializationContext ctxt,
CreatorCollectionState ccState, List<CreatorCandidate> ctorCandidates)
throws JsonMappingException
{
final DeserializationConfig config = ctxt.getConfig();
final BeanDescription beanDesc = ccState.beanDesc;
final CreatorCollector creators = ccState.creators;
final AnnotationIntrospector intr = ccState.annotationIntrospector();
final VisibilityChecker<?> vchecker = ccState.vchecker;
List<AnnotatedWithParams> implicitCtors = null;
final boolean preferPropsBased = config.getConstructorDetector().singleArgCreatorDefaultsToProperties();
for (CreatorCandidate candidate : ctorCandidates) {
final int argCount = candidate.paramCount();
final AnnotatedWithParams ctor = candidate.creator();
if (argCount == 1) {
final BeanPropertyDefinition propDef = candidate.propertyDef(0);
final boolean useProps = preferPropsBased || _checkIfCreatorPropertyBased(intr, ctor, propDef);
if (useProps) {
SettableBeanProperty[] properties = new SettableBeanProperty[1];
final JacksonInject.Value injection = candidate.injection(0);
PropertyName name = candidate.paramName(0);
if (name == null) {
name = candidate.findImplicitParamName(0);
if ((name == null) && (injection == null)) {
continue;
}
}
properties[0] = constructCreatorProperty(ctxt, beanDesc, name, 0,
candidate.parameter(0), injection);
creators.addPropertyCreator(ctor, false, properties);
} else {
_handleSingleArgumentCreator(creators,
ctor, false,
vchecker.isCreatorVisible(ctor));
if (propDef != null) {
((POJOPropertyBuilder) propDef).removeConstructors();
}
}
continue;
}
int nonAnnotatedParamIndex = -1;
SettableBeanProperty[] properties = new SettableBeanProperty[argCount];
int explicitNameCount = 0;
int implicitWithCreatorCount = 0;
int injectCount = 0;
for (int i = 0; i < argCount; ++i) {
final AnnotatedParameter param = ctor.getParameter(i);
BeanPropertyDefinition propDef = candidate.propertyDef(i);
JacksonInject.Value injectable = intr.findInjectableValue(param);
final PropertyName name = (propDef == null) ? null : propDef.getFullName();
if (propDef != null && propDef.isExplicitlyNamed()) {
++explicitNameCount;
properties[i] = constructCreatorProperty(ctxt, beanDesc, name, i, param, injectable);
continue;
}
if (injectable != null) {
++injectCount;
properties[i] = constructCreatorProperty(ctxt, beanDesc, name, i, param, injectable);
continue;
}
NameTransformer unwrapper = intr.findUnwrappingNameTransformer(param);
if (unwrapper != null) {
_reportUnwrappedCreatorProperty(ctxt, beanDesc, param);
continue;
}
if (nonAnnotatedParamIndex < 0) {
nonAnnotatedParamIndex = i;
}
}
final int namedCount = explicitNameCount + implicitWithCreatorCount;
if ((explicitNameCount > 0) || (injectCount > 0)) {
if ((namedCount + injectCount) == argCount) {
creators.addPropertyCreator(ctor, false, properties);
continue;
}
if ((explicitNameCount == 0) && ((injectCount + 1) == argCount)) {
creators.addDelegatingCreator(ctor, false, properties, 0);
continue;
}
PropertyName impl = candidate.findImplicitParamName(nonAnnotatedParamIndex);
if (impl == null || impl.isEmpty()) {
ctxt.reportBadTypeDefinition(beanDesc,
"Argument #%d of constructor %s has no property name annotation; must have name when multiple-parameter constructor annotated as Creator",
nonAnnotatedParamIndex, ctor);
}
}
if (!creators.hasDefaultCreator()) {
if (implicitCtors == null) {
implicitCtors = new LinkedList<>();
}
implicitCtors.add(ctor);
}
}
if ((implicitCtors != null) && !creators.hasDelegatingCreator()
&& !creators.hasPropertyBasedCreator()) {
_checkImplicitlyNamedConstructors(ctxt, beanDesc, vchecker, intr,
creators, implicitCtors);
}
}
protected void _addExplicitFactoryCreators(DeserializationContext ctxt,
CreatorCollectionState ccState, boolean findImplicit)
throws JsonMappingException
{
final BeanDescription beanDesc = ccState.beanDesc;
final CreatorCollector creators = ccState.creators;
final AnnotationIntrospector intr = ccState.annotationIntrospector();
final VisibilityChecker<?> vchecker = ccState.vchecker;
final Map<AnnotatedWithParams, BeanPropertyDefinition[]> creatorParams = ccState.creatorParams;
for (AnnotatedMethod factory : beanDesc.getFactoryMethods()) {
JsonCreator.Mode creatorMode = intr.findCreatorAnnotation(ctxt.getConfig(), factory);
final int argCount = factory.getParameterCount();
if (creatorMode == null) {
if (findImplicit && (argCount == 1) && vchecker.isCreatorVisible(factory)) {
ccState.addImplicitFactoryCandidate(CreatorCandidate.construct(intr, factory, null));
}
continue;
}
if (creatorMode == JsonCreator.Mode.DISABLED) {
continue;
}
if (argCount == 0) {
creators.setDefaultCreator(factory);
continue;
}
switch (creatorMode) {
case DELEGATING:
_addExplicitDelegatingCreator(ctxt, beanDesc, creators,
CreatorCandidate.construct(intr, factory, null));
break;
case PROPERTIES:
_addExplicitPropertyCreator(ctxt, beanDesc, creators,
CreatorCandidate.construct(intr, factory, creatorParams.get(factory)));
break;
case DEFAULT:
default:
_addExplicitAnyCreator(ctxt, beanDesc, creators,
CreatorCandidate.construct(intr, factory, creatorParams.get(factory)),
ConstructorDetector.DEFAULT);
break;
}
ccState.increaseExplicitFactoryCount();
}
}
protected void _addImplicitFactoryCreators(DeserializationContext ctxt,
CreatorCollectionState ccState, List<CreatorCandidate> factoryCandidates)
throws JsonMappingException
{
final BeanDescription beanDesc = ccState.beanDesc;
final CreatorCollector creators = ccState.creators;
final AnnotationIntrospector intr = ccState.annotationIntrospector();
final VisibilityChecker<?> vchecker = ccState.vchecker;
final Map<AnnotatedWithParams, BeanPropertyDefinition[]> creatorParams = ccState.creatorParams;
for (CreatorCandidate candidate : factoryCandidates) {
final int argCount = candidate.paramCount();
AnnotatedWithParams factory = candidate.creator();
final BeanPropertyDefinition[] propDefs = creatorParams.get(factory);
if (argCount != 1) {
continue;
}
BeanPropertyDefinition argDef = candidate.propertyDef(0);
boolean useProps = _checkIfCreatorPropertyBased(intr, factory, argDef);
if (!useProps) {
_handleSingleArgumentCreator(creators,
factory, false, vchecker.isCreatorVisible(factory));
if (argDef != null) {
((POJOPropertyBuilder) argDef).removeConstructors();
}
continue;
}
AnnotatedParameter nonAnnotatedParam = null;
SettableBeanProperty[] properties = new SettableBeanProperty[argCount];
int implicitNameCount = 0;
int explicitNameCount = 0;
int injectCount = 0;
for (int i = 0; i < argCount; ++i) {
final AnnotatedParameter param = factory.getParameter(i);
BeanPropertyDefinition propDef = (propDefs == null) ? null : propDefs[i];
JacksonInject.Value injectable = intr.findInjectableValue(param);
final PropertyName name = (propDef == null) ? null : propDef.getFullName();
if (propDef != null && propDef.isExplicitlyNamed()) {
++explicitNameCount;
properties[i] = constructCreatorProperty(ctxt, beanDesc, name, i, param, injectable);
continue;
}
if (injectable != null) {
++injectCount;
properties[i] = constructCreatorProperty(ctxt, beanDesc, name, i, param, injectable);
continue;
}
NameTransformer unwrapper = intr.findUnwrappingNameTransformer(param);
if (unwrapper != null) {
_reportUnwrappedCreatorProperty(ctxt, beanDesc, param);
continue;
}
if (nonAnnotatedParam == null) {
nonAnnotatedParam = param;
}
}
final int namedCount = explicitNameCount + implicitNameCount;
if (explicitNameCount > 0 || injectCount > 0) {
if ((namedCount + injectCount) == argCount) {
creators.addPropertyCreator(factory, false, properties);
} else if ((explicitNameCount == 0) && ((injectCount + 1) == argCount)) {
creators.addDelegatingCreator(factory, false, properties, 0);
} else {
ctxt.reportBadTypeDefinition(beanDesc,
"Argument #%d of factory method %s has no property name annotation; must have name when multiple-parameter constructor annotated as Creator",
nonAnnotatedParam.getIndex(), factory);
}
}
}
}
protected void _addExplicitDelegatingCreator(DeserializationContext ctxt,
BeanDescription beanDesc, CreatorCollector creators,
CreatorCandidate candidate)
throws JsonMappingException
{
int ix = -1;
final int argCount = candidate.paramCount();
SettableBeanProperty[] properties = new SettableBeanProperty[argCount];
for (int i = 0; i < argCount; ++i) {
AnnotatedParameter param = candidate.parameter(i);
JacksonInject.Value injectId = candidate.injection(i);
if (injectId != null) {
properties[i] = constructCreatorProperty(ctxt, beanDesc, null, i, param, injectId);
continue;
}
if (ix < 0) {
ix = i;
continue;
}
ctxt.reportBadTypeDefinition(beanDesc,
"More than one argument (#%d and #%d) left as delegating for Creator %s: only one allowed",
ix, i, candidate);
}
if (ix < 0) {
ctxt.reportBadTypeDefinition(beanDesc,
"No argument left as delegating for Creator %s: exactly one required", candidate);
}
if (argCount == 1) {
_handleSingleArgumentCreator(creators, candidate.creator(), true, true);
BeanPropertyDefinition paramDef = candidate.propertyDef(0);
if (paramDef != null) {
((POJOPropertyBuilder) paramDef).removeConstructors();
}
return;
}
creators.addDelegatingCreator(candidate.creator(), true, properties, ix);
}
protected void _addExplicitPropertyCreator(DeserializationContext ctxt,
BeanDescription beanDesc, CreatorCollector creators,
CreatorCandidate candidate)
throws JsonMappingException
{
final int paramCount = candidate.paramCount();
SettableBeanProperty[] properties = new SettableBeanProperty[paramCount];
for (int i = 0; i < paramCount; ++i) {
JacksonInject.Value injectId = candidate.injection(i);
AnnotatedParameter param = candidate.parameter(i);
PropertyName name = candidate.paramName(i);
if (name == null) {
NameTransformer unwrapper = ctxt.getAnnotationIntrospector().findUnwrappingNameTransformer(param);
if (unwrapper != null) {
_reportUnwrappedCreatorProperty(ctxt, beanDesc, param);
}
name = candidate.findImplicitParamName(i);
_validateNamedPropertyParameter(ctxt, beanDesc, candidate, i,
name, injectId);
}
properties[i] = constructCreatorProperty(ctxt, beanDesc, name, i, param, injectId);
}
creators.addPropertyCreator(candidate.creator(), true, properties);
}
@Deprecated
protected void _addExplicitAnyCreator(DeserializationContext ctxt,
BeanDescription beanDesc, CreatorCollector creators,
CreatorCandidate candidate)
throws JsonMappingException
{
_addExplicitAnyCreator(ctxt, beanDesc, creators, candidate,
ctxt.getConfig().getConstructorDetector());
}
protected void _addExplicitAnyCreator(DeserializationContext ctxt,
BeanDescription beanDesc, CreatorCollector creators,
CreatorCandidate candidate, ConstructorDetector ctorDetector)
throws JsonMappingException
{
if (1 != candidate.paramCount()) {
if (!ctorDetector.singleArgCreatorDefaultsToProperties()) {
int oneNotInjected = candidate.findOnlyParamWithoutInjection();
if (oneNotInjected >= 0) {
if (ctorDetector.singleArgCreatorDefaultsToDelegating()
|| candidate.paramName(oneNotInjected) == null) {
_addExplicitDelegatingCreator(ctxt, beanDesc, creators, candidate);
return;
}
}
}
_addExplicitPropertyCreator(ctxt, beanDesc, creators, candidate);
return;
}
final AnnotatedParameter param = candidate.parameter(0);
final JacksonInject.Value injectId = candidate.injection(0);
PropertyName paramName = null;
boolean useProps;
switch (ctorDetector.singleArgMode()) {
case DELEGATING:
useProps = false;
break;
case PROPERTIES:
useProps = true;
paramName = candidate.paramName(0);
if (paramName == null) {
_validateNamedPropertyParameter(ctxt, beanDesc, candidate, 0,
paramName, injectId);
}
break;
case REQUIRE_MODE:
ctxt.reportBadTypeDefinition(beanDesc,
"Single-argument constructor (%s) is annotated but no 'mode' defined; `CreatorDetector`"
+ "configured with `SingleArgConstructor.REQUIRE_MODE`",
candidate.creator());
return;
case HEURISTIC:
default:
{
final BeanPropertyDefinition paramDef = candidate.propertyDef(0);
paramName = candidate.explicitParamName(0);
useProps = (paramName != null) || (injectId != null);
if (!useProps && (paramDef != null)) {
paramName = candidate.paramName(0);
useProps = (paramName != null) && paramDef.couldSerialize();
}
}
}
if (useProps) {
SettableBeanProperty[] properties = new SettableBeanProperty[] {
constructCreatorProperty(ctxt, beanDesc, paramName, 0, param, injectId)
};
creators.addPropertyCreator(candidate.creator(), true, properties);
return;
}
_handleSingleArgumentCreator(creators, candidate.creator(), true, true);
final BeanPropertyDefinition paramDef = candidate.propertyDef(0);
if (paramDef != null) {
((POJOPropertyBuilder) paramDef).removeConstructors();
}
}
private boolean _checkIfCreatorPropertyBased(AnnotationIntrospector intr,
AnnotatedWithParams creator, BeanPropertyDefinition propDef)
{
if (((propDef != null) && propDef.isExplicitlyNamed())
|| (intr.findInjectableValue(creator.getParameter(0)) != null)) {
return true;
}
if (propDef != null) {
String implName = propDef.getName();
if (implName != null && !implName.isEmpty()) {
if (propDef.couldSerialize()) {
return true;
}
}
}
return false;
}
private void _checkImplicitlyNamedConstructors(DeserializationContext ctxt,
BeanDescription beanDesc, VisibilityChecker<?> vchecker,
AnnotationIntrospector intr, CreatorCollector creators,
List<AnnotatedWithParams> implicitCtors) throws JsonMappingException
{
AnnotatedWithParams found = null;
SettableBeanProperty[] foundProps = null;
main_loop:
for (AnnotatedWithParams ctor : implicitCtors) {
if (!vchecker.isCreatorVisible(ctor)) {
continue;
}
final int argCount = ctor.getParameterCount();
SettableBeanProperty[] properties = new SettableBeanProperty[argCount];
for (int i = 0; i < argCount; ++i) {
final AnnotatedParameter param = ctor.getParameter(i);
final PropertyName name = _findParamName(param, intr);
if (name == null || name.isEmpty()) {
continue main_loop;
}
properties[i] = constructCreatorProperty(ctxt, beanDesc, name, param.getIndex(),
param, null);
}
if (found != null) {
found = null;
break;
}
found = ctor;
foundProps = properties;
}
if (found != null) {
creators.addPropertyCreator(found, false, foundProps);
BasicBeanDescription bbd = (BasicBeanDescription) beanDesc;
for (SettableBeanProperty prop : foundProps) {
PropertyName pn = prop.getFullName();
if (!bbd.hasProperty(pn)) {
BeanPropertyDefinition newDef = SimpleBeanPropertyDefinition.construct(
ctxt.getConfig(), prop.getMember(), pn);
bbd.addProperty(newDef);
}
}
}
}
protected boolean _handleSingleArgumentCreator(CreatorCollector creators,
AnnotatedWithParams ctor, boolean isCreator, boolean isVisible)
{
Class<?> type = ctor.getRawParameterType(0);
if (type == String.class || type == CLASS_CHAR_SEQUENCE) {
if (isCreator || isVisible) {
creators.addStringCreator(ctor, isCreator);
}
return true;
}
if (type == int.class || type == Integer.class) {
if (isCreator || isVisible) {
creators.addIntCreator(ctor, isCreator);
}
return true;
}
if (type == long.class || type == Long.class) {
if (isCreator || isVisible) {
creators.addLongCreator(ctor, isCreator);
}
return true;
}
if (type == double.class || type == Double.class) {
if (isCreator || isVisible) {
creators.addDoubleCreator(ctor, isCreator);
}
return true;
}
if (type == boolean.class || type == Boolean.class) {
if (isCreator || isVisible) {
creators.addBooleanCreator(ctor, isCreator);
}
return true;
}
if (type == BigInteger.class) {
if (isCreator || isVisible) {
creators.addBigIntegerCreator(ctor, isCreator);
}
}
if (type == BigDecimal.class) {
if (isCreator || isVisible) {
creators.addBigDecimalCreator(ctor, isCreator);
}
}
if (isCreator) {
creators.addDelegatingCreator(ctor, isCreator, null, 0);
return true;
}
return false;
}
protected void _validateNamedPropertyParameter(DeserializationContext ctxt,
BeanDescription beanDesc,
CreatorCandidate candidate, int paramIndex,
PropertyName name, JacksonInject.Value injectId)
throws JsonMappingException
{
if ((name == null) && (injectId == null)) {
ctxt.reportBadTypeDefinition(beanDesc,
"Argument #%d of constructor %s has no property name (and is not Injectable): can not use as property-based Creator",
paramIndex, candidate);
}
}
protected void _reportUnwrappedCreatorProperty(DeserializationContext ctxt,
BeanDescription beanDesc, AnnotatedParameter param)
throws JsonMappingException
{
ctxt.reportBadTypeDefinition(beanDesc,
"Cannot define Creator parameter %d as `@JsonUnwrapped`: combination not yet supported",
param.getIndex());
}
protected SettableBeanProperty constructCreatorProperty(DeserializationContext ctxt,
BeanDescription beanDesc, PropertyName name, int index,
AnnotatedParameter param,
JacksonInject.Value injectable)
throws JsonMappingException
{
final DeserializationConfig config = ctxt.getConfig();
final AnnotationIntrospector intr = ctxt.getAnnotationIntrospector();
PropertyMetadata metadata;
{
if (intr == null) {
metadata = PropertyMetadata.STD_REQUIRED_OR_OPTIONAL;
} else {
Boolean b = intr.hasRequiredMarker(param);
String desc = intr.findPropertyDescription(param);
Integer idx = intr.findPropertyIndex(param);
String def = intr.findPropertyDefaultValue(param);
metadata = PropertyMetadata.construct(b, desc, idx, def);
}
}
JavaType type = resolveMemberAndTypeAnnotations(ctxt, param, param.getType());
BeanProperty.Std property = new BeanProperty.Std(name, type,
intr.findWrapperName(param), param, metadata);
TypeDeserializer typeDeser = (TypeDeserializer) type.getTypeHandler();
if (typeDeser == null) {
typeDeser = findTypeDeserializer(config, type);
}
metadata = _getSetterInfo(ctxt, property, metadata);
SettableBeanProperty prop = CreatorProperty.construct(name, type, property.getWrapperName(),
typeDeser, beanDesc.getClassAnnotations(), param, index, injectable,
metadata);
JsonDeserializer<?> deser = findDeserializerFromAnnotation(ctxt, param);
if (deser == null) {
deser = type.getValueHandler();
}
if (deser != null) {
deser = ctxt.handlePrimaryContextualization(deser, prop, type);
prop = prop.withValueDeserializer(deser);
}
return prop;
}
private PropertyName _findParamName(AnnotatedParameter param, AnnotationIntrospector intr)
{
if (intr != null) {
PropertyName name = intr.findNameForDeserialization(param);
if (name != null) {
if (!name.isEmpty()) {
return name;
}
}
String str = intr.findImplicitPropertyName(param);
if (str != null && !str.isEmpty()) {
return PropertyName.construct(str);
}
}
return null;
}
protected PropertyMetadata _getSetterInfo(DeserializationContext ctxt,
BeanProperty prop, PropertyMetadata metadata)
{
final AnnotationIntrospector intr = ctxt.getAnnotationIntrospector();
final DeserializationConfig config = ctxt.getConfig();
boolean needMerge = true;
Nulls valueNulls = null;
Nulls contentNulls = null;
AnnotatedMember prim = prop.getMember();
if (prim != null) {
if (intr != null) {
JsonSetter.Value setterInfo = intr.findSetterInfo(prim);
if (setterInfo != null) {
valueNulls = setterInfo.nonDefaultValueNulls();
contentNulls = setterInfo.nonDefaultContentNulls();
}
}
if (needMerge || (valueNulls == null) || (contentNulls == null)) {
ConfigOverride co = config.getConfigOverride(prop.getType().getRawClass());
JsonSetter.Value setterInfo = co.getSetterInfo();
if (setterInfo != null) {
if (valueNulls == null) {
valueNulls = setterInfo.nonDefaultValueNulls();
}
if (contentNulls == null) {
contentNulls = setterInfo.nonDefaultContentNulls();
}
}
}
}
if (needMerge || (valueNulls == null) || (contentNulls == null)) {
JsonSetter.Value setterInfo = config.getDefaultSetterInfo();
if (valueNulls == null) {
valueNulls = setterInfo.nonDefaultValueNulls();
}
if (contentNulls == null) {
contentNulls = setterInfo.nonDefaultContentNulls();
}
}
if ((valueNulls != null) || (contentNulls != null)) {
metadata = metadata.withNulls(valueNulls, contentNulls);
}
return metadata;
}
@Override
public JsonDeserializer<?> createArrayDeserializer(DeserializationContext ctxt,
ArrayType type, final BeanDescription beanDesc)
throws JsonMappingException
{
final DeserializationConfig config = ctxt.getConfig();
JavaType elemType = type.getContentType();
JsonDeserializer<Object> contentDeser = elemType.getValueHandler();
TypeDeserializer elemTypeDeser = elemType.getTypeHandler();
if (elemTypeDeser == null) {
elemTypeDeser = findTypeDeserializer(config, elemType);
}
JsonDeserializer<?> deser = _findCustomArrayDeserializer(type,
config, beanDesc, elemTypeDeser, contentDeser);
if (deser == null) {
if (contentDeser == null) {
Class<?> raw = elemType.getRawClass();
if (elemType.isPrimitive()) {
return PrimitiveArrayDeserializers.forType(raw);
}
if (raw == String.class) {
return StringArrayDeserializer.instance;
}
}
deser = new ObjectArrayDeserializer(type, contentDeser, elemTypeDeser);
}
if (_factoryConfig.hasDeserializerModifiers()) {
for (BeanDeserializerModifier mod : _factoryConfig.deserializerModifiers()) {
deser = mod.modifyArrayDeserializer(config, type, beanDesc, deser);
}
}
return deser;
}
@Override
public JsonDeserializer<?> createCollectionDeserializer(DeserializationContext ctxt,
CollectionType type, BeanDescription beanDesc)
throws JsonMappingException
{
JavaType contentType = type.getContentType();
JsonDeserializer<Object> contentDeser = contentType.getValueHandler();
final DeserializationConfig config = ctxt.getConfig();
TypeDeserializer contentTypeDeser = contentType.getTypeHandler();
if (contentTypeDeser == null) {
contentTypeDeser = findTypeDeserializer(config, contentType);
}
JsonDeserializer<?> deser = _findCustomCollectionDeserializer(type,
config, beanDesc, contentTypeDeser, contentDeser);
if (deser == null) {
Class<?> collectionClass = type.getRawClass();
if (contentDeser == null) {
if (EnumSet.class.isAssignableFrom(collectionClass)) {
deser = new EnumSetDeserializer(contentType, null);
}
}
}
if (deser == null) {
if (type.isInterface() || type.isAbstract()) {
CollectionType implType = _mapAbstractCollectionType(type, config);
if (implType == null) {
if (type.getTypeHandler() == null) {
throw new IllegalArgumentException("Cannot find a deserializer for non-concrete Collection type "+type);
}
deser = AbstractDeserializer.constructForNonPOJO(beanDesc);
} else {
type = implType;
beanDesc = config.introspectForCreation(type);
}
}
if (deser == null) {
ValueInstantiator inst = findValueInstantiator(ctxt, beanDesc);
if (!inst.canCreateUsingDefault()) {
if (type.hasRawClass(ArrayBlockingQueue.class)) {
return new ArrayBlockingQueueDeserializer(type, contentDeser, contentTypeDeser, inst);
}
deser = JavaUtilCollectionsDeserializers.findForCollection(ctxt, type);
if (deser != null) {
return deser;
}
}
if (contentType.hasRawClass(String.class)) {
deser = new StringCollectionDeserializer(type, contentDeser, inst);
} else {
deser = new CollectionDeserializer(type, contentDeser, contentTypeDeser, inst);
}
}
}
if (_factoryConfig.hasDeserializerModifiers()) {
for (BeanDeserializerModifier mod : _factoryConfig.deserializerModifiers()) {
deser = mod.modifyCollectionDeserializer(config, type, beanDesc, deser);
}
}
return deser;
}
protected CollectionType _mapAbstractCollectionType(JavaType type, DeserializationConfig config)
{
final Class<?> collectionClass = ContainerDefaultMappings.findCollectionFallback(type);
if (collectionClass != null) {
return (CollectionType) config.getTypeFactory()
.constructSpecializedType(type, collectionClass, true);
}
return null;
}
@Override
public JsonDeserializer<?> createCollectionLikeDeserializer(DeserializationContext ctxt,
CollectionLikeType type, final BeanDescription beanDesc)
throws JsonMappingException
{
JavaType contentType = type.getContentType();
JsonDeserializer<Object> contentDeser = contentType.getValueHandler();
final DeserializationConfig config = ctxt.getConfig();
TypeDeserializer contentTypeDeser = contentType.getTypeHandler();
if (contentTypeDeser == null) {
contentTypeDeser = findTypeDeserializer(config, contentType);
}
JsonDeserializer<?> deser = _findCustomCollectionLikeDeserializer(type, config, beanDesc,
contentTypeDeser, contentDeser);
if (deser != null) {
if (_factoryConfig.hasDeserializerModifiers()) {
for (BeanDeserializerModifier mod : _factoryConfig.deserializerModifiers()) {
deser = mod.modifyCollectionLikeDeserializer(config, type, beanDesc, deser);
}
}
}
return deser;
}
@Override
public JsonDeserializer<?> createMapDeserializer(DeserializationContext ctxt,
MapType type, BeanDescription beanDesc)
throws JsonMappingException
{
final DeserializationConfig config = ctxt.getConfig();
JavaType keyType = type.getKeyType();
JavaType contentType = type.getContentType();
@SuppressWarnings("unchecked")
JsonDeserializer<Object> contentDeser = (JsonDeserializer<Object>) contentType.getValueHandler();
KeyDeserializer keyDes = (KeyDeserializer) keyType.getValueHandler();
TypeDeserializer contentTypeDeser = contentType.getTypeHandler();
if (contentTypeDeser == null) {
contentTypeDeser = findTypeDeserializer(config, contentType);
}
JsonDeserializer<?> deser = _findCustomMapDeserializer(type, config, beanDesc,
keyDes, contentTypeDeser, contentDeser);
if (deser == null) {
Class<?> mapClass = type.getRawClass();
if (EnumMap.class.isAssignableFrom(mapClass)) {
ValueInstantiator inst;
if (mapClass == EnumMap.class) {
inst = null;
} else {
inst = findValueInstantiator(ctxt, beanDesc);
}
if (!keyType.isEnumImplType()) {
throw new IllegalArgumentException("Cannot construct EnumMap; generic (key) type not available");
}
deser = new EnumMapDeserializer(type, inst, null,
contentDeser, contentTypeDeser, null);
}
if (deser == null) {
if (type.isInterface() || type.isAbstract()) {
MapType fallback = _mapAbstractMapType(type, config);
if (fallback != null) {
type = (MapType) fallback;
mapClass = type.getRawClass();
beanDesc = config.introspectForCreation(type);
} else {
if (type.getTypeHandler() == null) {
throw new IllegalArgumentException("Cannot find a deserializer for non-concrete Map type "+type);
}
deser = AbstractDeserializer.constructForNonPOJO(beanDesc);
}
} else {
deser = JavaUtilCollectionsDeserializers.findForMap(ctxt, type);
if (deser != null) {
return deser;
}
}
if (deser == null) {
ValueInstantiator inst = findValueInstantiator(ctxt, beanDesc);
MapDeserializer md = new MapDeserializer(type, inst, keyDes, contentDeser, contentTypeDeser);
JsonIgnoreProperties.Value ignorals = config.getDefaultPropertyIgnorals(Map.class,
beanDesc.getClassInfo());
Set<String> ignored = (ignorals == null) ? null
: ignorals.findIgnoredForDeserialization();
md.setIgnorableProperties(ignored);
JsonIncludeProperties.Value inclusions = config.getDefaultPropertyInclusions(Map.class,
beanDesc.getClassInfo());
Set<String> included = inclusions == null ? null : inclusions.getIncluded();
md.setIncludableProperties(included);
deser = md;
}
}
}
if (_factoryConfig.hasDeserializerModifiers()) {
for (BeanDeserializerModifier mod : _factoryConfig.deserializerModifiers()) {
deser = mod.modifyMapDeserializer(config, type, beanDesc, deser);
}
}
return deser;
}
protected MapType _mapAbstractMapType(JavaType type, DeserializationConfig config)
{
final Class<?> mapClass = ContainerDefaultMappings.findMapFallback(type);
if (mapClass != null) {
return (MapType) config.getTypeFactory()
.constructSpecializedType(type, mapClass, true);
}
return null;
}
@Override
public JsonDeserializer<?> createMapLikeDeserializer(DeserializationContext ctxt,
MapLikeType type, final BeanDescription beanDesc)
throws JsonMappingException
{
JavaType keyType = type.getKeyType();
JavaType contentType = type.getContentType();
final DeserializationConfig config = ctxt.getConfig();
@SuppressWarnings("unchecked")
JsonDeserializer<Object> contentDeser = (JsonDeserializer<Object>) contentType.getValueHandler();
KeyDeserializer keyDes = (KeyDeserializer) keyType.getValueHandler();
TypeDeserializer contentTypeDeser = contentType.getTypeHandler();
if (contentTypeDeser == null) {
contentTypeDeser = findTypeDeserializer(config, contentType);
}
JsonDeserializer<?> deser = _findCustomMapLikeDeserializer(type, config,
beanDesc, keyDes, contentTypeDeser, contentDeser);
if (deser != null) {
if (_factoryConfig.hasDeserializerModifiers()) {
for (BeanDeserializerModifier mod : _factoryConfig.deserializerModifiers()) {
deser = mod.modifyMapLikeDeserializer(config, type, beanDesc, deser);
}
}
}
return deser;
}
@Override
public JsonDeserializer<?> createEnumDeserializer(DeserializationContext ctxt,
JavaType type, BeanDescription beanDesc)
throws JsonMappingException
{
final DeserializationConfig config = ctxt.getConfig();
final Class<?> enumClass = type.getRawClass();
JsonDeserializer<?> deser = _findCustomEnumDeserializer(enumClass, config, beanDesc);
if (deser == null) {
if (enumClass == Enum.class) {
return AbstractDeserializer.constructForNonPOJO(beanDesc);
}
ValueInstantiator valueInstantiator = _constructDefaultValueInstantiator(ctxt, beanDesc);
SettableBeanProperty[] creatorProps = (valueInstantiator == null) ? null
: valueInstantiator.getFromObjectArguments(ctxt.getConfig());
for (AnnotatedMethod factory : beanDesc.getFactoryMethods()) {
if (_hasCreatorAnnotation(ctxt, factory)) {
if (factory.getParameterCount() == 0) {
deser = EnumDeserializer.deserializerForNoArgsCreator(config, enumClass, factory);
break;
}
Class<?> returnType = factory.getRawReturnType();
if (!returnType.isAssignableFrom(enumClass)) {
ctxt.reportBadDefinition(type, String.format(
"Invalid `@JsonCreator` annotated Enum factory method [%s]: needs to return compatible type",
factory.toString()));
}
deser = EnumDeserializer.deserializerForCreator(config, enumClass, factory, valueInstantiator, creatorProps);
break;
}
}
if (deser == null) {
deser = new EnumDeserializer(constructEnumResolver(enumClass,
config, beanDesc.findJsonValueAccessor()),
config.isEnabled(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS));
}
}
if (_factoryConfig.hasDeserializerModifiers()) {
for (BeanDeserializerModifier mod : _factoryConfig.deserializerModifiers()) {
deser = mod.modifyEnumDeserializer(config, type, beanDesc, deser);
}
}
return deser;
}
@Override
public JsonDeserializer<?> createTreeDeserializer(DeserializationConfig config,
JavaType nodeType, BeanDescription beanDesc)
throws JsonMappingException
{
@SuppressWarnings("unchecked")
Class<? extends JsonNode> nodeClass = (Class<? extends JsonNode>) nodeType.getRawClass();
JsonDeserializer<?> custom = _findCustomTreeNodeDeserializer(nodeClass, config,
beanDesc);
if (custom != null) {
return custom;
}
return JsonNodeDeserializer.getDeserializer(nodeClass);
}
@Override
public JsonDeserializer<?> createReferenceDeserializer(DeserializationContext ctxt,
ReferenceType type, BeanDescription beanDesc)
throws JsonMappingException
{
JavaType contentType = type.getContentType();
JsonDeserializer<Object> contentDeser = contentType.getValueHandler();
final DeserializationConfig config = ctxt.getConfig();
TypeDeserializer contentTypeDeser = contentType.getTypeHandler();
if (contentTypeDeser == null) {
contentTypeDeser = findTypeDeserializer(config, contentType);
}
JsonDeserializer<?> deser = _findCustomReferenceDeserializer(type, config, beanDesc,
contentTypeDeser, contentDeser);
if (deser == null) {
if (type.isTypeOrSubTypeOf(AtomicReference.class)) {
Class<?> rawType = type.getRawClass();
ValueInstantiator inst;
if (rawType == AtomicReference.class) {
inst = null;
} else {
inst = findValueInstantiator(ctxt, beanDesc);
}
return new AtomicReferenceDeserializer(type, inst, contentTypeDeser, contentDeser);
}
}
if (deser != null) {
if (_factoryConfig.hasDeserializerModifiers()) {
for (BeanDeserializerModifier mod : _factoryConfig.deserializerModifiers()) {
deser = mod.modifyReferenceDeserializer(config, type, beanDesc, deser);
}
}
}
return deser;
}
@Override
public TypeDeserializer findTypeDeserializer(DeserializationConfig config,
JavaType baseType)
throws JsonMappingException
{
BeanDescription bean = config.introspectClassAnnotations(baseType.getRawClass());
AnnotatedClass ac = bean.getClassInfo();
AnnotationIntrospector ai = config.getAnnotationIntrospector();
TypeResolverBuilder<?> b = ai.findTypeResolver(config, ac, baseType);
Collection<NamedType> subtypes = null;
if (b == null) {
b = config.getDefaultTyper(baseType);
if (b == null) {
return null;
}
} else {
subtypes = config.getSubtypeResolver().collectAndResolveSubtypesByTypeId(config, ac);
}
if ((b.getDefaultImpl() == null) && baseType.isAbstract()) {
JavaType defaultType = mapAbstractType(config, baseType);
if ((defaultType != null) && !defaultType.hasRawClass(baseType.getRawClass())) {
b = b.defaultImpl(defaultType.getRawClass());
}
}
try {
return b.buildTypeDeserializer(config, baseType, subtypes);
} catch (IllegalArgumentException | IllegalStateException e0) {
InvalidDefinitionException e = InvalidDefinitionException.from((JsonParser) null,
ClassUtil.exceptionMessage(e0), baseType);
e.initCause(e0);
throw e;
}
}
protected JsonDeserializer<?> findOptionalStdDeserializer(DeserializationContext ctxt,
JavaType type, BeanDescription beanDesc)
throws JsonMappingException
{
return OptionalHandlerFactory.instance.findDeserializer(type, ctxt.getConfig(), beanDesc);
}
@Override
public KeyDeserializer createKeyDeserializer(DeserializationContext ctxt,
JavaType type)
throws JsonMappingException
{
final DeserializationConfig config = ctxt.getConfig();
BeanDescription beanDesc = null;
KeyDeserializer deser = null;
if (_factoryConfig.hasKeyDeserializers()) {
beanDesc = config.introspectClassAnnotations(type);
for (KeyDeserializers d : _factoryConfig.keyDeserializers()) {
deser = d.findKeyDeserializer(type, config, beanDesc);
if (deser != null) {
break;
}
}
}
if (deser == null) {
if (beanDesc == null) {
beanDesc = config.introspectClassAnnotations(type.getRawClass());
}
deser = findKeyDeserializerFromAnnotation(ctxt, beanDesc.getClassInfo());
if (deser == null) {
if (type.isEnumType()) {
deser = _createEnumKeyDeserializer(ctxt, type);
} else {
deser = StdKeyDeserializers.findStringBasedKeyDeserializer(config, type);
}
}
}
if (deser != null) {
if (_factoryConfig.hasDeserializerModifiers()) {
for (BeanDeserializerModifier mod : _factoryConfig.deserializerModifiers()) {
deser = mod.modifyKeyDeserializer(config, type, deser);
}
}
}
return deser;
}
private KeyDeserializer _createEnumKeyDeserializer(DeserializationContext ctxt,
JavaType type)
throws JsonMappingException
{
final DeserializationConfig config = ctxt.getConfig();
Class<?> enumClass = type.getRawClass();
BeanDescription beanDesc = config.introspect(type);
KeyDeserializer des = findKeyDeserializerFromAnnotation(ctxt, beanDesc.getClassInfo());
if (des != null) {
return des;
} else {
JsonDeserializer<?> custom = _findCustomEnumDeserializer(enumClass, config, beanDesc);
if (custom != null) {
return StdKeyDeserializers.constructDelegatingKeyDeserializer(config, type, custom);
}
JsonDeserializer<?> valueDesForKey = findDeserializerFromAnnotation(ctxt, beanDesc.getClassInfo());
if (valueDesForKey != null) {
return StdKeyDeserializers.constructDelegatingKeyDeserializer(config, type, valueDesForKey);
}
}
EnumResolver enumRes = constructEnumResolver(enumClass, config, beanDesc.findJsonValueAccessor());
for (AnnotatedMethod factory : beanDesc.getFactoryMethods()) {
if (_hasCreatorAnnotation(ctxt, factory)) {
int argCount = factory.getParameterCount();
if (argCount == 1) {
Class<?> returnType = factory.getRawReturnType();
if (returnType.isAssignableFrom(enumClass)) {
if (factory.getRawParameterType(0) != String.class) {
continue;
}
if (config.canOverrideAccessModifiers()) {
ClassUtil.checkAndFixAccess(factory.getMember(),
ctxt.isEnabled(MapperFeature.OVERRIDE_PUBLIC_ACCESS_MODIFIERS));
}
return StdKeyDeserializers.constructEnumKeyDeserializer(enumRes, factory);
}
}
throw new IllegalArgumentException("Unsuitable method ("+factory+") decorated with @JsonCreator (for Enum type "
+enumClass.getName()+")");
}
}
return StdKeyDeserializers.constructEnumKeyDeserializer(enumRes);
}
@Override
public boolean hasExplicitDeserializerFor(DeserializationConfig config,
Class<?> valueType)
{
while (valueType.isArray()) {
valueType = valueType.getComponentType();
}
if (Enum.class.isAssignableFrom(valueType)) {
return true;
}
final String clsName = valueType.getName();
if (clsName.startsWith("java.")) {
if (Collection.class.isAssignableFrom(valueType)) {
return true;
}
if (Map.class.isAssignableFrom(valueType)) {
return true;
}
if (Number.class.isAssignableFrom(valueType)) {
return NumberDeserializers.find(valueType, clsName) != null;
}
if (JdkDeserializers.hasDeserializerFor(valueType)
|| (valueType == CLASS_STRING)
|| (valueType == Boolean.class)
|| (valueType == EnumMap.class)
|| (valueType == AtomicReference.class)
) {
return true;
}
if (DateDeserializers.hasDeserializerFor(valueType)) {
return true;
}
} else if (clsName.startsWith("com.fasterxml.")) {
return JsonNode.class.isAssignableFrom(valueType)
|| (valueType == TokenBuffer.class);
} else {
return OptionalHandlerFactory.instance.hasDeserializerFor(valueType);
}
return false;
}
public TypeDeserializer findPropertyTypeDeserializer(DeserializationConfig config,
JavaType baseType, AnnotatedMember annotated)
throws JsonMappingException
{
AnnotationIntrospector ai = config.getAnnotationIntrospector();
TypeResolverBuilder<?> b = ai.findPropertyTypeResolver(config, annotated, baseType);
if (b == null) {
return findTypeDeserializer(config, baseType);
}
Collection<NamedType> subtypes = config.getSubtypeResolver().collectAndResolveSubtypesByTypeId(
config, annotated, baseType);
try {
return b.buildTypeDeserializer(config, baseType, subtypes);
} catch (IllegalArgumentException | IllegalStateException e0) {
InvalidDefinitionException e = InvalidDefinitionException.from((JsonParser) null,
ClassUtil.exceptionMessage(e0), baseType);
e.initCause(e0);
throw e;
}
}
public TypeDeserializer findPropertyContentTypeDeserializer(DeserializationConfig config,
JavaType containerType, AnnotatedMember propertyEntity)
throws JsonMappingException
{
AnnotationIntrospector ai = config.getAnnotationIntrospector();
TypeResolverBuilder<?> b = ai.findPropertyContentTypeResolver(config, propertyEntity, containerType);
JavaType contentType = containerType.getContentType();
if (b == null) {
return findTypeDeserializer(config, contentType);
}
Collection<NamedType> subtypes = config.getSubtypeResolver().collectAndResolveSubtypesByTypeId(
config, propertyEntity, contentType);
return b.buildTypeDeserializer(config, contentType, subtypes);
}
public JsonDeserializer<?> findDefaultDeserializer(DeserializationContext ctxt,
JavaType type, BeanDescription beanDesc)
throws JsonMappingException
{
Class<?> rawType = type.getRawClass();
if ((rawType == CLASS_OBJECT) || (rawType == CLASS_SERIALIZABLE)) {
DeserializationConfig config = ctxt.getConfig();
JavaType lt, mt;
if (_factoryConfig.hasAbstractTypeResolvers()) {
lt = _findRemappedType(config, List.class);
mt = _findRemappedType(config, Map.class);
} else {
lt = mt = null;
}
return new UntypedObjectDeserializer(lt, mt);
}
if (rawType == CLASS_STRING || rawType == CLASS_CHAR_SEQUENCE) {
return StringDeserializer.instance;
}
if (rawType == CLASS_ITERABLE) {
TypeFactory tf = ctxt.getTypeFactory();
JavaType[] tps = tf.findTypeParameters(type, CLASS_ITERABLE);
JavaType elemType = (tps == null || tps.length != 1) ? TypeFactory.unknownType() : tps[0];
CollectionType ct = tf.constructCollectionType(Collection.class, elemType);
return createCollectionDeserializer(ctxt, ct, beanDesc);
}
if (rawType == CLASS_MAP_ENTRY) {
JavaType kt = type.containedTypeOrUnknown(0);
JavaType vt = type.containedTypeOrUnknown(1);
TypeDeserializer vts = (TypeDeserializer) vt.getTypeHandler();
if (vts == null) {
vts = findTypeDeserializer(ctxt.getConfig(), vt);
}
JsonDeserializer<Object> valueDeser = vt.getValueHandler();
KeyDeserializer keyDes = (KeyDeserializer) kt.getValueHandler();
return new MapEntryDeserializer(type, keyDes, valueDeser, vts);
}
String clsName = rawType.getName();
if (rawType.isPrimitive() || clsName.startsWith("java.")) {
JsonDeserializer<?> deser = NumberDeserializers.find(rawType, clsName);
if (deser == null) {
deser = DateDeserializers.find(rawType, clsName);
}
if (deser != null) {
return deser;
}
}
if (rawType == TokenBuffer.class) {
return new TokenBufferDeserializer();
}
JsonDeserializer<?> deser = findOptionalStdDeserializer(ctxt, type, beanDesc);
if (deser != null) {
return deser;
}
return JdkDeserializers.find(rawType, clsName);
}
protected JavaType _findRemappedType(DeserializationConfig config, Class<?> rawType) throws JsonMappingException {
JavaType type = mapAbstractType(config, config.constructType(rawType));
return (type == null || type.hasRawClass(rawType)) ? null : type;
}
protected JsonDeserializer<?> _findCustomTreeNodeDeserializer(Class<? extends JsonNode> type,
DeserializationConfig config, BeanDescription beanDesc)
throws JsonMappingException
{
for (Deserializers d : _factoryConfig.deserializers()) {
JsonDeserializer<?> deser = d.findTreeNodeDeserializer(type, config, beanDesc);
if (deser != null) {
return deser;
}
}
return null;
}
protected JsonDeserializer<?> _findCustomReferenceDeserializer(ReferenceType type,
DeserializationConfig config, BeanDescription beanDesc,
TypeDeserializer contentTypeDeserializer, JsonDeserializer<?> contentDeserializer)
throws JsonMappingException
{
for (Deserializers d : _factoryConfig.deserializers()) {
JsonDeserializer<?> deser = d.findReferenceDeserializer(type, config, beanDesc,
contentTypeDeserializer, contentDeserializer);
if (deser != null) {
return deser;
}
}
return null;
}
@SuppressWarnings("unchecked")
protected JsonDeserializer<Object> _findCustomBeanDeserializer(JavaType type,
DeserializationConfig config, BeanDescription beanDesc)
throws JsonMappingException
{
for (Deserializers d : _factoryConfig.deserializers()) {
JsonDeserializer<?> deser = d.findBeanDeserializer(type, config, beanDesc);
if (deser != null) {
return (JsonDeserializer<Object>) deser;
}
}
return null;
}
protected JsonDeserializer<?> _findCustomArrayDeserializer(ArrayType type,
DeserializationConfig config, BeanDescription beanDesc,
TypeDeserializer elementTypeDeserializer, JsonDeserializer<?> elementDeserializer)
throws JsonMappingException
{
for (Deserializers d : _factoryConfig.deserializers()) {
JsonDeserializer<?> deser = d.findArrayDeserializer(type, config,
beanDesc, elementTypeDeserializer, elementDeserializer);
if (deser != null) {
return deser;
}
}
return null;
}
protected JsonDeserializer<?> _findCustomCollectionDeserializer(CollectionType type,
DeserializationConfig config, BeanDescription beanDesc,
TypeDeserializer elementTypeDeserializer, JsonDeserializer<?> elementDeserializer)
throws JsonMappingException
{
for (Deserializers d : _factoryConfig.deserializers()) {
JsonDeserializer<?> deser = d.findCollectionDeserializer(type, config, beanDesc,
elementTypeDeserializer, elementDeserializer);
if (deser != null) {
return deser;
}
}
return null;
}
protected JsonDeserializer<?> _findCustomCollectionLikeDeserializer(CollectionLikeType type,
DeserializationConfig config, BeanDescription beanDesc,
TypeDeserializer elementTypeDeserializer, JsonDeserializer<?> elementDeserializer)
throws JsonMappingException
{
for (Deserializers d : _factoryConfig.deserializers()) {
JsonDeserializer<?> deser = d.findCollectionLikeDeserializer(type, config, beanDesc,
elementTypeDeserializer, elementDeserializer);
if (deser != null) {
return deser;
}
}
return null;
}
protected JsonDeserializer<?> _findCustomEnumDeserializer(Class<?> type,
DeserializationConfig config, BeanDescription beanDesc)
throws JsonMappingException
{
for (Deserializers d : _factoryConfig.deserializers()) {
JsonDeserializer<?> deser = d.findEnumDeserializer(type, config, beanDesc);
if (deser != null) {
return deser;
}
}
return null;
}
protected JsonDeserializer<?> _findCustomMapDeserializer(MapType type,
DeserializationConfig config, BeanDescription beanDesc,
KeyDeserializer keyDeserializer,
TypeDeserializer elementTypeDeserializer, JsonDeserializer<?> elementDeserializer)
throws JsonMappingException
{
for (Deserializers d : _factoryConfig.deserializers()) {
JsonDeserializer<?> deser = d.findMapDeserializer(type, config, beanDesc,
keyDeserializer, elementTypeDeserializer, elementDeserializer);
if (deser != null) {
return deser;
}
}
return null;
}
protected JsonDeserializer<?> _findCustomMapLikeDeserializer(MapLikeType type,
DeserializationConfig config, BeanDescription beanDesc,
KeyDeserializer keyDeserializer,
TypeDeserializer elementTypeDeserializer, JsonDeserializer<?> elementDeserializer)
throws JsonMappingException
{
for (Deserializers d : _factoryConfig.deserializers()) {
JsonDeserializer<?> deser = d.findMapLikeDeserializer(type, config, beanDesc,
keyDeserializer, elementTypeDeserializer, elementDeserializer);
if (deser != null) {
return deser;
}
}
return null;
}
protected JsonDeserializer<Object> findDeserializerFromAnnotation(DeserializationContext ctxt,
Annotated ann)
throws JsonMappingException
{
AnnotationIntrospector intr = ctxt.getAnnotationIntrospector();
if (intr != null) {
Object deserDef = intr.findDeserializer(ann);
if (deserDef != null) {
return ctxt.deserializerInstance(ann, deserDef);
}
}
return null;
}
protected KeyDeserializer findKeyDeserializerFromAnnotation(DeserializationContext ctxt,
Annotated ann)
throws JsonMappingException
{
AnnotationIntrospector intr = ctxt.getAnnotationIntrospector();
if (intr != null) {
Object deserDef = intr.findKeyDeserializer(ann);
if (deserDef != null) {
return ctxt.keyDeserializerInstance(ann, deserDef);
}
}
return null;
}
protected JsonDeserializer<Object> findContentDeserializerFromAnnotation(DeserializationContext ctxt,
Annotated ann)
throws JsonMappingException
{
AnnotationIntrospector intr = ctxt.getAnnotationIntrospector();
if (intr != null) {
Object deserDef = intr.findContentDeserializer(ann);
if (deserDef != null) {
return ctxt.deserializerInstance(ann, deserDef);
}
}
return null;
}
protected JavaType resolveMemberAndTypeAnnotations(DeserializationContext ctxt,
AnnotatedMember member, JavaType type)
throws JsonMappingException
{
AnnotationIntrospector intr = ctxt.getAnnotationIntrospector();
if (intr == null) {
return type;
}
if (type.isMapLikeType()) {
JavaType keyType = type.getKeyType();
if (keyType != null) {
Object kdDef = intr.findKeyDeserializer(member);
KeyDeserializer kd = ctxt.keyDeserializerInstance(member, kdDef);
if (kd != null) {
type = ((MapLikeType) type).withKeyValueHandler(kd);
keyType = type.getKeyType();
}
}
}
if (type.hasContentType()) {
Object cdDef = intr.findContentDeserializer(member);
JsonDeserializer<?> cd = ctxt.deserializerInstance(member, cdDef);
if (cd != null) {
type = type.withContentValueHandler(cd);
}
TypeDeserializer contentTypeDeser = findPropertyContentTypeDeserializer(
ctxt.getConfig(), type, (AnnotatedMember) member);
if (contentTypeDeser != null) {
type = type.withContentTypeHandler(contentTypeDeser);
}
}
TypeDeserializer valueTypeDeser = findPropertyTypeDeserializer(ctxt.getConfig(),
type, (AnnotatedMember) member);
if (valueTypeDeser != null) {
type = type.withTypeHandler(valueTypeDeser);
}
type = intr.refineDeserializationType(ctxt.getConfig(), member, type);
return type;
}
protected EnumResolver constructEnumResolver(Class<?> enumClass,
DeserializationConfig config, AnnotatedMember jsonValueAccessor)
{
if (jsonValueAccessor != null) {
if (config.canOverrideAccessModifiers()) {
ClassUtil.checkAndFixAccess(jsonValueAccessor.getMember(),
config.isEnabled(MapperFeature.OVERRIDE_PUBLIC_ACCESS_MODIFIERS));
}
return EnumResolver.constructUsingMethod(config, enumClass, jsonValueAccessor);
}
return EnumResolver.constructFor(config, enumClass);
}
protected boolean _hasCreatorAnnotation(DeserializationContext ctxt,
Annotated ann) {
AnnotationIntrospector intr = ctxt.getAnnotationIntrospector();
if (intr != null) {
JsonCreator.Mode mode = intr.findCreatorAnnotation(ctxt.getConfig(), ann);
return (mode != null) && (mode != JsonCreator.Mode.DISABLED);
}
return false;
}
@Deprecated
protected JavaType modifyTypeByAnnotation(DeserializationContext ctxt,
Annotated a, JavaType type)
throws JsonMappingException
{
AnnotationIntrospector intr = ctxt.getAnnotationIntrospector();
if (intr == null) {
return type;
}
return intr.refineDeserializationType(ctxt.getConfig(), a, type);
}
@Deprecated
protected JavaType resolveType(DeserializationContext ctxt,
BeanDescription beanDesc, JavaType type, AnnotatedMember member)
throws JsonMappingException
{
return resolveMemberAndTypeAnnotations(ctxt, member, type);
}
@Deprecated
protected AnnotatedMethod _findJsonValueFor(DeserializationConfig config, JavaType enumType)
{
if (enumType == null) {
return null;
}
BeanDescription beanDesc = config.introspect(enumType);
return beanDesc.findJsonValueMethod();
}
@SuppressWarnings("rawtypes")
protected static class ContainerDefaultMappings {
final static HashMap<String, Class<? extends Collection>> _collectionFallbacks;
static {
HashMap<String, Class<? extends Collection>> fallbacks = new HashMap<>();
final Class<? extends Collection> DEFAULT_LIST = ArrayList.class;
final Class<? extends Collection> DEFAULT_SET = HashSet.class;
fallbacks.put(Collection.class.getName(), DEFAULT_LIST);
fallbacks.put(List.class.getName(), DEFAULT_LIST);
fallbacks.put(Set.class.getName(), DEFAULT_SET);
fallbacks.put(SortedSet.class.getName(), TreeSet.class);
fallbacks.put(Queue.class.getName(), LinkedList.class);
fallbacks.put(AbstractList.class.getName(), DEFAULT_LIST);
fallbacks.put(AbstractSet.class.getName(), DEFAULT_SET);
fallbacks.put(Deque.class.getName(), LinkedList.class);
fallbacks.put(NavigableSet.class.getName(), TreeSet.class);
_collectionFallbacks = fallbacks;
}
final static HashMap<String, Class<? extends Map>> _mapFallbacks;
static {
HashMap<String, Class<? extends Map>> fallbacks = new HashMap<>();
final Class<? extends Map> DEFAULT_MAP = LinkedHashMap.class;
fallbacks.put(Map.class.getName(), DEFAULT_MAP);
fallbacks.put(AbstractMap.class.getName(), DEFAULT_MAP);
fallbacks.put(ConcurrentMap.class.getName(), ConcurrentHashMap.class);
fallbacks.put(SortedMap.class.getName(), TreeMap.class);
fallbacks.put(java.util.NavigableMap.class.getName(), TreeMap.class);
fallbacks.put(java.util.concurrent.ConcurrentNavigableMap.class.getName(),
java.util.concurrent.ConcurrentSkipListMap.class);
_mapFallbacks = fallbacks;
}
public static Class<?> findCollectionFallback(JavaType type) {
return _collectionFallbacks.get(type.getRawClass().getName());
}
public static Class<?> findMapFallback(JavaType type) {
return _mapFallbacks.get(type.getRawClass().getName());
}
}
protected static class CreatorCollectionState {
public final DeserializationContext context;
public final BeanDescription beanDesc;
public final VisibilityChecker<?> vchecker;
public final CreatorCollector creators;
public final Map<AnnotatedWithParams,BeanPropertyDefinition[]> creatorParams;
private List<CreatorCandidate> _implicitFactoryCandidates;
private int _explicitFactoryCount;
private List<CreatorCandidate> _implicitConstructorCandidates;
private int _explicitConstructorCount;
public CreatorCollectionState(DeserializationContext ctxt, BeanDescription bd,
VisibilityChecker<?> vc,
CreatorCollector cc,
Map<AnnotatedWithParams,BeanPropertyDefinition[]> cp)
{
context = ctxt;
beanDesc = bd;
vchecker = vc;
creators = cc;
creatorParams = cp;
}
public AnnotationIntrospector annotationIntrospector() {
return context.getAnnotationIntrospector();
}
public void addImplicitFactoryCandidate(CreatorCandidate cc) {
if (_implicitFactoryCandidates == null) {
_implicitFactoryCandidates = new LinkedList<>();
}
_implicitFactoryCandidates.add(cc);
}
public void increaseExplicitFactoryCount() {
++_explicitFactoryCount;
}
public boolean hasExplicitFactories() {
return _explicitFactoryCount > 0;
}
public boolean hasImplicitFactoryCandidates() {
return _implicitFactoryCandidates != null;
}
public List<CreatorCandidate> implicitFactoryCandidates() {
return _implicitFactoryCandidates;
}
public void addImplicitConstructorCandidate(CreatorCandidate cc) {
if (_implicitConstructorCandidates == null) {
_implicitConstructorCandidates = new LinkedList<>();
}
_implicitConstructorCandidates.add(cc);
}
public void increaseExplicitConstructorCount() {
++_explicitConstructorCount;
}
public boolean hasExplicitConstructors() {
return _explicitConstructorCount > 0;
}
public boolean hasImplicitConstructorCandidates() {
return _implicitConstructorCandidates != null;
}
public List<CreatorCandidate> implicitConstructorCandidates() {
return _implicitConstructorCandidates;
}
}
}