1 package com.fasterxml.jackson.databind.deser;
2
3 import java.util.*;
4
5 import com.fasterxml.jackson.annotation.*;
6 import com.fasterxml.jackson.databind.*;
7 import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
8 import com.fasterxml.jackson.databind.cfg.DeserializerFactoryConfig;
9 import com.fasterxml.jackson.databind.deser.impl.*;
10 import com.fasterxml.jackson.databind.deser.std.ThrowableDeserializer;
11 import com.fasterxml.jackson.databind.exc.InvalidDefinitionException;
12 import com.fasterxml.jackson.databind.introspect.*;
13 import com.fasterxml.jackson.databind.jsontype.TypeDeserializer;
14 import com.fasterxml.jackson.databind.jsontype.impl.SubTypeValidator;
15 import com.fasterxml.jackson.databind.util.ClassUtil;
16 import com.fasterxml.jackson.databind.util.SimpleBeanPropertyDefinition;
17
18 /**
19  * Concrete deserializer factory class that adds full Bean deserializer
20  * construction logic using class introspection.
21  * Note that factories specifically do not implement any form of caching:
22  * aside from configuration they are stateless; caching is implemented
23  * by other components.
24  *<p>
25  * Instances of this class are fully immutable as all configuration is
26  * done by using "fluent factories" (methods that construct new factory
27  * instances with different configuration, instead of modifying instance).
28  */

29 public class BeanDeserializerFactory
30     extends BasicDeserializerFactory
31     implements java.io.Serializable // since 2.1
32 {
33     private static final long serialVersionUID = 1;
34
35     /**
36      * Signature of <b>Throwable.initCause</b> method.
37      */

38     private final static Class<?>[] INIT_CAUSE_PARAMS = new Class<?>[] { Throwable.class };
39
40     /*
41     /**********************************************************
42     /* Life-cycle
43     /**********************************************************
44      */

45     
46     /**
47      * Globally shareable thread-safe instance which has no additional custom deserializers
48      * registered
49      */

50     public final static BeanDeserializerFactory instance = new BeanDeserializerFactory(
51             new DeserializerFactoryConfig());
52
53     public BeanDeserializerFactory(DeserializerFactoryConfig config) {
54         super(config);
55     }
56     
57     /**
58      * Method used by module registration functionality, to construct a new bean
59      * deserializer factory
60      * with different configuration settings.
61      */

62     @Override
63     public DeserializerFactory withConfig(DeserializerFactoryConfig config)
64     {
65         if (_factoryConfig == config) {
66             return this;
67         }
68         /* 22-Nov-2010, tatu: Handling of subtypes is tricky if we do immutable-with-copy-ctor;
69          *    and we pretty much have to here either choose between losing subtype instance
70          *    when registering additional deserializers, or losing deserializers.
71          *    Instead, let's actually just throw an error if this method is called when subtype
72          *    has not properly overridden this method; this to indicate problem as soon as possible.
73          */

74         ClassUtil.verifyMustOverride(BeanDeserializerFactory.classthis"withConfig");
75         return new BeanDeserializerFactory(config);
76     }
77     
78     /*
79     /**********************************************************
80     /* DeserializerFactory API implementation
81     /**********************************************************
82      */

83
84     /**
85      * Method that {@link DeserializerCache}s call to create a new
86      * deserializer for types other than Collections, Maps, arrays and
87      * enums.
88      */

89     @SuppressWarnings("unchecked")
90     @Override
91     public JsonDeserializer<Object> createBeanDeserializer(DeserializationContext ctxt,
92             JavaType type, BeanDescription beanDesc)
93         throws JsonMappingException
94     {
95         final DeserializationConfig config = ctxt.getConfig();
96         // We may also have custom overrides:
97         JsonDeserializer<?> deser = _findCustomBeanDeserializer(type, config, beanDesc);
98         if (deser != null) {
99             // [databind#2392]
100             if (_factoryConfig.hasDeserializerModifiers()) {
101                 for (BeanDeserializerModifier mod : _factoryConfig.deserializerModifiers()) {
102                     deser = mod.modifyDeserializer(ctxt.getConfig(), beanDesc, deser);
103                 }
104             }
105             return (JsonDeserializer<Object>) deser;
106         }
107         /* One more thing to check: do we have an exception type
108          * (Throwable or its sub-classes)? If so, need slightly
109          * different handling.
110          */

111         if (type.isThrowable()) {
112             return buildThrowableDeserializer(ctxt, type, beanDesc);
113         }
114         // Or, for abstract types, may have alternate means for resolution
115         // (defaulting, materialization)
116
117         // 29-Nov-2015, tatu: Also, filter out calls to primitive types, they are
118         //    not something we could materialize anything for
119         if (type.isAbstract() && !type.isPrimitive() && !type.isEnumType()) {
120             // Let's make it possible to materialize abstract types.
121             JavaType concreteType = materializeAbstractType(ctxt, type, beanDesc);
122             if (concreteType != null) {
123                 /* important: introspect actual implementation (abstract class or
124                  * interface doesn't have constructors, for one)
125                  */

126                 beanDesc = config.introspect(concreteType);
127                 return buildBeanDeserializer(ctxt, concreteType, beanDesc);
128             }
129         }
130         // Otherwise, may want to check handlers for standard types, from superclass:
131         deser = findStdDeserializer(ctxt, type, beanDesc);
132         if (deser != null) {
133             return (JsonDeserializer<Object>)deser;
134         }
135
136         // Otherwise: could the class be a Bean class? If not, bail out
137         if (!isPotentialBeanType(type.getRawClass())) {
138             return null;
139         }
140         // For checks like [databind#1599]
141         _validateSubType(ctxt, type, beanDesc);
142         // Use generic bean introspection to build deserializer
143         return buildBeanDeserializer(ctxt, type, beanDesc);
144     }
145
146     @Override
147     public JsonDeserializer<Object> createBuilderBasedDeserializer(DeserializationContext ctxt,
148             JavaType valueType, BeanDescription beanDesc, Class<?> builderClass)
149                     throws JsonMappingException
150     {
151         // First: need a BeanDescription for builder class
152         JavaType builderType = ctxt.constructType(builderClass);
153         BeanDescription builderDesc = ctxt.getConfig().introspectForBuilder(builderType);
154         return buildBuilderBasedDeserializer(ctxt, valueType, builderDesc);
155     }
156
157     /**
158      * Method called by {@link BeanDeserializerFactory} to see if there might be a standard
159      * deserializer registered for given type.
160      */

161     protected JsonDeserializer<?> findStdDeserializer(DeserializationContext ctxt,
162             JavaType type, BeanDescription beanDesc)
163         throws JsonMappingException
164     {
165         // note: we do NOT check for custom deserializers here, caller has already
166         // done that
167         JsonDeserializer<?> deser = findDefaultDeserializer(ctxt, type, beanDesc);
168         // Also: better ensure these are post-processable?
169         if (deser != null) {
170             if (_factoryConfig.hasDeserializerModifiers()) {
171                 for (BeanDeserializerModifier mod : _factoryConfig.deserializerModifiers()) {
172                     deser = mod.modifyDeserializer(ctxt.getConfig(), beanDesc, deser);
173                 }
174             }
175         }
176         return deser;
177     }
178     
179     protected JavaType materializeAbstractType(DeserializationContext ctxt,
180             JavaType type, BeanDescription beanDesc)
181         throws JsonMappingException
182     {
183         // May have multiple resolvers, call in precedence order until one returns non-null
184         for (AbstractTypeResolver r : _factoryConfig.abstractTypeResolvers()) {
185             JavaType concrete = r.resolveAbstractType(ctxt.getConfig(), beanDesc);
186             if (concrete != null) {
187                 return concrete;
188             }
189         }
190         return null;
191     }
192
193     /*
194     /**********************************************************
195     /* Public construction method beyond DeserializerFactory API:
196     /* can be called from outside as well as overridden by
197     /* sub-classes
198     /**********************************************************
199      */

200
201     /**
202      * Method that is to actually build a bean deserializer instance.
203      * All basic sanity checks have been done to know that what we have
204      * may be a valid bean type, and that there are no default simple
205      * deserializers.
206      */

207     @SuppressWarnings("unchecked")
208     public JsonDeserializer<Object> buildBeanDeserializer(DeserializationContext ctxt,
209             JavaType type, BeanDescription beanDesc)
210         throws JsonMappingException
211     {
212         // First: check what creators we can use, if any
213         ValueInstantiator valueInstantiator;
214         /* 04-Jun-2015, tatu: To work around [databind#636], need to catch the
215          *    issue, defer; this seems like a reasonable good place for now.
216          *   Note, however, that for non-Bean types (Collections, Maps) this
217          *   probably won't work and needs to be added elsewhere.
218          */

219         try {
220             valueInstantiator = findValueInstantiator(ctxt, beanDesc);
221         } catch (NoClassDefFoundError error) {
222             return new ErrorThrowingDeserializer(error);
223         } catch (IllegalArgumentException e) {
224             // 05-Apr-2017, tatu: Although it might appear cleaner to require collector
225             //   to throw proper exception, it doesn't actually have reference to this
226             //   instance so...
227             throw InvalidDefinitionException.from(ctxt.getParser(),
228                     ClassUtil.exceptionMessage(e),
229                     beanDesc, null);
230         }
231         BeanDeserializerBuilder builder = constructBeanDeserializerBuilder(ctxt, beanDesc);
232         builder.setValueInstantiator(valueInstantiator);
233          // And then setters for deserializing from JSON Object
234         addBeanProps(ctxt, beanDesc, builder);
235         addObjectIdReader(ctxt, beanDesc, builder);
236
237         // managed/back reference fields/setters need special handling... first part
238         addBackReferenceProperties(ctxt, beanDesc, builder);
239         addInjectables(ctxt, beanDesc, builder);
240         
241         final DeserializationConfig config = ctxt.getConfig();
242         if (_factoryConfig.hasDeserializerModifiers()) {
243             for (BeanDeserializerModifier mod : _factoryConfig.deserializerModifiers()) {
244                 builder = mod.updateBuilder(config, beanDesc, builder);
245             }
246         }
247         JsonDeserializer<?> deserializer;
248
249         if (type.isAbstract() && !valueInstantiator.canInstantiate()) {
250             deserializer = builder.buildAbstract();
251         } else {
252             deserializer = builder.build();
253         }
254         // may have modifier(s) that wants to modify or replace serializer we just built
255         // (note that `resolve()` and `createContextual()` called later on)
256         if (_factoryConfig.hasDeserializerModifiers()) {
257             for (BeanDeserializerModifier mod : _factoryConfig.deserializerModifiers()) {
258                 deserializer = mod.modifyDeserializer(config, beanDesc, deserializer);
259             }
260         }
261         return (JsonDeserializer<Object>) deserializer;
262     }
263     
264     /**
265      * Method for constructing a bean deserializer that uses specified
266      * intermediate Builder for binding data, and construction of the
267      * value instance.
268      * Note that implementation is mostly copied from the regular
269      * BeanDeserializer build method.
270      */

271     @SuppressWarnings("unchecked")
272     protected JsonDeserializer<Object> buildBuilderBasedDeserializer(
273             DeserializationContext ctxt, JavaType valueType, BeanDescription builderDesc)
274         throws JsonMappingException
275     {
276         // Creators, anyone? (to create builder itself)
277         ValueInstantiator valueInstantiator;
278         try {
279             valueInstantiator = findValueInstantiator(ctxt, builderDesc);
280         } catch (NoClassDefFoundError error) {
281             return new ErrorThrowingDeserializer(error);
282         } catch (IllegalArgumentException e) {
283             // 05-Apr-2017, tatu: Although it might appear cleaner to require collector
284             //   to throw proper exception, it doesn't actually have reference to this
285             //   instance so...
286             throw InvalidDefinitionException.from(ctxt.getParser(),
287                     ClassUtil.exceptionMessage(e),
288                     builderDesc, null);
289         }
290         final DeserializationConfig config = ctxt.getConfig();
291         BeanDeserializerBuilder builder = constructBeanDeserializerBuilder(ctxt, builderDesc);
292         builder.setValueInstantiator(valueInstantiator);
293          // And then "with methods" for deserializing from JSON Object
294         addBeanProps(ctxt, builderDesc, builder);
295         addObjectIdReader(ctxt, builderDesc, builder);
296         
297         // managed/back reference fields/setters need special handling... first part
298         addBackReferenceProperties(ctxt, builderDesc, builder);
299         addInjectables(ctxt, builderDesc, builder);
300
301         JsonPOJOBuilder.Value builderConfig = builderDesc.findPOJOBuilderConfig();
302         final String buildMethodName = (builderConfig == null) ?
303                 JsonPOJOBuilder.DEFAULT_BUILD_METHOD : builderConfig.buildMethodName;
304         
305         // and lastly, find build method to use:
306         AnnotatedMethod buildMethod = builderDesc.findMethod(buildMethodName, null);
307         if (buildMethod != null) { // note: can't yet throw error; may be given build method
308             if (config.canOverrideAccessModifiers()) {
309                 ClassUtil.checkAndFixAccess(buildMethod.getMember(), config.isEnabled(MapperFeature.OVERRIDE_PUBLIC_ACCESS_MODIFIERS));
310             }
311         }
312         builder.setPOJOBuilder(buildMethod, builderConfig);
313         // this may give us more information...
314         if (_factoryConfig.hasDeserializerModifiers()) {
315             for (BeanDeserializerModifier mod : _factoryConfig.deserializerModifiers()) {
316                 builder = mod.updateBuilder(config, builderDesc, builder);
317             }
318         }
319         JsonDeserializer<?> deserializer = builder.buildBuilderBased(
320                 valueType, buildMethodName);
321
322         // [JACKSON-440]: may have modifier(s) that wants to modify or replace serializer we just built:
323         if (_factoryConfig.hasDeserializerModifiers()) {
324             for (BeanDeserializerModifier mod : _factoryConfig.deserializerModifiers()) {
325                 deserializer = mod.modifyDeserializer(config, builderDesc, deserializer);
326             }
327         }
328         return (JsonDeserializer<Object>) deserializer;
329     }
330     
331     protected void addObjectIdReader(DeserializationContext ctxt,
332             BeanDescription beanDesc, BeanDeserializerBuilder builder)
333         throws JsonMappingException
334     {
335         ObjectIdInfo objectIdInfo = beanDesc.getObjectIdInfo();
336         if (objectIdInfo == null) {
337             return;
338         }
339         Class<?> implClass = objectIdInfo.getGeneratorType();
340         JavaType idType;
341         SettableBeanProperty idProp;
342         ObjectIdGenerator<?> gen;
343
344         ObjectIdResolver resolver = ctxt.objectIdResolverInstance(beanDesc.getClassInfo(), objectIdInfo);
345
346         // Just one special case: Property-based generator is trickier
347         if (implClass == ObjectIdGenerators.PropertyGenerator.class) { // most special one, needs extra work
348             PropertyName propName = objectIdInfo.getPropertyName();
349             idProp = builder.findProperty(propName);
350             if (idProp == null) {
351                 throw new IllegalArgumentException("Invalid Object Id definition for "
352                         +beanDesc.getBeanClass().getName()+": cannot find property with name '"+propName+"'");
353             }
354             idType = idProp.getType();
355             gen = new PropertyBasedObjectIdGenerator(objectIdInfo.getScope());
356         } else {
357             JavaType type = ctxt.constructType(implClass);
358             idType = ctxt.getTypeFactory().findTypeParameters(type, ObjectIdGenerator.class)[0];
359             idProp = null;
360             gen = ctxt.objectIdGeneratorInstance(beanDesc.getClassInfo(), objectIdInfo);
361         }
362         // also: unlike with value deserializers, let's just resolve one we need here
363         JsonDeserializer<?> deser = ctxt.findRootValueDeserializer(idType);
364         builder.setObjectIdReader(ObjectIdReader.construct(idType,
365                 objectIdInfo.getPropertyName(), gen, deser, idProp, resolver));
366     }
367     
368     @SuppressWarnings("unchecked")
369     public JsonDeserializer<Object> buildThrowableDeserializer(DeserializationContext ctxt,
370             JavaType type, BeanDescription beanDesc)
371         throws JsonMappingException
372     {
373         final DeserializationConfig config = ctxt.getConfig();
374         // first: construct like a regular bean deserializer...
375         BeanDeserializerBuilder builder = constructBeanDeserializerBuilder(ctxt, beanDesc);
376         builder.setValueInstantiator(findValueInstantiator(ctxt, beanDesc));
377
378         addBeanProps(ctxt, beanDesc, builder);
379         // (and assume there won't be any back references)
380
381         // But then let's decorate things a bit
382         // Need to add "initCause" as setter for exceptions (sub-classes of Throwable).
383         AnnotatedMethod am = beanDesc.findMethod("initCause", INIT_CAUSE_PARAMS);
384         if (am != null) { // should never be null
385             SimpleBeanPropertyDefinition propDef = SimpleBeanPropertyDefinition.construct(ctxt.getConfig(), am,
386                     new PropertyName("cause"));
387             SettableBeanProperty prop = constructSettableProperty(ctxt, beanDesc, propDef,
388                     am.getParameterType(0));
389             if (prop != null) {
390                 // 21-Aug-2011, tatus: We may actually have found 'cause' property
391                 //   to set... but let's replace it just in case, otherwise can end up with odd errors.
392                 builder.addOrReplaceProperty(prop, true);
393             }
394         }
395
396         // And also need to ignore "localizedMessage"
397         builder.addIgnorable("localizedMessage");
398         // Java 7 also added "getSuppressed", skip if we have such data:
399         builder.addIgnorable("suppressed");
400         // As well as "message": it will be passed via constructor,
401         // as there's no 'setMessage()' method
402         // 23-Jan-2018, tatu: ... although there MAY be Creator Property... which is problematic
403 //        builder.addIgnorable("message");
404
405         // update builder now that all information is in?
406         if (_factoryConfig.hasDeserializerModifiers()) {
407             for (BeanDeserializerModifier mod : _factoryConfig.deserializerModifiers()) {
408                 builder = mod.updateBuilder(config, beanDesc, builder);
409             }
410         }
411         JsonDeserializer<?> deserializer = builder.build();
412         
413         /* At this point it ought to be a BeanDeserializer; if not, must assume
414          * it's some other thing that can handle deserialization ok...
415          */

416         if (deserializer instanceof BeanDeserializer) {
417             deserializer = new ThrowableDeserializer((BeanDeserializer) deserializer);
418         }
419
420         // may have modifier(s) that wants to modify or replace serializer we just built:
421         if (_factoryConfig.hasDeserializerModifiers()) {
422             for (BeanDeserializerModifier mod : _factoryConfig.deserializerModifiers()) {
423                 deserializer = mod.modifyDeserializer(config, beanDesc, deserializer);
424             }
425         }
426         return (JsonDeserializer<Object>) deserializer;
427     }
428
429     /*
430     /**********************************************************
431     /* Helper methods for Bean deserializer construction,
432     /* overridable by sub-classes
433     /**********************************************************
434      */

435
436     /**
437      * Overridable method that constructs a {@link BeanDeserializerBuilder}
438      * which is used to accumulate information needed to create deserializer
439      * instance.
440      */

441     protected BeanDeserializerBuilder constructBeanDeserializerBuilder(DeserializationContext ctxt,
442             BeanDescription beanDesc) {
443         return new BeanDeserializerBuilder(beanDesc, ctxt);
444     }
445     
446     /**
447      * Method called to figure out settable properties for the
448      * bean deserializer to use.
449      *<p>
450      * Note: designed to be overridable, and effort is made to keep interface
451      * similar between versions.
452      */

453     protected void addBeanProps(DeserializationContext ctxt,
454             BeanDescription beanDesc, BeanDeserializerBuilder builder)
455         throws JsonMappingException
456     {
457         final boolean isConcrete = !beanDesc.getType().isAbstract();
458         final SettableBeanProperty[] creatorProps = isConcrete
459                 ? builder.getValueInstantiator().getFromObjectArguments(ctxt.getConfig())
460                 : null;
461         final boolean hasCreatorProps = (creatorProps != null);
462
463         // 01-May-2016, tatu: Which base type to use here gets tricky, since
464         //   it may often make most sense to use general type for overrides,
465         //   but what we have here may be more specific impl type. But for now
466         //   just use it as is.
467         JsonIgnoreProperties.Value ignorals = ctxt.getConfig()
468                 .getDefaultPropertyIgnorals(beanDesc.getBeanClass(),
469                         beanDesc.getClassInfo());
470         Set<String> ignored;
471         if (ignorals != null) {
472             boolean ignoreAny = ignorals.getIgnoreUnknown();
473             builder.setIgnoreUnknownProperties(ignoreAny);
474             // Or explicit/implicit definitions?
475             ignored = ignorals.findIgnoredForDeserialization();
476             for (String propName : ignored) {
477                 builder.addIgnorable(propName);
478             }
479         } else {
480             ignored = Collections.emptySet();
481         }
482
483         // Also, do we have a fallback "any" setter?
484         AnnotatedMember anySetter = beanDesc.findAnySetterAccessor();
485         if (anySetter != null) {
486             builder.setAnySetter(constructAnySetter(ctxt, beanDesc, anySetter));
487         } else {
488             // 23-Jan-2018, tatu: although [databind#1805] would suggest we should block
489             //   properties regardless, for now only consider unless there's any setter...
490             Collection<String> ignored2 = beanDesc.getIgnoredPropertyNames();
491             if (ignored2 != null) {
492                 for (String propName : ignored2) {
493                     // allow ignoral of similarly named JSON property, but do not force;
494                     // latter means NOT adding this to 'ignored':
495                     builder.addIgnorable(propName);
496                 }
497             }
498         }
499         final boolean useGettersAsSetters = ctxt.isEnabled(MapperFeature.USE_GETTERS_AS_SETTERS)
500                 && ctxt.isEnabled(MapperFeature.AUTO_DETECT_GETTERS);
501
502         // Ok: let's then filter out property definitions
503         List<BeanPropertyDefinition> propDefs = filterBeanProps(ctxt,
504                 beanDesc, builder, beanDesc.findProperties(), ignored);
505         // After which we can let custom code change the set
506         if (_factoryConfig.hasDeserializerModifiers()) {
507             for (BeanDeserializerModifier mod : _factoryConfig.deserializerModifiers()) {
508                 propDefs = mod.updateProperties(ctxt.getConfig(), beanDesc, propDefs);
509             }
510         }
511
512         // At which point we still have all kinds of properties; not all with mutators:
513         for (BeanPropertyDefinition propDef : propDefs) {
514             SettableBeanProperty prop = null;
515             
516             // 18-Oct-2013, tatu: Although constructor parameters have highest precedence,
517             //   we need to do linkage (as per [databind#318]), and so need to start with
518             //   other types, and only then create constructor parameter, if any.
519             if (propDef.hasSetter()) {
520                 AnnotatedMethod setter = propDef.getSetter();
521                 JavaType propertyType = setter.getParameterType(0);
522                 prop = constructSettableProperty(ctxt, beanDesc, propDef, propertyType);
523             } else if (propDef.hasField()) {
524                 AnnotatedField field = propDef.getField();
525                 JavaType propertyType = field.getType();
526                 prop = constructSettableProperty(ctxt, beanDesc, propDef, propertyType);
527             } else {
528                 // NOTE: specifically getter, since field was already checked above
529                 AnnotatedMethod getter = propDef.getGetter();
530                 if (getter != null) {
531                     if (useGettersAsSetters && _isSetterlessType(getter.getRawType())) {
532                         // 23-Jan-2018, tatu: As per [databind#1805], need to ensure we don't
533                         //   accidentally sneak in getter-as-setter for `READ_ONLY` properties
534                         if (builder.hasIgnorable(propDef.getName())) {
535                             ;
536                         } else {
537                             prop = constructSetterlessProperty(ctxt, beanDesc, propDef);
538                         }
539                     } else if (!propDef.hasConstructorParameter()) {
540                         PropertyMetadata md = propDef.getMetadata();
541                         // 25-Oct-2016, tatu: If merging enabled, might not need setter.
542                         //   We cannot quite support this with creator parameters; in theory
543                         //   possibly, but right not not due to complexities of routing, so
544                         //   just prevent
545                         if (md.getMergeInfo() != null) {
546                             prop = constructSetterlessProperty(ctxt, beanDesc, propDef);
547                         }
548                     }
549                 }
550             }
551
552             // 25-Sep-2014, tatu: No point in finding constructor parameters for abstract types
553             //   (since they are never used anyway)
554             if (hasCreatorProps && propDef.hasConstructorParameter()) {
555                 /* If property is passed via constructor parameter, we must
556                  * handle things in special way. Not sure what is the most optimal way...
557                  * for now, let's just call a (new) method in builder, which does nothing.
558                  */

559                 // but let's call a method just to allow custom builders to be aware...
560                 final String name = propDef.getName();
561                 CreatorProperty cprop = null;
562                 if (creatorProps != null) {
563                     for (SettableBeanProperty cp : creatorProps) {
564                         if (name.equals(cp.getName()) && (cp instanceof CreatorProperty)) {
565                             cprop = (CreatorProperty) cp;
566                             break;
567                         }
568                     }
569                 }
570                 if (cprop == null) {
571                     List<String> n = new ArrayList<>();
572                     for (SettableBeanProperty cp : creatorProps) {
573                         n.add(cp.getName());
574                     }
575                     ctxt.reportBadPropertyDefinition(beanDesc, propDef,
576                             "Could not find creator property with name '%s' (known Creator properties: %s)",
577                             name, n);
578                     continue;
579                 }
580                 if (prop != null) {
581                     cprop.setFallbackSetter(prop);
582                 }
583                 Class<?>[] views = propDef.findViews();
584                 if (views == null) {
585                     views = beanDesc.findDefaultViews();
586                 }
587                 cprop.setViews(views);
588                 builder.addCreatorProperty(cprop);
589                 continue;
590             }
591             if (prop != null) {
592                 // one more thing before adding to builder: copy any metadata
593                 Class<?>[] views = propDef.findViews();
594                 if (views == null) {
595                     views = beanDesc.findDefaultViews();
596                 }
597                 prop.setViews(views);
598                 builder.addProperty(prop);
599             }
600         }
601     }
602
603     private boolean _isSetterlessType(Class<?> rawType) {
604         // May also need to consider getters
605         // for Map/Collection properties; but with lowest precedence
606         // should only consider Collections and Maps, for now?
607         return Collection.class.isAssignableFrom(rawType)
608                 || Map.class.isAssignableFrom(rawType);
609     }
610
611     /**
612      * Helper method called to filter out explicit ignored properties,
613      * as well as properties that have "ignorable types".
614      * Note that this will not remove properties that have no
615      * setters.
616      */

617     protected List<BeanPropertyDefinition> filterBeanProps(DeserializationContext ctxt,
618             BeanDescription beanDesc, BeanDeserializerBuilder builder,
619             List<BeanPropertyDefinition> propDefsIn,
620             Set<String> ignored)
621         throws JsonMappingException
622     {
623         ArrayList<BeanPropertyDefinition> result = new ArrayList<BeanPropertyDefinition>(
624                 Math.max(4, propDefsIn.size()));
625         HashMap<Class<?>,Boolean> ignoredTypes = new HashMap<Class<?>,Boolean>();
626         // These are all valid setters, but we do need to introspect bit more
627         for (BeanPropertyDefinition property : propDefsIn) {
628             String name = property.getName();
629             if (ignored.contains(name)) { // explicit ignoral using @JsonIgnoreProperties needs to block entries
630                 continue;
631             }
632             if (!property.hasConstructorParameter()) { // never skip constructor params
633                 Class<?> rawPropertyType = property.getRawPrimaryType();
634                 // Some types are declared as ignorable as well
635                 if ((rawPropertyType != null)
636                         && isIgnorableType(ctxt.getConfig(), property, rawPropertyType, ignoredTypes)) {
637                     // important: make ignorable, to avoid errors if value is actually seen
638                     builder.addIgnorable(name);
639                     continue;
640                 }
641             }
642             result.add(property);
643         }
644         return result;
645     }
646
647     /**
648      * Method that will find if bean has any managed- or back-reference properties,
649      * and if so add them to bean, to be linked during resolution phase.
650      *
651      * @since 2.9
652      */

653     protected void addBackReferenceProperties(DeserializationContext ctxt,
654             BeanDescription beanDesc, BeanDeserializerBuilder builder)
655         throws JsonMappingException
656     {
657         // and then back references, not necessarily found as regular properties
658         List<BeanPropertyDefinition> refProps = beanDesc.findBackReferences();
659         if (refProps != null) {
660             for (BeanPropertyDefinition refProp : refProps) {
661                 /*
662                 AnnotatedMember m = refProp.getMutator();
663                 JavaType type;
664                 if (m instanceof AnnotatedMethod) {
665                     type = ((AnnotatedMethod) m).getParameterType(0);
666                 } else {
667                     type = m.getType();
668                     // 30-Mar-2017, tatu: Unfortunately it is not yet possible to make back-refs
669                     //    work through constructors; but let's at least indicate the issue for now
670                     if (m instanceof AnnotatedParameter) {
671                         ctxt.reportBadTypeDefinition(beanDesc,
672 "Cannot bind back reference using Creator parameter (reference '%s', parameter index #%d)",
673 name, ((AnnotatedParameter) m).getIndex());
674                     }
675                 }
676                 */

677                 String refName = refProp.findReferenceName();
678                 builder.addBackReferenceProperty(refName, constructSettableProperty(ctxt,
679                         beanDesc, refProp, refProp.getPrimaryType()));
680             }
681         }
682     }
683
684     @Deprecated // since 2.9 (rename)
685     protected void addReferenceProperties(DeserializationContext ctxt,
686             BeanDescription beanDesc, BeanDeserializerBuilder builder)
687         throws JsonMappingException
688     {
689         addBackReferenceProperties(ctxt, beanDesc, builder);
690     }
691
692     /**
693      * Method called locate all members used for value injection (if any),
694      * constructor {@link com.fasterxml.jackson.databind.deser.impl.ValueInjector} instances, and add them to builder.
695      */

696     protected void addInjectables(DeserializationContext ctxt,
697             BeanDescription beanDesc, BeanDeserializerBuilder builder)
698         throws JsonMappingException
699     {
700         Map<Object, AnnotatedMember> raw = beanDesc.findInjectables();
701         if (raw != null) {
702             for (Map.Entry<Object, AnnotatedMember> entry : raw.entrySet()) {
703                 AnnotatedMember m = entry.getValue();
704                 builder.addInjectable(PropertyName.construct(m.getName()),
705                         m.getType(),
706                         beanDesc.getClassAnnotations(), m, entry.getKey());
707             }
708         }
709     }
710
711     /**
712      * Method called to construct fallback {@link SettableAnyProperty}
713      * for handling unknown bean properties, given a method that
714      * has been designated as such setter.
715      * 
716      * @param mutator Either 2-argument method (setter, with key and value), or Field
717      *     that contains Map; either way accessor used for passing "any values"
718      */

719     @SuppressWarnings("unchecked")
720     protected SettableAnyProperty constructAnySetter(DeserializationContext ctxt,
721             BeanDescription beanDesc, AnnotatedMember mutator)
722         throws JsonMappingException
723     {
724         //find the java type based on the annotated setter method or setter field 
725         BeanProperty prop;
726         JavaType keyType;
727         JavaType valueType;
728
729         if (mutator instanceof AnnotatedMethod) {
730             // we know it's a 2-arg method, second arg is the value
731             AnnotatedMethod am = (AnnotatedMethod) mutator;
732             keyType = am.getParameterType(0);
733             valueType = am.getParameterType(1);
734             valueType = resolveMemberAndTypeAnnotations(ctxt, mutator, valueType);
735             prop = new BeanProperty.Std(PropertyName.construct(mutator.getName()),
736                     valueType, null, mutator,
737                     PropertyMetadata.STD_OPTIONAL);
738
739         } else if (mutator instanceof AnnotatedField) {
740             AnnotatedField af = (AnnotatedField) mutator;
741             // get the type from the content type of the map object
742             JavaType mapType = af.getType();
743             mapType = resolveMemberAndTypeAnnotations(ctxt, mutator, mapType);
744             keyType = mapType.getKeyType();
745             valueType = mapType.getContentType();
746             prop = new BeanProperty.Std(PropertyName.construct(mutator.getName()),
747                     mapType, null, mutator, PropertyMetadata.STD_OPTIONAL);
748         } else {
749             return ctxt.reportBadDefinition(beanDesc.getType(), String.format(
750                     "Unrecognized mutator type for any setter: %s", mutator.getClass()));
751         }
752         // First: see if there are explicitly specified 
753         // and then possible direct deserializer override on accessor
754         KeyDeserializer keyDeser = findKeyDeserializerFromAnnotation(ctxt, mutator);
755         if (keyDeser == null) {
756             keyDeser = keyType.getValueHandler();
757         }
758         if (keyDeser == null) {
759             keyDeser = ctxt.findKeyDeserializer(keyType, prop);
760         } else {
761             if (keyDeser instanceof ContextualKeyDeserializer) {
762                 keyDeser = ((ContextualKeyDeserializer) keyDeser)
763                         .createContextual(ctxt, prop);
764             }
765         }
766         JsonDeserializer<Object> deser = findContentDeserializerFromAnnotation(ctxt, mutator);
767         if (deser == null) {
768             deser = valueType.getValueHandler();
769         }
770         if (deser != null) {
771             // As per [databind#462] need to ensure we contextualize deserializer before passing it on
772             deser = (JsonDeserializer<Object>) ctxt.handlePrimaryContextualization(deser, prop, valueType);
773         }
774         TypeDeserializer typeDeser = valueType.getTypeHandler();
775         return new SettableAnyProperty(prop, mutator, valueType,
776                 keyDeser, deser, typeDeser);
777     }
778
779     /**
780      * Method that will construct a regular bean property setter using
781      * the given setter method.
782      *
783      * @return Property constructed, if any; or null to indicate that
784      *   there should be no property based on given definitions.
785      */

786     protected SettableBeanProperty constructSettableProperty(DeserializationContext ctxt,
787             BeanDescription beanDesc, BeanPropertyDefinition propDef,
788             JavaType propType0)
789         throws JsonMappingException
790     {
791         // need to ensure method is callable (for non-public)
792         AnnotatedMember mutator = propDef.getNonConstructorMutator();
793         // 08-Sep-2016, tatu: issues like [databind#1342] suggest something fishy
794         //   going on; add sanity checks to try to pin down actual problem...
795         //   Possibly passing creator parameter?
796         if (mutator == null) {
797             ctxt.reportBadPropertyDefinition(beanDesc, propDef, "No non-constructor mutator available");
798         }
799         JavaType type = resolveMemberAndTypeAnnotations(ctxt, mutator, propType0);
800         // Does the Method specify the deserializer to use? If so, let's use it.
801         TypeDeserializer typeDeser = type.getTypeHandler();
802         SettableBeanProperty prop;
803         if (mutator instanceof AnnotatedMethod) {
804             prop = new MethodProperty(propDef, type, typeDeser,
805                     beanDesc.getClassAnnotations(), (AnnotatedMethod) mutator);
806         } else {
807             // 08-Sep-2016, tatu: wonder if we should verify it is `AnnotatedField` to be safe?
808             prop = new FieldProperty(propDef, type, typeDeser,
809                     beanDesc.getClassAnnotations(), (AnnotatedField) mutator);
810         }
811         JsonDeserializer<?> deser = findDeserializerFromAnnotation(ctxt, mutator);
812         if (deser == null) {
813             deser = type.getValueHandler();
814         }
815         if (deser != null) {
816             deser = ctxt.handlePrimaryContextualization(deser, prop, type);
817             prop = prop.withValueDeserializer(deser);
818         }
819         // need to retain name of managed forward references:
820         AnnotationIntrospector.ReferenceProperty ref = propDef.findReferenceType();
821         if (ref != null && ref.isManagedReference()) {
822             prop.setManagedReferenceName(ref.getName());
823         }
824         ObjectIdInfo objectIdInfo = propDef.findObjectIdInfo();
825         if (objectIdInfo != null){
826             prop.setObjectIdInfo(objectIdInfo);
827         }
828         return prop;
829     }
830
831     /**
832      * Method that will construct a regular bean property setter using
833      * the given setter method.
834      */

835     protected SettableBeanProperty constructSetterlessProperty(DeserializationContext ctxt,
836             BeanDescription beanDesc, BeanPropertyDefinition propDef)
837         throws JsonMappingException
838     {
839         final AnnotatedMethod getter = propDef.getGetter();
840         JavaType type = resolveMemberAndTypeAnnotations(ctxt, getter, getter.getType());
841         TypeDeserializer typeDeser = type.getTypeHandler();
842         SettableBeanProperty prop = new SetterlessProperty(propDef, type, typeDeser,
843                 beanDesc.getClassAnnotations(), getter);
844         JsonDeserializer<?> deser = findDeserializerFromAnnotation(ctxt, getter);
845         if (deser == null) {
846             deser = type.getValueHandler();
847         }
848         if (deser != null) {
849             deser = ctxt.handlePrimaryContextualization(deser, prop, type);
850             prop = prop.withValueDeserializer(deser);
851         }
852         return prop;
853     }
854
855     /*
856     /**********************************************************
857     /* Helper methods for Bean deserializer, other
858     /**********************************************************
859      */

860
861     /**
862      * Helper method used to skip processing for types that we know
863      * cannot be (i.e. are never consider to be) beans: 
864      * things like primitives, Arrays, Enums, and proxy types.
865      *<p>
866      * Note that usually we shouldn't really be getting these sort of
867      * types anyway; but better safe than sorry.
868      */

869     protected boolean isPotentialBeanType(Class<?> type)
870     {
871         String typeStr = ClassUtil.canBeABeanType(type);
872         if (typeStr != null) {
873             throw new IllegalArgumentException("Cannot deserialize Class "+type.getName()+" (of type "+typeStr+") as a Bean");
874         }
875         if (ClassUtil.isProxyType(type)) {
876             throw new IllegalArgumentException("Cannot deserialize Proxy class "+type.getName()+" as a Bean");
877         }
878         // also: can't deserialize some local classes: static are ok; in-method not;
879         // other non-static inner classes are ok
880         typeStr = ClassUtil.isLocalType(type, true);
881         if (typeStr != null) {
882             throw new IllegalArgumentException("Cannot deserialize Class "+type.getName()+" (of type "+typeStr+") as a Bean");
883         }
884         return true;
885     }
886
887     /**
888      * Helper method that will check whether given raw type is marked as always ignorable
889      * (for purpose of ignoring properties with type)
890      */

891     protected boolean isIgnorableType(DeserializationConfig config, BeanPropertyDefinition propDef,
892             Class<?> type, Map<Class<?>,Boolean> ignoredTypes)
893     {
894         Boolean status = ignoredTypes.get(type);
895         if (status != null) {
896             return status.booleanValue();
897         }
898         // 22-Oct-2016, tatu: Slight check to skip primitives, String
899         if ((type == String.class) || type.isPrimitive()) {
900             status = Boolean.FALSE;
901         } else {
902             // 21-Apr-2016, tatu: For 2.8, can specify config overrides
903             status = config.getConfigOverride(type).getIsIgnoredType();
904             if (status == null) {
905                 BeanDescription desc = config.introspectClassAnnotations(type);
906                 status = config.getAnnotationIntrospector().isIgnorableType(desc.getClassInfo());
907                 // We default to 'false', i.e. not ignorable
908                 if (status == null) {
909                     status = Boolean.FALSE;
910                 }
911             }
912         }
913         ignoredTypes.put(type, status);
914         return status.booleanValue();
915     }
916
917     /**
918      * @since 2.8.11
919      */

920     protected void _validateSubType(DeserializationContext ctxt, JavaType type,
921             BeanDescription beanDesc)
922         throws JsonMappingException
923     {
924         SubTypeValidator.instance().validateSubType(ctxt, type, beanDesc);
925     }
926 }
927