package com.fasterxml.jackson.databind.introspect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.*;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
import com.fasterxml.jackson.databind.cfg.HandlerInstantiator;
import com.fasterxml.jackson.databind.cfg.MapperConfig;
import com.fasterxml.jackson.databind.type.TypeBindings;
import com.fasterxml.jackson.databind.util.Annotations;
import com.fasterxml.jackson.databind.util.ClassUtil;
import com.fasterxml.jackson.databind.util.Converter;
public class BasicBeanDescription extends BeanDescription
{
private final static Class<?>[] NO_VIEWS = new Class<?>[0];
final protected POJOPropertiesCollector _propCollector;
final protected MapperConfig<?> _config;
final protected AnnotationIntrospector _annotationIntrospector;
final protected AnnotatedClass _classInfo;
protected Class<?>[] _defaultViews;
protected boolean _defaultViewsResolved;
protected List<BeanPropertyDefinition> _properties;
protected ObjectIdInfo _objectIdInfo;
protected BasicBeanDescription(POJOPropertiesCollector coll,
JavaType type, AnnotatedClass classDef)
{
super(type);
_propCollector = coll;
_config = coll.getConfig();
if (_config == null) {
_annotationIntrospector = null;
} else {
_annotationIntrospector = _config.getAnnotationIntrospector();
}
_classInfo = classDef;
}
protected BasicBeanDescription(MapperConfig<?> config,
JavaType type, AnnotatedClass classDef, List<BeanPropertyDefinition> props)
{
super(type);
_propCollector = null;
_config = config;
if (_config == null) {
_annotationIntrospector = null;
} else {
_annotationIntrospector = _config.getAnnotationIntrospector();
}
_classInfo = classDef;
_properties = props;
}
protected BasicBeanDescription(POJOPropertiesCollector coll)
{
this(coll, coll.getType(), coll.getClassDef());
_objectIdInfo = coll.getObjectIdInfo();
}
public static BasicBeanDescription forDeserialization(POJOPropertiesCollector coll) {
return new BasicBeanDescription(coll);
}
public static BasicBeanDescription forSerialization(POJOPropertiesCollector coll) {
return new BasicBeanDescription(coll);
}
public static BasicBeanDescription forOtherUse(MapperConfig<?> config,
JavaType type, AnnotatedClass ac)
{
return new BasicBeanDescription(config, type,
ac, Collections.<BeanPropertyDefinition>emptyList());
}
protected List<BeanPropertyDefinition> _properties() {
if (_properties == null) {
_properties = _propCollector.getProperties();
}
return _properties;
}
public boolean removeProperty(String propName)
{
Iterator<BeanPropertyDefinition> it = _properties().iterator();
while (it.hasNext()) {
BeanPropertyDefinition prop = it.next();
if (prop.getName().equals(propName)) {
it.remove();
return true;
}
}
return false;
}
public boolean addProperty(BeanPropertyDefinition def)
{
if (hasProperty(def.getFullName())) {
return false;
}
_properties().add(def);
return true;
}
public boolean hasProperty(PropertyName name) {
return findProperty(name) != null;
}
public BeanPropertyDefinition findProperty(PropertyName name)
{
for (BeanPropertyDefinition prop : _properties()) {
if (prop.hasName(name)) {
return prop;
}
}
return null;
}
@Override
public AnnotatedClass getClassInfo() { return _classInfo; }
@Override
public ObjectIdInfo getObjectIdInfo() { return _objectIdInfo; }
@Override
public List<BeanPropertyDefinition> findProperties() {
return _properties();
}
@Override
public AnnotatedMember findJsonKeyAccessor() {
return (_propCollector == null) ? null
: _propCollector.getJsonKeyAccessor();
}
@Override
@Deprecated
public AnnotatedMethod findJsonValueMethod() {
return (_propCollector == null) ? null
: _propCollector.getJsonValueMethod();
}
@Override
public AnnotatedMember findJsonValueAccessor() {
return (_propCollector == null) ? null
: _propCollector.getJsonValueAccessor();
}
@Override
public Set<String> getIgnoredPropertyNames() {
Set<String> ign = (_propCollector == null) ? null
: _propCollector.getIgnoredPropertyNames();
if (ign == null) {
return Collections.emptySet();
}
return ign;
}
@Override
public boolean hasKnownClassAnnotations() {
return _classInfo.hasAnnotations();
}
@Override
public Annotations getClassAnnotations() {
return _classInfo.getAnnotations();
}
@Override
@Deprecated
public TypeBindings bindingsForBeanType() {
return _type.getBindings();
}
@Override
@Deprecated
public JavaType resolveType(java.lang.reflect.Type jdkType) {
return _config.getTypeFactory().resolveMemberType(jdkType, _type.getBindings());
}
@Override
public AnnotatedConstructor findDefaultConstructor() {
return _classInfo.getDefaultConstructor();
}
@Override
public AnnotatedMember findAnySetterAccessor() throws IllegalArgumentException
{
if (_propCollector != null) {
AnnotatedMethod anyMethod = _propCollector.getAnySetterMethod();
if (anyMethod != null) {
Class<?> type = anyMethod.getRawParameterType(0);
if ((type != String.class) && (type != Object.class)) {
throw new IllegalArgumentException(String.format(
"Invalid 'any-setter' annotation on method '%s()': first argument not of type String or Object, but %s",
anyMethod.getName(), type.getName()));
}
return anyMethod;
}
AnnotatedMember anyField = _propCollector.getAnySetterField();
if (anyField != null) {
Class<?> type = anyField.getRawType();
if (!Map.class.isAssignableFrom(type)) {
throw new IllegalArgumentException(String.format(
"Invalid 'any-setter' annotation on field '%s': type is not instance of java.util.Map",
anyField.getName()));
}
return anyField;
}
}
return null;
}
@Override
public Map<Object, AnnotatedMember> findInjectables() {
if (_propCollector != null) {
return _propCollector.getInjectables();
}
return Collections.emptyMap();
}
@Override
public List<AnnotatedConstructor> getConstructors() {
return _classInfo.getConstructors();
}
@Override
public Object instantiateBean(boolean fixAccess) {
AnnotatedConstructor ac = _classInfo.getDefaultConstructor();
if (ac == null) {
return null;
}
if (fixAccess) {
ac.fixAccess(_config.isEnabled(MapperFeature.OVERRIDE_PUBLIC_ACCESS_MODIFIERS));
}
try {
return ac.getAnnotated().newInstance();
} catch (Exception e) {
Throwable t = e;
while (t.getCause() != null) {
t = t.getCause();
}
ClassUtil.throwIfError(t);
ClassUtil.throwIfRTE(t);
throw new IllegalArgumentException("Failed to instantiate bean of type "
+_classInfo.getAnnotated().getName()+": ("+t.getClass().getName()+") "
+ClassUtil.exceptionMessage(t), t);
}
}
@Override
public AnnotatedMethod findMethod(String name, Class<?>[] paramTypes) {
return _classInfo.findMethod(name, paramTypes);
}
@Override
public JsonFormat.Value findExpectedFormat(JsonFormat.Value defValue)
{
if (_annotationIntrospector != null) {
JsonFormat.Value v = _annotationIntrospector.findFormat(_classInfo);
if (v != null) {
if (defValue == null) {
defValue = v;
} else {
defValue = defValue.withOverrides(v);
}
}
}
JsonFormat.Value v = _config.getDefaultPropertyFormat(_classInfo.getRawType());
if (v != null) {
if (defValue == null) {
defValue = v;
} else {
defValue = defValue.withOverrides(v);
}
}
return defValue;
}
@Override
public Class<?>[] findDefaultViews()
{
if (!_defaultViewsResolved) {
_defaultViewsResolved = true;
Class<?>[] def = (_annotationIntrospector == null) ? null
: _annotationIntrospector.findViews(_classInfo);
if (def == null) {
if (!_config.isEnabled(MapperFeature.DEFAULT_VIEW_INCLUSION)) {
def = NO_VIEWS;
}
}
_defaultViews = def;
}
return _defaultViews;
}
@Override
public Converter<Object,Object> findSerializationConverter()
{
if (_annotationIntrospector == null) {
return null;
}
return _createConverter(_annotationIntrospector.findSerializationConverter(_classInfo));
}
@Override
public JsonInclude.Value findPropertyInclusion(JsonInclude.Value defValue) {
if (_annotationIntrospector != null) {
JsonInclude.Value incl = _annotationIntrospector.findPropertyInclusion(_classInfo);
if (incl != null) {
return (defValue == null) ? incl : defValue.withOverrides(incl);
}
}
return defValue;
}
@Override
public AnnotatedMember findAnyGetter() throws IllegalArgumentException
{
if (_propCollector != null) {
AnnotatedMember anyGetter = _propCollector.getAnyGetterMethod();
if (anyGetter != null) {
Class<?> type = anyGetter.getRawType();
if (!Map.class.isAssignableFrom(type)) {
throw new IllegalArgumentException(String.format(
"Invalid 'any-getter' annotation on method %s(): return type is not instance of java.util.Map",
anyGetter.getName()));
}
return anyGetter;
}
AnnotatedMember anyField = _propCollector.getAnyGetterField();
if (anyField != null) {
Class<?> type = anyField.getRawType();
if (!Map.class.isAssignableFrom(type)) {
throw new IllegalArgumentException(String.format(
"Invalid 'any-getter' annotation on field '%s': type is not instance of java.util.Map",
anyField.getName()));
}
return anyField;
}
}
return null;
}
@Override
public List<BeanPropertyDefinition> findBackReferences()
{
List<BeanPropertyDefinition> result = null;
HashSet<String> names = null;
for (BeanPropertyDefinition property : _properties()) {
AnnotationIntrospector.ReferenceProperty refDef = property.findReferenceType();
if ((refDef == null) || !refDef.isBackReference()) {
continue;
}
final String refName = refDef.getName();
if (result == null) {
result = new ArrayList<BeanPropertyDefinition>();
names = new HashSet<>();
names.add(refName);
} else {
if (!names.add(refName)) {
throw new IllegalArgumentException("Multiple back-reference properties with name "+ClassUtil.name(refName));
}
}
result.add(property);
}
return result;
}
@Deprecated
@Override
public Map<String,AnnotatedMember> findBackReferenceProperties()
{
List<BeanPropertyDefinition> props = findBackReferences();
if (props == null) {
return null;
}
Map<String,AnnotatedMember> result = new HashMap<>();
for (BeanPropertyDefinition prop : props) {
result.put(prop.getName(), prop.getMutator());
}
return result;
}
@Override
public List<AnnotatedMethod> getFactoryMethods()
{
List<AnnotatedMethod> candidates = _classInfo.getFactoryMethods();
if (candidates.isEmpty()) {
return candidates;
}
List<AnnotatedMethod> result = null;
for (AnnotatedMethod am : candidates) {
if (isFactoryMethod(am)) {
if (result == null) {
result = new ArrayList<AnnotatedMethod>();
}
result.add(am);
}
}
if (result == null) {
return Collections.emptyList();
}
return result;
}
@Override
public Constructor<?> findSingleArgConstructor(Class<?>... argTypes)
{
for (AnnotatedConstructor ac : _classInfo.getConstructors()) {
if (ac.getParameterCount() == 1) {
Class<?> actArg = ac.getRawParameterType(0);
for (Class<?> expArg : argTypes) {
if (expArg == actArg) {
return ac.getAnnotated();
}
}
}
}
return null;
}
@Override
public Method findFactoryMethod(Class<?>... expArgTypes)
{
for (AnnotatedMethod am : _classInfo.getFactoryMethods()) {
if (isFactoryMethod(am) && am.getParameterCount() == 1) {
Class<?> actualArgType = am.getRawParameterType(0);
for (Class<?> expArgType : expArgTypes) {
if (actualArgType.isAssignableFrom(expArgType)) {
return am.getAnnotated();
}
}
}
}
return null;
}
protected boolean isFactoryMethod(AnnotatedMethod am)
{
Class<?> rt = am.getRawReturnType();
if (!getBeanClass().isAssignableFrom(rt)) {
return false;
}
JsonCreator.Mode mode = _annotationIntrospector.findCreatorAnnotation(_config, am);
if ((mode != null) && (mode != JsonCreator.Mode.DISABLED)) {
return true;
}
final String name = am.getName();
if ("valueOf".equals(name)) {
if (am.getParameterCount() == 1) {
return true;
}
}
if ("fromString".equals(name)) {
if (am.getParameterCount() == 1) {
Class<?> cls = am.getRawParameterType(0);
if (cls == String.class || CharSequence.class.isAssignableFrom(cls)) {
return true;
}
}
}
return false;
}
@Deprecated
protected PropertyName _findCreatorPropertyName(AnnotatedParameter param)
{
PropertyName name = _annotationIntrospector.findNameForDeserialization(param);
if (name == null || name.isEmpty()) {
String str = _annotationIntrospector.findImplicitPropertyName(param);
if (str != null && !str.isEmpty()) {
name = PropertyName.construct(str);
}
}
return name;
}
@Override
public Class<?> findPOJOBuilder() {
return (_annotationIntrospector == null) ?
null : _annotationIntrospector.findPOJOBuilder(_classInfo);
}
@Override
public JsonPOJOBuilder.Value findPOJOBuilderConfig()
{
return (_annotationIntrospector == null) ?
null : _annotationIntrospector.findPOJOBuilderConfig(_classInfo);
}
@Override
public Converter<Object,Object> findDeserializationConverter()
{
if (_annotationIntrospector == null) {
return null;
}
return _createConverter(_annotationIntrospector.findDeserializationConverter(_classInfo));
}
@Override
public String findClassDescription() {
return (_annotationIntrospector == null) ?
null : _annotationIntrospector.findClassDescription(_classInfo);
}
@Deprecated
public LinkedHashMap<String,AnnotatedField> _findPropertyFields(
Collection<String> ignoredProperties, boolean forSerialization)
{
LinkedHashMap<String,AnnotatedField> results = new LinkedHashMap<String,AnnotatedField>();
for (BeanPropertyDefinition property : _properties()) {
AnnotatedField f = property.getField();
if (f != null) {
String name = property.getName();
if (ignoredProperties != null) {
if (ignoredProperties.contains(name)) {
continue;
}
}
results.put(name, f);
}
}
return results;
}
@SuppressWarnings("unchecked")
protected Converter<Object,Object> _createConverter(Object converterDef)
{
if (converterDef == null) {
return null;
}
if (converterDef instanceof Converter<?,?>) {
return (Converter<Object,Object>) converterDef;
}
if (!(converterDef instanceof Class)) {
throw new IllegalStateException("AnnotationIntrospector returned Converter definition of type "
+converterDef.getClass().getName()+"; expected type Converter or Class<Converter> instead");
}
Class<?> converterClass = (Class<?>)converterDef;
if (converterClass == Converter.None.class || ClassUtil.isBogusClass(converterClass)) {
return null;
}
if (!Converter.class.isAssignableFrom(converterClass)) {
throw new IllegalStateException("AnnotationIntrospector returned Class "
+converterClass.getName()+"; expected Class<Converter>");
}
HandlerInstantiator hi = _config.getHandlerInstantiator();
Converter<?,?> conv = (hi == null) ? null : hi.converterInstance(_config, _classInfo, converterClass);
if (conv == null) {
conv = (Converter<?,?>) ClassUtil.createInstance(converterClass,
_config.canOverrideAccessModifiers());
}
return (Converter<Object,Object>) conv;
}
}