com.fasterxml.jackson.databind.introspect.BasicBeanDescription Maven / Gradle / Ivy
Show all versions of jackson-databind Show documentation
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;
/**
* Default {@link BeanDescription} implementation used by Jackson.
*
* Although sub-classing is a theoretical possibility there are no known
* use cases for that, nor is such usage tested or supported.
* Separation from API is mostly to isolate some implementation details
* here and keep API simple.
*/
public class BasicBeanDescription extends BeanDescription
{
// since 2.9
private final static Class>[] NO_VIEWS = new Class>[0];
/*
/**********************************************************
/* General configuration
/**********************************************************
*/
/**
* We will hold a reference to the collector in cases where
* information is lazily accessed and constructed; properties
* are only accessed when they are actually needed.
*/
final protected POJOPropertiesCollector _propCollector;
final protected MapperConfig> _config;
final protected AnnotationIntrospector _annotationIntrospector;
/*
/**********************************************************
/* Information about type itself
/**********************************************************
*/
/**
* Information collected about the class introspected.
*/
final protected AnnotatedClass _classInfo;
/**
* @since 2.9
*/
protected Class>[] _defaultViews;
/**
* @since 2.9
*/
protected boolean _defaultViewsResolved;
/*
/**********************************************************
/* Member information
/**********************************************************
*/
/**
* Properties collected for the POJO; initialized as needed.
*/
protected List _properties;
/**
* Details of Object Id to include, if any
*/
protected ObjectIdInfo _objectIdInfo;
/*
/**********************************************************
/* Life-cycle
/**********************************************************
*/
protected BasicBeanDescription(POJOPropertiesCollector coll,
JavaType type, AnnotatedClass classDef)
{
super(type);
_propCollector = coll;
_config = coll.getConfig();
// NOTE: null config only for some pre-constructed types
if (_config == null) {
_annotationIntrospector = null;
} else {
_annotationIntrospector = _config.getAnnotationIntrospector();
}
_classInfo = classDef;
}
/**
* Alternate constructor used in cases where property information is not needed,
* only class info.
*/
protected BasicBeanDescription(MapperConfig> config,
JavaType type, AnnotatedClass classDef, List props)
{
super(type);
_propCollector = null;
_config = config;
// NOTE: null config only for some pre-constructed types
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();
}
/**
* Factory method to use for constructing an instance to use for building
* deserializers.
*/
public static BasicBeanDescription forDeserialization(POJOPropertiesCollector coll) {
return new BasicBeanDescription(coll);
}
/**
* Factory method to use for constructing an instance to use for building
* serializers.
*/
public static BasicBeanDescription forSerialization(POJOPropertiesCollector coll) {
return new BasicBeanDescription(coll);
}
/**
* Factory method to use for constructing an instance to use for purposes
* other than building serializers or deserializers; will only have information
* on class, not on properties.
*/
public static BasicBeanDescription forOtherUse(MapperConfig> config,
JavaType type, AnnotatedClass ac)
{
return new BasicBeanDescription(config, type,
ac, Collections.emptyList());
}
protected List _properties() {
if (_properties == null) {
_properties = _propCollector.getProperties();
}
return _properties;
}
/*
/**********************************************************
/* Limited modifications by core databind functionality
/**********************************************************
*/
/**
* Method that can be used to prune unwanted properties, during
* construction of serializers and deserializers.
* Use with utmost care, if at all...
*
* @since 2.1
*/
public boolean removeProperty(String propName)
{
Iterator 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)
{
// first: ensure we do not have such property
if (hasProperty(def.getFullName())) {
return false;
}
_properties().add(def);
return true;
}
/**
* @since 2.6
*/
public boolean hasProperty(PropertyName name) {
return findProperty(name) != null;
}
/**
* @since 2.6
*/
public BeanPropertyDefinition findProperty(PropertyName name)
{
for (BeanPropertyDefinition prop : _properties()) {
if (prop.hasName(name)) {
return prop;
}
}
return null;
}
/*
/**********************************************************
/* Simple accessors from BeanDescription
/**********************************************************
*/
@Override
public AnnotatedClass getClassInfo() { return _classInfo; }
@Override
public ObjectIdInfo getObjectIdInfo() { return _objectIdInfo; }
@Override
public List findProperties() {
return _properties();
}
@Override
@Deprecated // since 2.9
public AnnotatedMethod findJsonValueMethod() {
return (_propCollector == null) ? null
: _propCollector.getJsonValueMethod();
}
@Override // since 2.9
public AnnotatedMember findJsonValueAccessor() {
return (_propCollector == null) ? null
: _propCollector.getJsonValueAccessor();
}
@Override
public Set getIgnoredPropertyNames() {
Set 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 // since 2.7
public TypeBindings bindingsForBeanType() {
return _type.getBindings();
}
@Override
@Deprecated // since 2.8
public JavaType resolveType(java.lang.reflect.Type jdkType) {
if (jdkType == null) {
return null;
}
return _config.getTypeFactory().constructType(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) {
// Also, let's be somewhat strict on how field name is to be
// passed; String, Object make sense, others not so much.
/* !!! 18-May-2009, tatu: how about enums? Can add support if
* requested; easy enough for devs to add support within method.
*/
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) {
// For now let's require a Map; in future can add support for other
// types like perhaps Iterable?
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