package com.fasterxml.jackson.databind.deser.impl;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Member;
import java.lang.reflect.Type;
import java.util.*;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.cfg.MapperConfig;
import com.fasterxml.jackson.databind.deser.SettableBeanProperty;
import com.fasterxml.jackson.databind.deser.ValueInstantiator;
import com.fasterxml.jackson.databind.deser.std.StdValueInstantiator;
import com.fasterxml.jackson.databind.introspect.*;
import com.fasterxml.jackson.databind.util.ClassUtil;
public class CreatorCollector {
protected final static int C_DEFAULT = 0;
protected final static int C_STRING = 1;
protected final static int C_INT = 2;
protected final static int C_LONG = 3;
protected final static int C_DOUBLE = 4;
protected final static int C_BOOLEAN = 5;
protected final static int C_DELEGATE = 6;
protected final static int C_PROPS = 7;
protected final static int C_ARRAY_DELEGATE = 8;
protected final static String[] TYPE_DESCS = new String[] { "default",
"from-String", "from-int", "from-long", "from-double",
"from-boolean", "delegate", "property-based" };
final protected BeanDescription _beanDesc;
final protected boolean _canFixAccess;
final protected boolean _forceAccess;
protected final AnnotatedWithParams[] _creators = new AnnotatedWithParams[9];
protected int _explicitCreators = 0;
protected boolean _hasNonDefaultCreator = false;
protected SettableBeanProperty[] _delegateArgs;
protected SettableBeanProperty[] _arrayDelegateArgs;
protected SettableBeanProperty[] _propertyBasedArgs;
protected AnnotatedParameter _incompleteParameter;
public CreatorCollector(BeanDescription beanDesc, MapperConfig<?> config) {
_beanDesc = beanDesc;
_canFixAccess = config.canOverrideAccessModifiers();
_forceAccess = config
.isEnabled(MapperFeature.OVERRIDE_PUBLIC_ACCESS_MODIFIERS);
}
public ValueInstantiator constructValueInstantiator(
DeserializationConfig config) {
final JavaType delegateType = _computeDelegateType(
_creators[C_DELEGATE], _delegateArgs);
final JavaType arrayDelegateType = _computeDelegateType(
_creators[C_ARRAY_DELEGATE], _arrayDelegateArgs);
final JavaType type = _beanDesc.getType();
AnnotatedWithParams defaultCtor = StdTypeConstructor
.tryToOptimize(_creators[C_DEFAULT]);
StdValueInstantiator inst = new StdValueInstantiator(config, type);
inst.configureFromObjectSettings(defaultCtor, _creators[C_DELEGATE],
delegateType, _delegateArgs, _creators[C_PROPS],
_propertyBasedArgs);
inst.configureFromArraySettings(_creators[C_ARRAY_DELEGATE],
arrayDelegateType, _arrayDelegateArgs);
inst.configureFromStringCreator(_creators[C_STRING]);
inst.configureFromIntCreator(_creators[C_INT]);
inst.configureFromLongCreator(_creators[C_LONG]);
inst.configureFromDoubleCreator(_creators[C_DOUBLE]);
inst.configureFromBooleanCreator(_creators[C_BOOLEAN]);
inst.configureIncompleteParameter(_incompleteParameter);
return inst;
}
public void setDefaultCreator(AnnotatedWithParams creator) {
_creators[C_DEFAULT] = _fixAccess(creator);
}
public void addStringCreator(AnnotatedWithParams creator, boolean explicit) {
verifyNonDup(creator, C_STRING, explicit);
}
public void addIntCreator(AnnotatedWithParams creator, boolean explicit) {
verifyNonDup(creator, C_INT, explicit);
}
public void addLongCreator(AnnotatedWithParams creator, boolean explicit) {
verifyNonDup(creator, C_LONG, explicit);
}
public void addDoubleCreator(AnnotatedWithParams creator, boolean explicit) {
verifyNonDup(creator, C_DOUBLE, explicit);
}
public void addBooleanCreator(AnnotatedWithParams creator, boolean explicit) {
verifyNonDup(creator, C_BOOLEAN, explicit);
}
public void addDelegatingCreator(AnnotatedWithParams creator,
boolean explicit, SettableBeanProperty[] injectables,
int delegateeIndex)
{
if (creator.getParameterType(delegateeIndex).isCollectionLikeType()) {
if (verifyNonDup(creator, C_ARRAY_DELEGATE, explicit)) {
_arrayDelegateArgs = injectables;
}
} else {
if (verifyNonDup(creator, C_DELEGATE, explicit)) {
_delegateArgs = injectables;
}
}
}
public void addPropertyCreator(AnnotatedWithParams creator,
boolean explicit, SettableBeanProperty[] properties)
{
if (verifyNonDup(creator, C_PROPS, explicit)) {
if (properties.length > 1) {
HashMap<String, Integer> names = new HashMap<String, Integer>();
for (int i = 0, len = properties.length; i < len; ++i) {
String name = properties[i].getName();
if (name.isEmpty() && (properties[i].getInjectableValueId() != null)) {
continue;
}
Integer old = names.put(name, Integer.valueOf(i));
if (old != null) {
throw new IllegalArgumentException(String.format(
"Duplicate creator property \"%s\" (index %s vs %d)",
name, old, i));
}
}
}
_propertyBasedArgs = properties;
}
}
public void addIncompeteParameter(AnnotatedParameter parameter) {
if (_incompleteParameter == null) {
_incompleteParameter = parameter;
}
}
public boolean hasDefaultCreator() {
return _creators[C_DEFAULT] != null;
}
public boolean hasDelegatingCreator() {
return _creators[C_DELEGATE] != null;
}
public boolean hasPropertyBasedCreator() {
return _creators[C_PROPS] != null;
}
private JavaType _computeDelegateType(AnnotatedWithParams creator,
SettableBeanProperty[] delegateArgs) {
if (!_hasNonDefaultCreator || (creator == null)) {
return null;
}
int ix = 0;
if (delegateArgs != null) {
for (int i = 0, len = delegateArgs.length; i < len; ++i) {
if (delegateArgs[i] == null) {
ix = i;
break;
}
}
}
return creator.getParameterType(ix);
}
private <T extends AnnotatedMember> T _fixAccess(T member) {
if (member != null && _canFixAccess) {
ClassUtil.checkAndFixAccess((Member) member.getAnnotated(),
_forceAccess);
}
return member;
}
protected boolean verifyNonDup(AnnotatedWithParams newOne, int typeIndex, boolean explicit)
{
final int mask = (1 << typeIndex);
_hasNonDefaultCreator = true;
AnnotatedWithParams oldOne = _creators[typeIndex];
if (oldOne != null) {
boolean verify;
if ((_explicitCreators & mask) != 0) {
if (!explicit) {
return false;
}
verify = true;
} else {
verify = !explicit;
}
if (verify && (oldOne.getClass() == newOne.getClass())) {
Class<?> oldType = oldOne.getRawParameterType(0);
Class<?> newType = newOne.getRawParameterType(0);
if (oldType == newType) {
if (_isEnumValueOf(newOne)) {
return false;
}
if (_isEnumValueOf(oldOne)) {
;
} else {
throw new IllegalArgumentException(String.format(
"Conflicting %s creators: already had %s creator %s, encountered another: %s",
TYPE_DESCS[typeIndex],
explicit ? "explicitly marked"
: "implicitly discovered",
oldOne, newOne));
}
}
else if (newType.isAssignableFrom(oldType)) {
return false;
}
}
}
if (explicit) {
_explicitCreators |= mask;
}
_creators[typeIndex] = _fixAccess(newOne);
return true;
}
protected boolean _isEnumValueOf(AnnotatedWithParams creator) {
return creator.getDeclaringClass().isEnum()
&& "valueOf".equals(creator.getName());
}
protected final static class StdTypeConstructor extends AnnotatedWithParams
implements java.io.Serializable {
private static final long serialVersionUID = 1L;
public final static int TYPE_ARRAY_LIST = 1;
public final static int TYPE_HASH_MAP = 2;
public final static int TYPE_LINKED_HASH_MAP = 3;
private final AnnotatedWithParams _base;
private final int _type;
public StdTypeConstructor(AnnotatedWithParams base, int t) {
super(base, null);
_base = base;
_type = t;
}
public static AnnotatedWithParams tryToOptimize(
AnnotatedWithParams src) {
if (src != null) {
final Class<?> rawType = src.getDeclaringClass();
if (rawType == List.class || rawType == ArrayList.class) {
return new StdTypeConstructor(src, TYPE_ARRAY_LIST);
}
if (rawType == LinkedHashMap.class) {
return new StdTypeConstructor(src, TYPE_LINKED_HASH_MAP);
}
if (rawType == HashMap.class) {
return new StdTypeConstructor(src, TYPE_HASH_MAP);
}
}
return src;
}
protected final Object _construct() {
switch (_type) {
case TYPE_ARRAY_LIST:
return new ArrayList<Object>();
case TYPE_LINKED_HASH_MAP:
return new LinkedHashMap<String, Object>();
case TYPE_HASH_MAP:
return new HashMap<String, Object>();
}
throw new IllegalStateException("Unknown type " + _type);
}
@Override
public int getParameterCount() {
return _base.getParameterCount();
}
@Override
public Class<?> getRawParameterType(int index) {
return _base.getRawParameterType(index);
}
@Override
public JavaType getParameterType(int index) {
return _base.getParameterType(index);
}
@Override
@Deprecated
public Type getGenericParameterType(int index) {
return _base.getGenericParameterType(index);
}
@Override
public Object call() throws Exception {
return _construct();
}
@Override
public Object call(Object[] args) throws Exception {
return _construct();
}
@Override
public Object call1(Object arg) throws Exception {
return _construct();
}
@Override
public Class<?> getDeclaringClass() {
return _base.getDeclaringClass();
}
@Override
public Member getMember() {
return _base.getMember();
}
@Override
public void setValue(Object pojo, Object value)
throws UnsupportedOperationException, IllegalArgumentException {
throw new UnsupportedOperationException();
}
@Override
public Object getValue(Object pojo)
throws UnsupportedOperationException, IllegalArgumentException {
throw new UnsupportedOperationException();
}
@Override
public Annotated withAnnotations(AnnotationMap fallback) {
throw new UnsupportedOperationException();
}
@Override
public AnnotatedElement getAnnotated() {
return _base.getAnnotated();
}
@Override
protected int getModifiers() {
return _base.getMember().getModifiers();
}
@Override
public String getName() {
return _base.getName();
}
@Override
public JavaType getType() {
return _base.getType();
}
@Override
public Class<?> getRawType() {
return _base.getRawType();
}
@Override
public boolean equals(Object o) {
return (o == this);
}
@Override
public int hashCode() {
return _base.hashCode();
}
@Override
public String toString() {
return _base.toString();
}
}
}