Skip to content

Commit

Permalink
Refactoring to make #815 cleaner for 2.6 (and remove 2.5 work-around,…
Browse files Browse the repository at this point in the history
… annotation from ObjectNode); also need to move #636 fix along since it will be triggered at bit later point.
  • Loading branch information
cowtowncoder committed Jun 5, 2015
1 parent 09960de commit 08ec397
Show file tree
Hide file tree
Showing 8 changed files with 139 additions and 102 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import com.fasterxml.jackson.annotation.ObjectIdGenerator;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
import com.fasterxml.jackson.annotation.ObjectIdResolver;

import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
import com.fasterxml.jackson.databind.cfg.DeserializerFactoryConfig;
Expand Down Expand Up @@ -213,7 +212,17 @@ public JsonDeserializer<Object> buildBeanDeserializer(DeserializationContext ctx
throws JsonMappingException
{
// First: check what creators we can use, if any
ValueInstantiator valueInstantiator = findValueInstantiator(ctxt, beanDesc);
ValueInstantiator valueInstantiator;
/* 04-Jun-2015, tatu: To work around [databind#636], need to catch the
* issue, defer; this seems like a reasonable good place for now.
* Note, however, that for non-Bean types (Collections, Maps) this
* probably won't work and needs to be added elsewhere.
*/
try {
valueInstantiator = findValueInstantiator(ctxt, beanDesc);
} catch (NoClassDefFoundError error) {
return new NoClassDefFoundDeserializer<Object>(error);
}
BeanDeserializerBuilder builder = constructBeanDeserializerBuilder(ctxt, beanDesc);
builder.setValueInstantiator(valueInstantiator);
// And then setters for deserializing from JSON Object
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.deser.impl.NoClassDefFoundDeserializer;
import com.fasterxml.jackson.databind.deser.std.StdDelegatingDeserializer;
import com.fasterxml.jackson.databind.introspect.Annotated;
import com.fasterxml.jackson.databind.type.*;
Expand Down Expand Up @@ -325,12 +324,7 @@ protected JsonDeserializer<Object> _createDeserializer(DeserializationContext ct
if (type.isAbstract() || type.isMapLikeType() || type.isCollectionLikeType()) {
type = factory.mapAbstractType(config, type);
}
BeanDescription beanDesc;
try {
beanDesc = config.introspect(type);
} catch (NoClassDefFoundError error) {
return new NoClassDefFoundDeserializer<Object>(error);
}
BeanDescription beanDesc = config.introspect(type);
// Then: does type define explicit deserializer to use, with annotation(s)?
JsonDeserializer<Object> deser = findDeserializerFromAnnotation(ctxt,
beanDesc.getClassInfo());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@
import java.io.IOException;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;

/**
* A deserializer that stores a {@link NoClassDefFoundError} error
* and throws the stored exception when attempting to deserialize
* a value. Null and empty values can be deserialized without error.
*
* @since 2.5
*/
public class NoClassDefFoundDeserializer<T> extends JsonDeserializer<T>
{
Expand All @@ -22,8 +23,7 @@ public NoClassDefFoundDeserializer(NoClassDefFoundError cause)
}

@Override
public T deserialize(JsonParser jp, DeserializationContext ctxt)
throws IOException, JsonProcessingException
public T deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException
{
throw _cause;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@
* 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.
*<p>
* Note that since 2.6 this class has been a thin shell around
* {@link POJOPropertiesCollector}, which handles most of actual work.
*/
public class BasicBeanDescription extends BeanDescription
{
Expand All @@ -31,6 +34,13 @@ public class BasicBeanDescription extends BeanDescription
/**********************************************************
*/

/**
* 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;
Expand All @@ -53,80 +63,66 @@ public class BasicBeanDescription extends BeanDescription
*/

/**
* Properties collected for the POJO.
* Properties collected for the POJO; initialized as needed.
*/
protected final List<BeanPropertyDefinition> _properties;
protected List<BeanPropertyDefinition> _properties;

/**
* Details of Object Id to include, if any
*/
protected ObjectIdInfo _objectIdInfo;

// // for deserialization

protected AnnotatedMethod _anySetterMethod;

protected Map<Object, AnnotatedMember> _injectables;

/**
* Set of properties that can be ignored during deserialization, due
* to being marked as ignored.
*/
protected Set<String> _ignoredPropertyNames;

// // for serialization

protected AnnotatedMethod _jsonValueMethod;

protected AnnotatedMember _anyGetter;

/*
/**********************************************************
/* Life-cycle
/**********************************************************
*/

protected BasicBeanDescription(POJOPropertiesCollector coll,
JavaType type, AnnotatedClass classDef)
{
super(type);
_propCollector = coll;
_config = coll.getConfig();
_annotationIntrospector = (_config == null) ? null : _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<BeanPropertyDefinition> props)
JavaType type, AnnotatedClass classDef, List<BeanPropertyDefinition> props)
{
super(type);
_propCollector = null;
_config = config;
_annotationIntrospector = (config == null) ? null : config.getAnnotationIntrospector();
_annotationIntrospector = (_config == null) ? null : _config.getAnnotationIntrospector();
_classInfo = classDef;
_properties = props;
}

protected BasicBeanDescription(POJOPropertiesCollector coll)
{
this(coll.getConfig(), coll.getType(), coll.getClassDef(), coll.getProperties());
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)
{
BasicBeanDescription desc = new BasicBeanDescription(coll);
desc._anySetterMethod = coll.getAnySetterMethod();
desc._ignoredPropertyNames = coll.getIgnoredPropertyNames();
desc._injectables = coll.getInjectables();
desc._jsonValueMethod = coll.getJsonValueMethod();
return desc;
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)
{
BasicBeanDescription desc = new BasicBeanDescription(coll);
desc._jsonValueMethod = coll.getJsonValueMethod();
desc._anyGetter = coll.getAnyGetter();
return desc;
public static BasicBeanDescription forSerialization(POJOPropertiesCollector coll) {
return new BasicBeanDescription(coll);
}

/**
Expand All @@ -141,6 +137,13 @@ public static BasicBeanDescription forOtherUse(MapperConfig<?> config,
ac, Collections.<BeanPropertyDefinition>emptyList());
}

protected List<BeanPropertyDefinition> _properties() {
if (_properties == null) {
_properties = _propCollector.getProperties();
}
return _properties;
}

/*
/**********************************************************
/* Limited modifications by core databind functionality
Expand All @@ -156,7 +159,7 @@ public static BasicBeanDescription forOtherUse(MapperConfig<?> config,
*/
public boolean removeProperty(String propName)
{
Iterator<BeanPropertyDefinition> it = _properties.iterator();
Iterator<BeanPropertyDefinition> it = _properties().iterator();
while (it.hasNext()) {
BeanPropertyDefinition prop = it.next();
if (prop.getName().equals(propName)) {
Expand All @@ -173,7 +176,7 @@ public boolean addProperty(BeanPropertyDefinition def)
if (hasProperty(def.getFullName())) {
return false;
}
_properties.add(def);
_properties().add(def);
return true;
}

Expand All @@ -189,7 +192,7 @@ public boolean hasProperty(PropertyName name) {
*/
public BeanPropertyDefinition findProperty(PropertyName name)
{
for (BeanPropertyDefinition prop : _properties) {
for (BeanPropertyDefinition prop : _properties()) {
if (prop.hasName(name)) {
return prop;
}
Expand All @@ -211,20 +214,23 @@ public BeanPropertyDefinition findProperty(PropertyName name)

@Override
public List<BeanPropertyDefinition> findProperties() {
return _properties;
return _properties();
}

@Override
public AnnotatedMethod findJsonValueMethod() {
return _jsonValueMethod;
return (_propCollector == null) ? null
: _propCollector.getJsonValueMethod();
}

@Override
public Set<String> getIgnoredPropertyNames() {
if (_ignoredPropertyNames == null) {
Set<String> ign = (_propCollector == null) ? null
: _propCollector.getIgnoredPropertyNames();
if (ign == null) {
return Collections.emptySet();
}
return _ignoredPropertyNames;
return ign;
}

@Override
Expand Down Expand Up @@ -262,7 +268,9 @@ public AnnotatedConstructor findDefaultConstructor() {
@Override
public AnnotatedMethod findAnySetter() throws IllegalArgumentException
{
if (_anySetterMethod != null) {
AnnotatedMethod anySetter = (_propCollector == null) ? null
: _propCollector.getAnySetterMethod();
if (anySetter != null) {
/* Also, let's be somewhat strict on how field name is to be
* passed; String, Object make sense, others not
* so much.
Expand All @@ -271,17 +279,20 @@ public AnnotatedMethod findAnySetter() throws IllegalArgumentException
* requested; easy enough for devs to add support within
* method.
*/
Class<?> type = _anySetterMethod.getRawParameterType(0);
Class<?> type = anySetter.getRawParameterType(0);
if (type != String.class && type != Object.class) {
throw new IllegalArgumentException("Invalid 'any-setter' annotation on method "+_anySetterMethod.getName()+"(): first argument not of type String or Object, but "+type.getName());
throw new IllegalArgumentException("Invalid 'any-setter' annotation on method "+anySetter.getName()+"(): first argument not of type String or Object, but "+type.getName());
}
}
return _anySetterMethod;
return anySetter;
}

@Override
public Map<Object, AnnotatedMember> findInjectables() {
return _injectables;
if (_propCollector != null) {
return _propCollector.getInjectables();
}
return Collections.emptyMap();
}

@Override
Expand Down Expand Up @@ -387,25 +398,27 @@ public JsonInclude.Include findSerializationInclusionForContent(JsonInclude.Incl
@Override
public AnnotatedMember findAnyGetter() throws IllegalArgumentException
{
if (_anyGetter != null) {
AnnotatedMember anyGetter = (_propCollector == null) ? null
: _propCollector.getAnyGetter();
if (anyGetter != null) {
/* For now let's require a Map; in future can add support for other
* types like perhaps Iterable<Map.Entry>?
*/
Class<?> type = _anyGetter.getRawType();
Class<?> type = anyGetter.getRawType();
if (!Map.class.isAssignableFrom(type)) {
throw new IllegalArgumentException("Invalid 'any-getter' annotation on method "+_anyGetter.getName()+"(): return type is not instance of java.util.Map");
throw new IllegalArgumentException("Invalid 'any-getter' annotation on method "+anyGetter.getName()+"(): return type is not instance of java.util.Map");
}
}
return _anyGetter;
return anyGetter;
}

@Override
public Map<String,AnnotatedMember> findBackReferenceProperties()
{
HashMap<String,AnnotatedMember> result = null;
// boolean hasIgnored = (_ignoredPropertyNames != null);

for (BeanPropertyDefinition property : _properties) {
for (BeanPropertyDefinition property : _properties()) {
/* 23-Sep-2014, tatu: As per [Databind#426], we _should_ try to avoid
* calling accessor, as it triggers exception from seeming conflict.
* But the problem is that _ignoredPropertyNames here only contains
Expand Down Expand Up @@ -636,7 +649,7 @@ public LinkedHashMap<String,AnnotatedField> _findPropertyFields(
Collection<String> ignoredProperties, boolean forSerialization)
{
LinkedHashMap<String,AnnotatedField> results = new LinkedHashMap<String,AnnotatedField>();
for (BeanPropertyDefinition property : _properties) {
for (BeanPropertyDefinition property : _properties()) {
AnnotatedField f = property.getField();
if (f != null) {
String name = property.getName();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ protected POJOPropertiesCollector collectProperties(MapperConfig<?> config,
boolean useAnnotations = config.isAnnotationProcessingEnabled();
AnnotatedClass ac = AnnotatedClass.construct(type.getRawClass(),
(useAnnotations ? config.getAnnotationIntrospector() : null), r);
return constructPropertyCollector(config, ac, type, forSerialization, mutatorPrefix).collect();
return constructPropertyCollector(config, ac, type, forSerialization, mutatorPrefix);
}

protected POJOPropertiesCollector collectPropertiesWithBuilder(MapperConfig<?> config,
Expand All @@ -205,7 +205,7 @@ protected POJOPropertiesCollector collectPropertiesWithBuilder(MapperConfig<?> c
AnnotatedClass ac = AnnotatedClass.construct(type.getRawClass(), ai, r);
JsonPOJOBuilder.Value builderConfig = (ai == null) ? null : ai.findPOJOBuilderConfig(ac);
String mutatorPrefix = (builderConfig == null) ? "with" : builderConfig.withPrefix;
return constructPropertyCollector(config, ac, type, forSerialization, mutatorPrefix).collect();
return constructPropertyCollector(config, ac, type, forSerialization, mutatorPrefix);
}

/**
Expand Down
Loading

0 comments on commit 08ec397

Please sign in to comment.