1 package com.fasterxml.jackson.databind.deser;
2 
3 import java.util.*;
4 
5 import com.fasterxml.jackson.annotation.JsonFormat;
6 import com.fasterxml.jackson.databind.*;
7 import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
8 import com.fasterxml.jackson.databind.deser.impl.BeanPropertyMap;
9 import com.fasterxml.jackson.databind.deser.impl.ObjectIdValueProperty;
10 import com.fasterxml.jackson.databind.deser.impl.ObjectIdReader;
11 import com.fasterxml.jackson.databind.deser.impl.ValueInjector;
12 import com.fasterxml.jackson.databind.introspect.*;
13 import com.fasterxml.jackson.databind.util.Annotations;
14 import com.fasterxml.jackson.databind.util.ClassUtil;
15 import com.fasterxml.jackson.databind.util.IgnorePropertiesUtil;
16 
17 /**
18  * Builder class used for aggregating deserialization information about
19  * a POJO, in order to build a {@link JsonDeserializer} for deserializing
20  * instances.
21  */
22 public class BeanDeserializerBuilder
23 {
24     /*
25     /**********************************************************
26     /* Configuration
27     /**********************************************************
28      */
29 
30     final protected DeserializationConfig _config;
31 
32     /**
33      * @since 2.9
34      */
35     final protected DeserializationContext _context;
36 
37     /*
38     /**********************************************************
39     /* General information about POJO
40     /**********************************************************
41      */
42 
43     /**
44      * Introspected information about POJO for deserializer to handle
45      */
46     final protected BeanDescription _beanDesc;
47 
48     /*
49     /**********************************************************
50     /* Accumulated information about properties
51     /**********************************************************
52      */
53 
54     /**
55      * Properties to deserialize collected so far.
56      */
57     final protected Map<String, SettableBeanProperty> _properties
58         = new LinkedHashMap<String, SettableBeanProperty>();
59 
60     /**
61      * Value injectors for deserialization
62      */
63     protected List<ValueInjector> _injectables;
64 
65     /**
66      * Back-reference properties this bean contains (if any)
67      */
68     protected HashMap<String, SettableBeanProperty> _backRefProperties;
69 
70     /**
71      * Set of names of properties that are recognized but are to be ignored for deserialization
72      * purposes (meaning no exception is thrown, value is just skipped).
73      */
74     protected HashSet<String> _ignorableProps;
75 
76     /**
77      * Set of names of properties that are recognized and are set to be included for deserialization
78      * purposes (null deactivate this, empty includes nothing).
79      */
80     protected HashSet<String> _includableProps;
81 
82     /**
83      * Object that will handle value instantiation for the bean type.
84      */
85     protected ValueInstantiator _valueInstantiator;
86 
87     /**
88      * Handler for Object Id values, if Object Ids are enabled for the
89      * bean type.
90      */
91     protected ObjectIdReader _objectIdReader;
92 
93     /**
94      * Fallback setter used for handling any properties that are not
95      * mapped to regular setters. If setter is not null, it will be
96      * called once for each such property.
97      */
98     protected SettableAnyProperty _anySetter;
99 
100     /**
101      * Flag that can be set to ignore and skip unknown properties.
102      * If set, will not throw an exception for unknown properties.
103      */
104     protected boolean _ignoreAllUnknown;
105 
106     /**
107      * When creating Builder-based deserializers, this indicates
108      * method to call on builder to finalize value.
109      */
110     protected AnnotatedMethod _buildMethod;
111 
112     /**
113      * In addition, Builder may have additional configuration
114      */
115     protected JsonPOJOBuilder.Value _builderConfig;
116 
117     /*
118     /**********************************************************
119     /* Life-cycle: construction
120     /**********************************************************
121      */
122 
BeanDeserializerBuilder(BeanDescription beanDesc, DeserializationContext ctxt)123     public BeanDeserializerBuilder(BeanDescription beanDesc,
124             DeserializationContext ctxt)
125     {
126         _beanDesc = beanDesc;
127         _context = ctxt;
128         _config = ctxt.getConfig();
129     }
130 
131     /**
132      * Copy constructor for sub-classes to use, when constructing
133      * custom builder instances
134      */
BeanDeserializerBuilder(BeanDeserializerBuilder src)135     protected BeanDeserializerBuilder(BeanDeserializerBuilder src)
136     {
137         _beanDesc = src._beanDesc;
138         _context = src._context;
139         _config = src._config;
140 
141         // let's make copy of properties
142         _properties.putAll(src._properties);
143         _injectables = _copy(src._injectables);
144         _backRefProperties = _copy(src._backRefProperties);
145         // Hmmh. Should we create defensive copies here? For now, not yet
146         _ignorableProps = src._ignorableProps;
147         _includableProps = src._includableProps;
148         _valueInstantiator = src._valueInstantiator;
149         _objectIdReader = src._objectIdReader;
150 
151         _anySetter = src._anySetter;
152         _ignoreAllUnknown = src._ignoreAllUnknown;
153 
154         _buildMethod = src._buildMethod;
155         _builderConfig = src._builderConfig;
156     }
157 
_copy(HashMap<String, SettableBeanProperty> src)158     private static HashMap<String, SettableBeanProperty> _copy(HashMap<String, SettableBeanProperty> src) {
159         return (src == null) ? null
160                 : new HashMap<String, SettableBeanProperty>(src);
161     }
162 
_copy(List<T> src)163     private static <T> List<T> _copy(List<T> src) {
164         return (src == null) ? null : new ArrayList<T>(src);
165     }
166 
167     /*
168     /**********************************************************
169     /* Life-cycle: state modification (adders, setters)
170     /**********************************************************
171      */
172 
173     /**
174      * Method for adding a new property or replacing a property.
175      */
addOrReplaceProperty(SettableBeanProperty prop, boolean allowOverride)176     public void addOrReplaceProperty(SettableBeanProperty prop, boolean allowOverride) {
177         _properties.put(prop.getName(), prop);
178     }
179 
180     /**
181      * Method to add a property setter. Will ensure that there is no
182      * unexpected override; if one is found will throw a
183      * {@link IllegalArgumentException}.
184      */
addProperty(SettableBeanProperty prop)185     public void addProperty(SettableBeanProperty prop)
186     {
187         SettableBeanProperty old =  _properties.put(prop.getName(), prop);
188         if (old != null && old != prop) { // should never occur...
189             throw new IllegalArgumentException("Duplicate property '"+prop.getName()+"' for "+_beanDesc.getType());
190         }
191     }
192 
193     /**
194      * Method called to add a property that represents so-called back reference;
195      * reference that "points back" to object that has forward reference to
196      * currently built bean.
197      */
addBackReferenceProperty(String referenceName, SettableBeanProperty prop)198     public void  addBackReferenceProperty(String referenceName, SettableBeanProperty prop)
199     {
200         if (_backRefProperties == null) {
201             _backRefProperties = new HashMap<String, SettableBeanProperty>(4);
202         }
203         // 15-Sep-2016, tatu: For some reason fixing access at point of `build()` does
204         //    NOT work (2 failing unit tests). Not 100% clear why, but for now force
205         //    access set early; unfortunate, but since it works....
206         if (_config.canOverrideAccessModifiers()) {
207             prop.fixAccess(_config);
208         }
209         _backRefProperties.put(referenceName, prop);
210         // 16-Jan-2018, tatu: As per [databind#1878] we may want to leave it as is, to allow
211         //    population for cases of "wrong direction", traversing parent first
212         //   If this causes problems should probably instead include in "ignored properties" list
213         //   Alternatively could also extend annotation to allow/disallow explicit value from input
214         /*
215         if (_properties != null) {
216             _properties.remove(prop.getName());
217         }
218         */
219     }
220 
addInjectable(PropertyName propName, JavaType propType, Annotations contextAnnotations, AnnotatedMember member, Object valueId)221     public void addInjectable(PropertyName propName, JavaType propType,
222             Annotations contextAnnotations, AnnotatedMember member,
223             Object valueId)
224     {
225         if (_injectables == null) {
226             _injectables = new ArrayList<ValueInjector>();
227         }
228         if ( _config.canOverrideAccessModifiers()) {
229             member.fixAccess(_config.isEnabled(MapperFeature.OVERRIDE_PUBLIC_ACCESS_MODIFIERS));
230         }
231         _injectables.add(new ValueInjector(propName, propType, member, valueId));
232     }
233 
234     /**
235      * Method that will add property name as one of properties that can
236      * be ignored if not recognized.
237      */
addIgnorable(String propName)238     public void addIgnorable(String propName)
239     {
240         if (_ignorableProps == null) {
241             _ignorableProps = new HashSet<String>();
242         }
243         _ignorableProps.add(propName);
244     }
245 
246     /**
247      * Method that will add property name as one of the properties that will be included.
248      *
249      * @since 2.12
250      */
addIncludable(String propName)251     public void addIncludable(String propName)
252     {
253         if (_includableProps == null) {
254             _includableProps = new HashSet<>();
255         }
256         _includableProps.add(propName);
257     }
258 
259     /**
260      * Method called by deserializer factory, when a "creator property"
261      * (something that is passed via constructor- or factory method argument;
262      * instead of setter or field).
263      *<p>
264      * Default implementation does not do anything; we may need to revisit this
265      * decision if these properties need to be available through accessors.
266      * For now, however, we just have to ensure that we don't try to resolve
267      * types that masked setter/field has (see [JACKSON-700] for details).
268      */
addCreatorProperty(SettableBeanProperty prop)269     public void addCreatorProperty(SettableBeanProperty prop)
270     {
271         addProperty(prop);
272     }
273 
setAnySetter(SettableAnyProperty s)274     public void setAnySetter(SettableAnyProperty s)
275     {
276         if (_anySetter != null && s != null) {
277             throw new IllegalStateException("_anySetter already set to non-null");
278         }
279         _anySetter = s;
280     }
281 
setIgnoreUnknownProperties(boolean ignore)282     public void setIgnoreUnknownProperties(boolean ignore) {
283         _ignoreAllUnknown = ignore;
284     }
285 
setValueInstantiator(ValueInstantiator inst)286     public void setValueInstantiator(ValueInstantiator inst) {
287         _valueInstantiator = inst;
288     }
289 
setObjectIdReader(ObjectIdReader r)290     public void setObjectIdReader(ObjectIdReader r) {
291         _objectIdReader = r;
292     }
293 
setPOJOBuilder(AnnotatedMethod buildMethod, JsonPOJOBuilder.Value config)294     public void setPOJOBuilder(AnnotatedMethod buildMethod, JsonPOJOBuilder.Value config) {
295         _buildMethod = buildMethod;
296         _builderConfig = config;
297     }
298 
299     /*
300     /**********************************************************
301     /* Public accessors
302     /**********************************************************
303      */
304 
305     /**
306      * Method that allows accessing all properties that this
307      * builder currently contains.
308      *<p>
309      * Note that properties are returned in order that properties
310      * are ordered (explictly, or by rule), which is the serialization
311      * order.
312      */
getProperties()313     public Iterator<SettableBeanProperty> getProperties() {
314         return _properties.values().iterator();
315     }
316 
findProperty(PropertyName propertyName)317     public SettableBeanProperty findProperty(PropertyName propertyName) {
318         return _properties.get(propertyName.getSimpleName());
319     }
320 
hasProperty(PropertyName propertyName)321     public boolean hasProperty(PropertyName propertyName) {
322         return findProperty(propertyName) != null;
323     }
324 
removeProperty(PropertyName name)325     public SettableBeanProperty removeProperty(PropertyName name) {
326         return _properties.remove(name.getSimpleName());
327     }
328 
getAnySetter()329     public SettableAnyProperty getAnySetter() {
330         return _anySetter;
331     }
332 
getValueInstantiator()333     public ValueInstantiator getValueInstantiator() {
334         return _valueInstantiator;
335     }
336 
getInjectables()337     public List<ValueInjector> getInjectables() {
338         return _injectables;
339     }
340 
getObjectIdReader()341     public ObjectIdReader getObjectIdReader() {
342         return _objectIdReader;
343     }
344 
getBuildMethod()345     public AnnotatedMethod getBuildMethod() {
346     	return _buildMethod;
347     }
348 
getBuilderConfig()349     public JsonPOJOBuilder.Value getBuilderConfig() {
350         return _builderConfig;
351     }
352 
353     /**
354      * @since 2.9.4
355      */
hasIgnorable(String name)356     public boolean hasIgnorable(String name) {
357         return IgnorePropertiesUtil.shouldIgnore(name, _ignorableProps, _includableProps);
358     }
359 
360     /*
361     /**********************************************************
362     /* Build method(s)
363     /**********************************************************
364      */
365 
366     /**
367      * Method for constructing a {@link BeanDeserializer}, given all
368      * information collected.
369      */
build()370     public JsonDeserializer<?> build()
371     {
372         Collection<SettableBeanProperty> props = _properties.values();
373         _fixAccess(props);
374         BeanPropertyMap propertyMap = BeanPropertyMap.construct(_config, props,
375                 _collectAliases(props),
376                 _findCaseInsensitivity());
377         propertyMap.assignIndexes();
378 
379         // view processing must be enabled if:
380         // (a) fields are not included by default (when deserializing with view), OR
381         // (b) one of properties has view(s) to included in defined
382         boolean anyViews = !_config.isEnabled(MapperFeature.DEFAULT_VIEW_INCLUSION);
383         if (!anyViews) {
384             for (SettableBeanProperty prop : props) {
385                 if (prop.hasViews()) {
386                     anyViews = true;
387                     break;
388                 }
389             }
390         }
391 
392         // one more thing: may need to create virtual ObjectId property:
393         if (_objectIdReader != null) {
394             /* 18-Nov-2012, tatu: May or may not have annotations for id property;
395              *   but no easy access. But hard to see id property being optional,
396              *   so let's consider required at this point.
397              */
398             ObjectIdValueProperty prop = new ObjectIdValueProperty(_objectIdReader, PropertyMetadata.STD_REQUIRED);
399             propertyMap = propertyMap.withProperty(prop);
400         }
401 
402         return new BeanDeserializer(this,
403                 _beanDesc, propertyMap, _backRefProperties, _ignorableProps, _ignoreAllUnknown, _includableProps,
404                 anyViews);
405     }
406 
407     /**
408      * Alternate build method used when we must be using some form of
409      * abstract resolution, usually by using addition Type Id
410      * ("polymorphic deserialization")
411      *
412      * @since 2.0
413      */
buildAbstract()414     public AbstractDeserializer buildAbstract() {
415         return new AbstractDeserializer(this, _beanDesc, _backRefProperties, _properties);
416     }
417 
418     /**
419      * Method for constructing a specialized deserializer that uses
420      * additional external Builder object during data binding.
421      */
buildBuilderBased(JavaType valueType, String expBuildMethodName)422     public JsonDeserializer<?> buildBuilderBased(JavaType valueType, String expBuildMethodName)
423         throws JsonMappingException
424     {
425         // First: validation; must have build method that returns compatible type
426         if (_buildMethod == null) {
427             // as per [databind#777], allow empty name
428             if (!expBuildMethodName.isEmpty()) {
429                 _context.reportBadDefinition(_beanDesc.getType(),
430                         String.format("Builder class %s does not have build method (name: '%s')",
431                         ClassUtil.getTypeDescription(_beanDesc.getType()),
432                         expBuildMethodName));
433             }
434         } else {
435             // also: type of the method must be compatible
436             Class<?> rawBuildType = _buildMethod.getRawReturnType();
437             Class<?> rawValueType = valueType.getRawClass();
438             if ((rawBuildType != rawValueType)
439                     && !rawBuildType.isAssignableFrom(rawValueType)
440                     && !rawValueType.isAssignableFrom(rawBuildType)) {
441                 _context.reportBadDefinition(_beanDesc.getType(),
442                         String.format("Build method `%s` has wrong return type (%s), not compatible with POJO type (%s)",
443                         _buildMethod.getFullName(),
444                         ClassUtil.getClassDescription(rawBuildType),
445                         ClassUtil.getTypeDescription(valueType)));
446             }
447         }
448         // And if so, we can try building the deserializer
449         Collection<SettableBeanProperty> props = _properties.values();
450         _fixAccess(props);
451         BeanPropertyMap propertyMap = BeanPropertyMap.construct(_config, props,
452                 _collectAliases(props),
453                 _findCaseInsensitivity());
454         propertyMap.assignIndexes();
455 
456         boolean anyViews = !_config.isEnabled(MapperFeature.DEFAULT_VIEW_INCLUSION);
457 
458         if (!anyViews) {
459             for (SettableBeanProperty prop : props) {
460                 if (prop.hasViews()) {
461                     anyViews = true;
462                     break;
463                 }
464             }
465         }
466 
467         if (_objectIdReader != null) {
468             // May or may not have annotations for id property; but no easy access.
469             // But hard to see id property being optional, so let's consider required at this point.
470             ObjectIdValueProperty prop = new ObjectIdValueProperty(_objectIdReader,
471                     PropertyMetadata.STD_REQUIRED);
472             propertyMap = propertyMap.withProperty(prop);
473         }
474 
475         return createBuilderBasedDeserializer(valueType, propertyMap, anyViews);
476     }
477 
478     /**
479      * Extension point for overriding the actual creation of the builder deserializer.
480      *
481      * @since 2.11
482      */
createBuilderBasedDeserializer(JavaType valueType, BeanPropertyMap propertyMap, boolean anyViews)483     protected JsonDeserializer<?> createBuilderBasedDeserializer(JavaType valueType,
484             BeanPropertyMap propertyMap, boolean anyViews) {
485         return new BuilderBasedDeserializer(this,
486                 _beanDesc, valueType, propertyMap, _backRefProperties, _ignorableProps, _ignoreAllUnknown,
487                 _includableProps, anyViews);
488     }
489 
490     /*
491     /**********************************************************
492     /* Internal helper method(s)
493     /**********************************************************
494      */
495 
_fixAccess(Collection<SettableBeanProperty> mainProps)496     protected void _fixAccess(Collection<SettableBeanProperty> mainProps)
497     {
498         /* 07-Sep-2016, tatu: Ideally we should be able to avoid forcing
499          *   access to properties that are likely ignored, but due to
500          *   renaming it seems this is not a safe thing to do (there was
501          *   at least one failing test). May need to dig deeper in future;
502          *   for now let's just play it safe.
503          */
504         /*
505         Set<String> ignorable = _ignorableProps;
506         if (ignorable == null) {
507             ignorable = Collections.emptySet();
508         }
509         */
510 
511         // 17-Jun-2020, tatu: [databind#2760] means we should not force access
512         //   if we are not configured to... at least not "regular" properties
513 
514         if (_config.canOverrideAccessModifiers()) {
515             for (SettableBeanProperty prop : mainProps) {
516                 /*
517                 // first: no point forcing access on to-be-ignored properties
518                 if (ignorable.contains(prop.getName())) {
519                     continue;
520                 }
521                 */
522                 prop.fixAccess(_config);
523             }
524         }
525 
526         // 15-Sep-2016, tatu: Access via back-ref properties has been done earlier
527         //   as it has to, for some reason, so not repeated here.
528 /*
529         if (_backRefProperties != null) {
530             for (SettableBeanProperty prop : _backRefProperties.values()) {
531                 prop.fixAccess(_config);
532             }
533         }
534         */
535 
536         // 17-Jun-2020, tatu: Despite [databind#2760], it seems that methods that
537         //    are explicitly defined (any setter via annotation, builder too) can not
538         //    be left as-is? May reconsider based on feedback
539 
540         if (_anySetter != null) {
541             _anySetter.fixAccess(_config);
542         }
543         if (_buildMethod != null) {
544             _buildMethod.fixAccess(_config.isEnabled(MapperFeature.OVERRIDE_PUBLIC_ACCESS_MODIFIERS));
545         }
546     }
547 
_collectAliases(Collection<SettableBeanProperty> props)548     protected Map<String,List<PropertyName>> _collectAliases(Collection<SettableBeanProperty> props)
549     {
550         Map<String,List<PropertyName>> mapping = null;
551         AnnotationIntrospector intr = _config.getAnnotationIntrospector();
552         if (intr != null) {
553             for (SettableBeanProperty prop : props) {
554                 List<PropertyName> aliases = intr.findPropertyAliases(prop.getMember());
555                 if ((aliases == null) || aliases.isEmpty()) {
556                     continue;
557                 }
558                 if (mapping == null) {
559                     mapping = new HashMap<>();
560                 }
561                 mapping.put(prop.getName(), aliases);
562             }
563         }
564         if (mapping == null) {
565             return Collections.emptyMap();
566         }
567         return mapping;
568     }
569 
570     // @since 2.12
_findCaseInsensitivity()571     protected boolean _findCaseInsensitivity() {
572         // 07-May-2020, tatu: First find combination of per-type config overrides (higher
573         //   precedence) and per-type annotations (lower):
574         JsonFormat.Value format = _beanDesc.findExpectedFormat(null);
575         // and see if any of those has explicit definition; if not, use global baseline default
576         Boolean B = format.getFeature(JsonFormat.Feature.ACCEPT_CASE_INSENSITIVE_PROPERTIES);
577         return (B == null) ? _config.isEnabled(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES)
578                 : B.booleanValue();
579     }
580 }
581