Skip to content

Commit 08ec397

Browse files
committed
Refactoring to make #815 cleaner for 2.6 (and remove 2.5 work-around, annotation from ObjectNode); also need to move #636 fix along since it will be triggered at bit later point.
1 parent 09960de commit 08ec397

File tree

8 files changed

+139
-102
lines changed

8 files changed

+139
-102
lines changed

src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializerFactory.java

+11-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import com.fasterxml.jackson.annotation.ObjectIdGenerator;
77
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
88
import com.fasterxml.jackson.annotation.ObjectIdResolver;
9-
109
import com.fasterxml.jackson.databind.*;
1110
import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
1211
import com.fasterxml.jackson.databind.cfg.DeserializerFactoryConfig;
@@ -213,7 +212,17 @@ public JsonDeserializer<Object> buildBeanDeserializer(DeserializationContext ctx
213212
throws JsonMappingException
214213
{
215214
// First: check what creators we can use, if any
216-
ValueInstantiator valueInstantiator = findValueInstantiator(ctxt, beanDesc);
215+
ValueInstantiator valueInstantiator;
216+
/* 04-Jun-2015, tatu: To work around [databind#636], need to catch the
217+
* issue, defer; this seems like a reasonable good place for now.
218+
* Note, however, that for non-Bean types (Collections, Maps) this
219+
* probably won't work and needs to be added elsewhere.
220+
*/
221+
try {
222+
valueInstantiator = findValueInstantiator(ctxt, beanDesc);
223+
} catch (NoClassDefFoundError error) {
224+
return new NoClassDefFoundDeserializer<Object>(error);
225+
}
217226
BeanDeserializerBuilder builder = constructBeanDeserializerBuilder(ctxt, beanDesc);
218227
builder.setValueInstantiator(valueInstantiator);
219228
// And then setters for deserializing from JSON Object

src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java

+1-7
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55

66
import com.fasterxml.jackson.annotation.JsonFormat;
77
import com.fasterxml.jackson.databind.*;
8-
import com.fasterxml.jackson.databind.deser.impl.NoClassDefFoundDeserializer;
98
import com.fasterxml.jackson.databind.deser.std.StdDelegatingDeserializer;
109
import com.fasterxml.jackson.databind.introspect.Annotated;
1110
import com.fasterxml.jackson.databind.type.*;
@@ -325,12 +324,7 @@ protected JsonDeserializer<Object> _createDeserializer(DeserializationContext ct
325324
if (type.isAbstract() || type.isMapLikeType() || type.isCollectionLikeType()) {
326325
type = factory.mapAbstractType(config, type);
327326
}
328-
BeanDescription beanDesc;
329-
try {
330-
beanDesc = config.introspect(type);
331-
} catch (NoClassDefFoundError error) {
332-
return new NoClassDefFoundDeserializer<Object>(error);
333-
}
327+
BeanDescription beanDesc = config.introspect(type);
334328
// Then: does type define explicit deserializer to use, with annotation(s)?
335329
JsonDeserializer<Object> deser = findDeserializerFromAnnotation(ctxt,
336330
beanDesc.getClassInfo());

src/main/java/com/fasterxml/jackson/databind/deser/impl/NoClassDefFoundDeserializer.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,15 @@
33
import java.io.IOException;
44

55
import com.fasterxml.jackson.core.JsonParser;
6-
import com.fasterxml.jackson.core.JsonProcessingException;
76
import com.fasterxml.jackson.databind.DeserializationContext;
87
import com.fasterxml.jackson.databind.JsonDeserializer;
98

109
/**
1110
* A deserializer that stores a {@link NoClassDefFoundError} error
1211
* and throws the stored exception when attempting to deserialize
1312
* a value. Null and empty values can be deserialized without error.
13+
*
14+
* @since 2.5
1415
*/
1516
public class NoClassDefFoundDeserializer<T> extends JsonDeserializer<T>
1617
{
@@ -22,8 +23,7 @@ public NoClassDefFoundDeserializer(NoClassDefFoundError cause)
2223
}
2324

2425
@Override
25-
public T deserialize(JsonParser jp, DeserializationContext ctxt)
26-
throws IOException, JsonProcessingException
26+
public T deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException
2727
{
2828
throw _cause;
2929
}

src/main/java/com/fasterxml/jackson/databind/introspect/BasicBeanDescription.java

+70-57
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@
2222
* use cases for that, nor is such usage tested or supported.
2323
* Separation from API is mostly to isolate some implementation details
2424
* here and keep API simple.
25+
*<p>
26+
* Note that since 2.6 this class has been a thin shell around
27+
* {@link POJOPropertiesCollector}, which handles most of actual work.
2528
*/
2629
public class BasicBeanDescription extends BeanDescription
2730
{
@@ -31,6 +34,13 @@ public class BasicBeanDescription extends BeanDescription
3134
/**********************************************************
3235
*/
3336

37+
/**
38+
* We will hold a reference to the collector in cases where
39+
* information is lazily accessed and constructed; properties
40+
* are only accessed when they are actually needed.
41+
*/
42+
final protected POJOPropertiesCollector _propCollector;
43+
3444
final protected MapperConfig<?> _config;
3545

3646
final protected AnnotationIntrospector _annotationIntrospector;
@@ -53,80 +63,66 @@ public class BasicBeanDescription extends BeanDescription
5363
*/
5464

5565
/**
56-
* Properties collected for the POJO.
66+
* Properties collected for the POJO; initialized as needed.
5767
*/
58-
protected final List<BeanPropertyDefinition> _properties;
68+
protected List<BeanPropertyDefinition> _properties;
5969

6070
/**
6171
* Details of Object Id to include, if any
6272
*/
6373
protected ObjectIdInfo _objectIdInfo;
6474

65-
// // for deserialization
66-
67-
protected AnnotatedMethod _anySetterMethod;
68-
69-
protected Map<Object, AnnotatedMember> _injectables;
70-
71-
/**
72-
* Set of properties that can be ignored during deserialization, due
73-
* to being marked as ignored.
74-
*/
75-
protected Set<String> _ignoredPropertyNames;
76-
77-
// // for serialization
78-
79-
protected AnnotatedMethod _jsonValueMethod;
80-
81-
protected AnnotatedMember _anyGetter;
82-
8375
/*
8476
/**********************************************************
8577
/* Life-cycle
8678
/**********************************************************
8779
*/
8880

81+
protected BasicBeanDescription(POJOPropertiesCollector coll,
82+
JavaType type, AnnotatedClass classDef)
83+
{
84+
super(type);
85+
_propCollector = coll;
86+
_config = coll.getConfig();
87+
_annotationIntrospector = (_config == null) ? null : _config.getAnnotationIntrospector();
88+
_classInfo = classDef;
89+
}
90+
91+
/**
92+
* Alternate constructor used in cases where property information is not needed,
93+
* only class info.
94+
*/
8995
protected BasicBeanDescription(MapperConfig<?> config,
90-
JavaType type, AnnotatedClass classDef,
91-
List<BeanPropertyDefinition> props)
96+
JavaType type, AnnotatedClass classDef, List<BeanPropertyDefinition> props)
9297
{
9398
super(type);
99+
_propCollector = null;
94100
_config = config;
95-
_annotationIntrospector = (config == null) ? null : config.getAnnotationIntrospector();
101+
_annotationIntrospector = (_config == null) ? null : _config.getAnnotationIntrospector();
96102
_classInfo = classDef;
97103
_properties = props;
98104
}
99105

100106
protected BasicBeanDescription(POJOPropertiesCollector coll)
101107
{
102-
this(coll.getConfig(), coll.getType(), coll.getClassDef(), coll.getProperties());
108+
this(coll, coll.getType(), coll.getClassDef());
103109
_objectIdInfo = coll.getObjectIdInfo();
104110
}
105111

106112
/**
107113
* Factory method to use for constructing an instance to use for building
108114
* deserializers.
109115
*/
110-
public static BasicBeanDescription forDeserialization(POJOPropertiesCollector coll)
111-
{
112-
BasicBeanDescription desc = new BasicBeanDescription(coll);
113-
desc._anySetterMethod = coll.getAnySetterMethod();
114-
desc._ignoredPropertyNames = coll.getIgnoredPropertyNames();
115-
desc._injectables = coll.getInjectables();
116-
desc._jsonValueMethod = coll.getJsonValueMethod();
117-
return desc;
116+
public static BasicBeanDescription forDeserialization(POJOPropertiesCollector coll) {
117+
return new BasicBeanDescription(coll);
118118
}
119119

120120
/**
121121
* Factory method to use for constructing an instance to use for building
122122
* serializers.
123123
*/
124-
public static BasicBeanDescription forSerialization(POJOPropertiesCollector coll)
125-
{
126-
BasicBeanDescription desc = new BasicBeanDescription(coll);
127-
desc._jsonValueMethod = coll.getJsonValueMethod();
128-
desc._anyGetter = coll.getAnyGetter();
129-
return desc;
124+
public static BasicBeanDescription forSerialization(POJOPropertiesCollector coll) {
125+
return new BasicBeanDescription(coll);
130126
}
131127

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

140+
protected List<BeanPropertyDefinition> _properties() {
141+
if (_properties == null) {
142+
_properties = _propCollector.getProperties();
143+
}
144+
return _properties;
145+
}
146+
144147
/*
145148
/**********************************************************
146149
/* Limited modifications by core databind functionality
@@ -156,7 +159,7 @@ public static BasicBeanDescription forOtherUse(MapperConfig<?> config,
156159
*/
157160
public boolean removeProperty(String propName)
158161
{
159-
Iterator<BeanPropertyDefinition> it = _properties.iterator();
162+
Iterator<BeanPropertyDefinition> it = _properties().iterator();
160163
while (it.hasNext()) {
161164
BeanPropertyDefinition prop = it.next();
162165
if (prop.getName().equals(propName)) {
@@ -173,7 +176,7 @@ public boolean addProperty(BeanPropertyDefinition def)
173176
if (hasProperty(def.getFullName())) {
174177
return false;
175178
}
176-
_properties.add(def);
179+
_properties().add(def);
177180
return true;
178181
}
179182

@@ -189,7 +192,7 @@ public boolean hasProperty(PropertyName name) {
189192
*/
190193
public BeanPropertyDefinition findProperty(PropertyName name)
191194
{
192-
for (BeanPropertyDefinition prop : _properties) {
195+
for (BeanPropertyDefinition prop : _properties()) {
193196
if (prop.hasName(name)) {
194197
return prop;
195198
}
@@ -211,20 +214,23 @@ public BeanPropertyDefinition findProperty(PropertyName name)
211214

212215
@Override
213216
public List<BeanPropertyDefinition> findProperties() {
214-
return _properties;
217+
return _properties();
215218
}
216219

217220
@Override
218221
public AnnotatedMethod findJsonValueMethod() {
219-
return _jsonValueMethod;
222+
return (_propCollector == null) ? null
223+
: _propCollector.getJsonValueMethod();
220224
}
221225

222226
@Override
223227
public Set<String> getIgnoredPropertyNames() {
224-
if (_ignoredPropertyNames == null) {
228+
Set<String> ign = (_propCollector == null) ? null
229+
: _propCollector.getIgnoredPropertyNames();
230+
if (ign == null) {
225231
return Collections.emptySet();
226232
}
227-
return _ignoredPropertyNames;
233+
return ign;
228234
}
229235

230236
@Override
@@ -262,7 +268,9 @@ public AnnotatedConstructor findDefaultConstructor() {
262268
@Override
263269
public AnnotatedMethod findAnySetter() throws IllegalArgumentException
264270
{
265-
if (_anySetterMethod != null) {
271+
AnnotatedMethod anySetter = (_propCollector == null) ? null
272+
: _propCollector.getAnySetterMethod();
273+
if (anySetter != null) {
266274
/* Also, let's be somewhat strict on how field name is to be
267275
* passed; String, Object make sense, others not
268276
* so much.
@@ -271,17 +279,20 @@ public AnnotatedMethod findAnySetter() throws IllegalArgumentException
271279
* requested; easy enough for devs to add support within
272280
* method.
273281
*/
274-
Class<?> type = _anySetterMethod.getRawParameterType(0);
282+
Class<?> type = anySetter.getRawParameterType(0);
275283
if (type != String.class && type != Object.class) {
276-
throw new IllegalArgumentException("Invalid 'any-setter' annotation on method "+_anySetterMethod.getName()+"(): first argument not of type String or Object, but "+type.getName());
284+
throw new IllegalArgumentException("Invalid 'any-setter' annotation on method "+anySetter.getName()+"(): first argument not of type String or Object, but "+type.getName());
277285
}
278286
}
279-
return _anySetterMethod;
287+
return anySetter;
280288
}
281289

282290
@Override
283291
public Map<Object, AnnotatedMember> findInjectables() {
284-
return _injectables;
292+
if (_propCollector != null) {
293+
return _propCollector.getInjectables();
294+
}
295+
return Collections.emptyMap();
285296
}
286297

287298
@Override
@@ -387,25 +398,27 @@ public JsonInclude.Include findSerializationInclusionForContent(JsonInclude.Incl
387398
@Override
388399
public AnnotatedMember findAnyGetter() throws IllegalArgumentException
389400
{
390-
if (_anyGetter != null) {
401+
AnnotatedMember anyGetter = (_propCollector == null) ? null
402+
: _propCollector.getAnyGetter();
403+
if (anyGetter != null) {
391404
/* For now let's require a Map; in future can add support for other
392405
* types like perhaps Iterable<Map.Entry>?
393406
*/
394-
Class<?> type = _anyGetter.getRawType();
407+
Class<?> type = anyGetter.getRawType();
395408
if (!Map.class.isAssignableFrom(type)) {
396-
throw new IllegalArgumentException("Invalid 'any-getter' annotation on method "+_anyGetter.getName()+"(): return type is not instance of java.util.Map");
409+
throw new IllegalArgumentException("Invalid 'any-getter' annotation on method "+anyGetter.getName()+"(): return type is not instance of java.util.Map");
397410
}
398411
}
399-
return _anyGetter;
412+
return anyGetter;
400413
}
401-
414+
402415
@Override
403416
public Map<String,AnnotatedMember> findBackReferenceProperties()
404417
{
405418
HashMap<String,AnnotatedMember> result = null;
406419
// boolean hasIgnored = (_ignoredPropertyNames != null);
407420

408-
for (BeanPropertyDefinition property : _properties) {
421+
for (BeanPropertyDefinition property : _properties()) {
409422
/* 23-Sep-2014, tatu: As per [Databind#426], we _should_ try to avoid
410423
* calling accessor, as it triggers exception from seeming conflict.
411424
* But the problem is that _ignoredPropertyNames here only contains
@@ -636,7 +649,7 @@ public LinkedHashMap<String,AnnotatedField> _findPropertyFields(
636649
Collection<String> ignoredProperties, boolean forSerialization)
637650
{
638651
LinkedHashMap<String,AnnotatedField> results = new LinkedHashMap<String,AnnotatedField>();
639-
for (BeanPropertyDefinition property : _properties) {
652+
for (BeanPropertyDefinition property : _properties()) {
640653
AnnotatedField f = property.getField();
641654
if (f != null) {
642655
String name = property.getName();

src/main/java/com/fasterxml/jackson/databind/introspect/BasicClassIntrospector.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ protected POJOPropertiesCollector collectProperties(MapperConfig<?> config,
194194
boolean useAnnotations = config.isAnnotationProcessingEnabled();
195195
AnnotatedClass ac = AnnotatedClass.construct(type.getRawClass(),
196196
(useAnnotations ? config.getAnnotationIntrospector() : null), r);
197-
return constructPropertyCollector(config, ac, type, forSerialization, mutatorPrefix).collect();
197+
return constructPropertyCollector(config, ac, type, forSerialization, mutatorPrefix);
198198
}
199199

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

211211
/**

0 commit comments

Comments
 (0)