1 package com.fasterxml.jackson.databind.deser;
2
3 import java.io.Serializable;
4 import java.util.*;
5 import java.util.concurrent.*;
6 import java.util.concurrent.atomic.AtomicReference;
7
8 import com.fasterxml.jackson.annotation.JacksonInject;
9 import com.fasterxml.jackson.annotation.JsonCreator;
10 import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
11 import com.fasterxml.jackson.annotation.JsonSetter;
12 import com.fasterxml.jackson.annotation.Nulls;
13 import com.fasterxml.jackson.annotation.JsonCreator.Mode;
14
15 import com.fasterxml.jackson.core.JsonParser;
16
17 import com.fasterxml.jackson.databind.*;
18 import com.fasterxml.jackson.databind.cfg.ConfigOverride;
19 import com.fasterxml.jackson.databind.cfg.DeserializerFactoryConfig;
20 import com.fasterxml.jackson.databind.cfg.HandlerInstantiator;
21 import com.fasterxml.jackson.databind.deser.impl.CreatorCandidate;
22 import com.fasterxml.jackson.databind.deser.impl.CreatorCollector;
23 import com.fasterxml.jackson.databind.deser.impl.JDKValueInstantiators;
24 import com.fasterxml.jackson.databind.deser.impl.JavaUtilCollectionsDeserializers;
25 import com.fasterxml.jackson.databind.deser.std.*;
26 import com.fasterxml.jackson.databind.exc.InvalidDefinitionException;
27 import com.fasterxml.jackson.databind.ext.OptionalHandlerFactory;
28 import com.fasterxml.jackson.databind.introspect.*;
29 import com.fasterxml.jackson.databind.jsontype.NamedType;
30 import com.fasterxml.jackson.databind.jsontype.TypeDeserializer;
31 import com.fasterxml.jackson.databind.jsontype.TypeResolverBuilder;
32 import com.fasterxml.jackson.databind.type.*;
33 import com.fasterxml.jackson.databind.util.*;
34
35 /**
36  * Abstract factory base class that can provide deserializers for standard
37  * JDK classes, including collection classes and simple heuristics for
38  * "upcasting" common collection interface types
39  * (such as {@link java.util.Collection}).
40  *<p>
41  * Since all simple deserializers are eagerly instantiated, and there is
42  * no additional introspection or customizability of these types,
43  * this factory is stateless.
44  */

45 @SuppressWarnings("serial")
46 public abstract class BasicDeserializerFactory
47     extends DeserializerFactory
48     implements java.io.Serializable
49 {
50     private final static Class<?> CLASS_OBJECT = Object.class;
51     private final static Class<?> CLASS_STRING = String.class;
52     private final static Class<?> CLASS_CHAR_SEQUENCE = CharSequence.class;
53     private final static Class<?> CLASS_ITERABLE = Iterable.class;
54     private final static Class<?> CLASS_MAP_ENTRY = Map.Entry.class;
55     private final static Class<?> CLASS_SERIALIZABLE = Serializable.class;
56
57     /**
58      * We need a placeholder for creator properties that don't have name
59      * but are marked with `@JsonWrapped` annotation.
60      */

61     protected final static PropertyName UNWRAPPED_CREATOR_PARAM_NAME = new PropertyName("@JsonUnwrapped");
62
63     /*
64     /**********************************************************
65     /* Config
66     /**********************************************************
67      */

68     
69     /**
70      * Configuration settings for this factory; immutable instance (just like this
71      * factory), new version created via copy-constructor (fluent-style)
72      */

73     protected final DeserializerFactoryConfig _factoryConfig;
74
75     /*
76     /**********************************************************
77     /* Life cycle
78     /**********************************************************
79      */

80
81     protected BasicDeserializerFactory(DeserializerFactoryConfig config) {
82         _factoryConfig = config;
83     }
84     
85     /**
86      * Method for getting current {@link DeserializerFactoryConfig}.
87       *<p>
88      * Note that since instances are immutable, you can NOT change settings
89      * by accessing an instance and calling methods: this will simply create
90      * new instance of config object.
91      */

92     public DeserializerFactoryConfig getFactoryConfig() {
93         return _factoryConfig;
94     }
95
96     protected abstract DeserializerFactory withConfig(DeserializerFactoryConfig config);
97     
98     /*
99     /********************************************************
100     /* Configuration handling: fluent factories
101     /********************************************************
102      */

103
104     /**
105      * Convenience method for creating a new factory instance with additional deserializer
106      * provider.
107      */

108     @Override
109     public final DeserializerFactory withAdditionalDeserializers(Deserializers additional) {
110         return withConfig(_factoryConfig.withAdditionalDeserializers(additional));
111     }
112
113     /**
114      * Convenience method for creating a new factory instance with additional
115      * {@link KeyDeserializers}.
116      */

117     @Override
118     public final DeserializerFactory withAdditionalKeyDeserializers(KeyDeserializers additional) {
119         return withConfig(_factoryConfig.withAdditionalKeyDeserializers(additional));
120     }
121     
122     /**
123      * Convenience method for creating a new factory instance with additional
124      * {@link BeanDeserializerModifier}.
125      */

126     @Override
127     public final DeserializerFactory withDeserializerModifier(BeanDeserializerModifier modifier) {
128         return withConfig(_factoryConfig.withDeserializerModifier(modifier));
129     }
130
131     /**
132      * Convenience method for creating a new factory instance with additional
133      * {@link AbstractTypeResolver}.
134      */

135     @Override
136     public final DeserializerFactory withAbstractTypeResolver(AbstractTypeResolver resolver) {
137         return withConfig(_factoryConfig.withAbstractTypeResolver(resolver));
138     }
139
140     /**
141      * Convenience method for creating a new factory instance with additional
142      * {@link ValueInstantiators}.
143      */

144     @Override
145     public final DeserializerFactory withValueInstantiators(ValueInstantiators instantiators) {
146         return withConfig(_factoryConfig.withValueInstantiators(instantiators));
147     }
148
149     /*
150     /**********************************************************
151     /* DeserializerFactory impl (partial): type mappings
152     /**********************************************************
153      */

154
155     @Override
156     public JavaType mapAbstractType(DeserializationConfig config, JavaType type) throws JsonMappingException
157     {
158         // first, general mappings
159         while (true) {
160             JavaType next = _mapAbstractType2(config, type);
161             if (next == null) {
162                 return type;
163             }
164             // Should not have to worry about cycles; but better verify since they will invariably occur... :-)
165             // (also: guard against invalid resolution to a non-related type)
166             Class<?> prevCls = type.getRawClass();
167             Class<?> nextCls = next.getRawClass();
168             if ((prevCls == nextCls) || !prevCls.isAssignableFrom(nextCls)) {
169                 throw new IllegalArgumentException("Invalid abstract type resolution from "+type+" to "+next+": latter is not a subtype of former");
170             }
171             type = next;
172         }
173     }
174
175     /**
176      * Method that will find abstract type mapping for specified type, doing a single
177      * lookup through registered abstract type resolvers; will not do recursive lookups.
178      */

179     private JavaType _mapAbstractType2(DeserializationConfig config, JavaType type)
180         throws JsonMappingException
181     {
182         Class<?> currClass = type.getRawClass();
183         if (_factoryConfig.hasAbstractTypeResolvers()) {
184             for (AbstractTypeResolver resolver : _factoryConfig.abstractTypeResolvers()) {
185                 JavaType concrete = resolver.findTypeMapping(config, type);
186                 if ((concrete != null) && !concrete.hasRawClass(currClass)) {
187                     return concrete;
188                 }
189             }
190         }
191         return null;
192     }
193
194     /*
195     /**********************************************************
196     /* DeserializerFactory impl (partial): ValueInstantiators
197     /**********************************************************
198      */

199
200     /**
201      * Value instantiator is created both based on creator annotations,
202      * and on optional externally provided instantiators (registered through
203      * module interface).
204      */

205     @Override
206     public ValueInstantiator findValueInstantiator(DeserializationContext ctxt,
207             BeanDescription beanDesc)
208         throws JsonMappingException
209     {
210         final DeserializationConfig config = ctxt.getConfig();
211
212         ValueInstantiator instantiator = null;
213         // Check @JsonValueInstantiator before anything else
214         AnnotatedClass ac = beanDesc.getClassInfo();
215         Object instDef = ctxt.getAnnotationIntrospector().findValueInstantiator(ac);
216         if (instDef != null) {
217             instantiator = _valueInstantiatorInstance(config, ac, instDef);
218         }
219         if (instantiator == null) {
220             // Second: see if some of standard Jackson/JDK types might provide value
221             // instantiators.
222             instantiator = JDKValueInstantiators.findStdValueInstantiator(config, beanDesc.getBeanClass());
223             if (instantiator == null) {
224                 instantiator = _constructDefaultValueInstantiator(ctxt, beanDesc);
225             }
226         }
227
228         // finally: anyone want to modify ValueInstantiator?
229         if (_factoryConfig.hasValueInstantiators()) {
230             for (ValueInstantiators insts : _factoryConfig.valueInstantiators()) {
231                 instantiator = insts.findValueInstantiator(config, beanDesc, instantiator);
232                 // let's do sanity check; easier to spot buggy handlers
233                 if (instantiator == null) {
234                     ctxt.reportBadTypeDefinition(beanDesc,
235                         "Broken registered ValueInstantiators (of type %s): returned null ValueInstantiator",
236                         insts.getClass().getName());
237                 }
238             }
239         }
240
241         // Sanity check: does the chosen ValueInstantiator have incomplete creators?
242         if (instantiator.getIncompleteParameter() != null) {
243             final AnnotatedParameter nonAnnotatedParam = instantiator.getIncompleteParameter();
244             final AnnotatedWithParams ctor = nonAnnotatedParam.getOwner();
245             throw new IllegalArgumentException("Argument #"+nonAnnotatedParam.getIndex()
246                 +" of constructor "+ctor+" has no property name annotation; must have name when multiple-parameter constructor annotated as Creator");
247         }
248
249         return instantiator;
250     }
251
252     /**
253      * Method that will construct standard default {@link ValueInstantiator}
254      * using annotations (like @JsonCreator) and visibility rules
255      */

256     protected ValueInstantiator _constructDefaultValueInstantiator(DeserializationContext ctxt,
257             BeanDescription beanDesc)
258         throws JsonMappingException
259     {
260         CreatorCollector creators = new CreatorCollector(beanDesc, ctxt.getConfig());
261         AnnotationIntrospector intr = ctxt.getAnnotationIntrospector();
262         
263         // need to construct suitable visibility checker:
264         final DeserializationConfig config = ctxt.getConfig();
265         VisibilityChecker<?> vchecker = config.getDefaultVisibilityChecker(beanDesc.getBeanClass(),
266                 beanDesc.getClassInfo());
267
268         /* 24-Sep-2014, tatu: Tricky part first; need to merge resolved property information
269          *  (which has creator parameters sprinkled around) with actual creator
270          *  declarations (which are needed to access creator annotation, amongst other things).
271          *  Easiest to combine that info first, then pass it to remaining processing.
272          */

273         /* 15-Mar-2015, tatu: Alas, this won't help with constructors that only have implicit
274          *   names. Those will need to be resolved later on.
275          */

276         Map<AnnotatedWithParams,BeanPropertyDefinition[]> creatorDefs = _findCreatorsFromProperties(ctxt,
277                 beanDesc);
278         // Important: first add factory methods; then constructors, so
279         // latter can override former!
280         _addDeserializerFactoryMethods(ctxt, beanDesc, vchecker, intr, creators, creatorDefs);
281         // constructors only usable on concrete types:
282         if (beanDesc.getType().isConcrete()) {
283             _addDeserializerConstructors(ctxt, beanDesc, vchecker, intr, creators, creatorDefs);
284         }
285         return creators.constructValueInstantiator(ctxt);
286     }
287
288     protected Map<AnnotatedWithParams,BeanPropertyDefinition[]> _findCreatorsFromProperties(DeserializationContext ctxt,
289             BeanDescription beanDesc) throws JsonMappingException
290     {
291         Map<AnnotatedWithParams,BeanPropertyDefinition[]> result = Collections.emptyMap();
292         for (BeanPropertyDefinition propDef : beanDesc.findProperties()) {
293             Iterator<AnnotatedParameter> it = propDef.getConstructorParameters();
294             while (it.hasNext()) {
295                 AnnotatedParameter param = it.next();
296                 AnnotatedWithParams owner = param.getOwner();
297                 BeanPropertyDefinition[] defs = result.get(owner);
298                 final int index = param.getIndex();
299                 
300                 if (defs == null) {
301                     if (result.isEmpty()) { // since emptyMap is immutable need to create a 'real' one
302                         result = new LinkedHashMap<AnnotatedWithParams,BeanPropertyDefinition[]>();
303                     }
304                     defs = new BeanPropertyDefinition[owner.getParameterCount()];
305                     result.put(owner, defs);
306                 } else {
307                     if (defs[index] != null) {
308                         ctxt.reportBadTypeDefinition(beanDesc,
309 "Conflict: parameter #%d of %s bound to more than one property; %s vs %s",
310 index, owner, defs[index], propDef);
311                     }
312                 }
313                 defs[index] = propDef;
314             }
315         }
316         return result;
317     }
318     
319     public ValueInstantiator _valueInstantiatorInstance(DeserializationConfig config,
320             Annotated annotated, Object instDef)
321         throws JsonMappingException
322     {
323         if (instDef == null) {
324             return null;
325         }
326
327         ValueInstantiator inst;
328         
329         if (instDef instanceof ValueInstantiator) {
330             return (ValueInstantiator) instDef;
331         }
332         if (!(instDef instanceof Class)) {
333             throw new IllegalStateException("AnnotationIntrospector returned key deserializer definition of type "
334                     +instDef.getClass().getName()
335                     +"; expected type KeyDeserializer or Class<KeyDeserializer> instead");
336         }
337         Class<?> instClass = (Class<?>)instDef;
338         if (ClassUtil.isBogusClass(instClass)) {
339             return null;
340         }
341         if (!ValueInstantiator.class.isAssignableFrom(instClass)) {
342             throw new IllegalStateException("AnnotationIntrospector returned Class "+instClass.getName()
343                     +"; expected Class<ValueInstantiator>");
344         }
345         HandlerInstantiator hi = config.getHandlerInstantiator();
346         if (hi != null) {
347             inst = hi.valueInstantiatorInstance(config, annotated, instClass);
348             if (inst != null) {
349                 return inst;
350             }
351         }
352         return (ValueInstantiator) ClassUtil.createInstance(instClass,
353                 config.canOverrideAccessModifiers());
354     }
355
356     /*
357     /**********************************************************
358     /* Creator introspection
359     /**********************************************************
360      */

361
362     protected void _addDeserializerConstructors(DeserializationContext ctxt,
363             BeanDescription beanDesc, VisibilityChecker<?> vchecker,
364          AnnotationIntrospector intr, CreatorCollector creators,
365          Map<AnnotatedWithParams,BeanPropertyDefinition[]> creatorParams)
366                  throws JsonMappingException
367     {
368         // 25-Jan-2017, tatu: As per [databind#1501], [databind#1502], [databind#1503], best
369         //     for now to skip attempts at using anything but no-args constructor (see
370         //     `InnerClassProperty` construction for that)
371         final boolean isNonStaticInnerClass = beanDesc.isNonStaticInnerClass();
372         if (isNonStaticInnerClass) {
373             // TODO: look for `@JsonCreator` annotated ones, throw explicit exception?
374             return;
375         }
376
377         // First things first: the "default constructor" (zero-arg
378         // constructor; whether implicit or explicit) is NOT included
379         // in list of constructors, so needs to be handled separately.
380         AnnotatedConstructor defaultCtor = beanDesc.findDefaultConstructor();
381         if (defaultCtor != null) {
382             if (!creators.hasDefaultCreator() || _hasCreatorAnnotation(ctxt, defaultCtor)) {
383                 creators.setDefaultCreator(defaultCtor);
384             }
385         }
386         // 21-Sep-2017, tatu: First let's handle explicitly annotated ones
387         List<CreatorCandidate> nonAnnotated = new LinkedList<>();
388         int explCount = 0;
389         for (AnnotatedConstructor ctor : beanDesc.getConstructors()) {
390             JsonCreator.Mode creatorMode = intr.findCreatorAnnotation(ctxt.getConfig(), ctor);
391             if (Mode.DISABLED == creatorMode) {
392                 continue;
393             }
394             if (creatorMode == null) {
395                 // let's check Visibility here, to avoid further processing for non-visible?
396                 if (vchecker.isCreatorVisible(ctor)) {
397                     nonAnnotated.add(CreatorCandidate.construct(intr, ctor, creatorParams.get(ctor)));
398                 }
399                 continue;
400             }
401             switch (creatorMode) {
402             case DELEGATING:
403                 _addExplicitDelegatingCreator(ctxt, beanDesc, creators,
404                         CreatorCandidate.construct(intr, ctor, null));
405                 break;
406             case PROPERTIES:
407                 _addExplicitPropertyCreator(ctxt, beanDesc, creators,
408                         CreatorCandidate.construct(intr, ctor, creatorParams.get(ctor)));
409                 break;
410             default:
411                 _addExplicitAnyCreator(ctxt, beanDesc, creators,
412                         CreatorCandidate.construct(intr, ctor, creatorParams.get(ctor)));
413                 break;
414             }
415             ++explCount;
416         }
417         // And only if and when those handled, consider potentially visible ones
418         if (explCount > 0) { // TODO: split method into two since we could have expl factories
419             return;
420         }
421         List<AnnotatedWithParams> implicitCtors = null;
422         for (CreatorCandidate candidate : nonAnnotated) {
423             final int argCount = candidate.paramCount();
424             final AnnotatedWithParams ctor = candidate.creator();
425
426             // some single-arg factory methods (String, number) are auto-detected
427             if (argCount == 1) {
428                 BeanPropertyDefinition propDef = candidate.propertyDef(0);
429                 boolean useProps = _checkIfCreatorPropertyBased(intr, ctor, propDef);
430
431                 if (useProps) {
432                     SettableBeanProperty[] properties = new SettableBeanProperty[1];
433                     PropertyName name = candidate.paramName(0);
434                     properties[0] = constructCreatorProperty(ctxt, beanDesc, name, 0,
435                             candidate.parameter(0), candidate.injection(0));
436                     creators.addPropertyCreator(ctor, false, properties);
437                 } else {
438                     /*boolean added = */ _handleSingleArgumentCreator(creators,
439                             ctor, false,
440                             vchecker.isCreatorVisible(ctor));
441                     // one more thing: sever link to creator property, to avoid possible later
442                     // problems with "unresolved" constructor property
443                     if (propDef != null) {
444                         ((POJOPropertyBuilder) propDef).removeConstructors();
445                     }
446                 }
447                 // regardless, fully handled
448                 continue;
449             }
450
451             // 2 or more args; all params must have names or be injectable
452             // 14-Mar-2015, tatu (2.6): Or, as per [#725], implicit names will also
453             //   do, with some constraints. But that will require bit post processing...
454
455             int nonAnnotatedParamIndex = -1;
456             SettableBeanProperty[] properties = new SettableBeanProperty[argCount];
457             int explicitNameCount = 0;
458             int implicitWithCreatorCount = 0;
459             int injectCount = 0;
460
461             for (int i = 0; i < argCount; ++i) {
462                 final AnnotatedParameter param = ctor.getParameter(i);
463                 BeanPropertyDefinition propDef = candidate.propertyDef(i);
464                 JacksonInject.Value injectable = intr.findInjectableValue(param);
465                 final PropertyName name = (propDef == null) ? null : propDef.getFullName();
466
467                 if (propDef != null && propDef.isExplicitlyNamed()) {
468                     ++explicitNameCount;
469                     properties[i] = constructCreatorProperty(ctxt, beanDesc, name, i, param, injectable);
470                     continue;
471                 }
472                 if (injectable != null) {
473                     ++injectCount;
474                     properties[i] = constructCreatorProperty(ctxt, beanDesc, name, i, param, injectable);
475                     continue;
476                 }
477                 NameTransformer unwrapper = intr.findUnwrappingNameTransformer(param);
478                 if (unwrapper != null) {
479                     _reportUnwrappedCreatorProperty(ctxt, beanDesc, param);
480                     /*
481                     properties[i] = constructCreatorProperty(ctxt, beanDesc, UNWRAPPED_CREATOR_PARAM_NAME, i, param, null);
482                     ++explicitNameCount;
483                     */

484                     continue;
485                 }
486                 // One more thing: implicit names are ok iff ctor has creator annotation
487                 /*
488                 if (isCreator && (name != null && !name.isEmpty())) {
489                     ++implicitWithCreatorCount;
490                     properties[i] = constructCreatorProperty(ctxt, beanDesc, name, i, param, injectId);
491                     continue;
492                 }
493                 */

494                 if (nonAnnotatedParamIndex < 0) {
495                     nonAnnotatedParamIndex = i;
496                 }
497             }
498
499             final int namedCount = explicitNameCount + implicitWithCreatorCount;
500             // Ok: if named or injectable, we have more work to do
501             if ((explicitNameCount > 0) || (injectCount > 0)) {
502                 // simple case; everything covered:
503                 if ((namedCount + injectCount) == argCount) {
504                     creators.addPropertyCreator(ctor, false, properties);
505                     continue;
506                 }
507                 if ((explicitNameCount == 0) && ((injectCount + 1) == argCount)) {
508                     // Secondary: all but one injectable, one un-annotated (un-named)
509                     creators.addDelegatingCreator(ctor, false, properties, 0);
510                     continue;
511                 }
512                 // otherwise, epic fail?
513                 // 16-Mar-2015, tatu: due to [#725], need to be more permissive. For now let's
514                 //    only report problem if there's no implicit name
515                 PropertyName impl = candidate.findImplicitParamName(nonAnnotatedParamIndex);
516                 if (impl == null || impl.isEmpty()) {
517                     // Let's consider non-static inner class as a special case...
518                     // 25-Jan-2017, tatu: Non-static inner classes skipped altogether, now
519                     /*
520                     if ((nonAnnotatedParamIndex == 0) && isNonStaticInnerClass) {
521                         throw new IllegalArgumentException("Non-static inner classes like "
522                                 +ctor.getDeclaringClass().getName()+" cannot use @JsonCreator for constructors");
523                     }
524                     */

525                     ctxt.reportBadTypeDefinition(beanDesc,
526 "Argument #%d of constructor %s has no property name annotation; must have name when multiple-parameter constructor annotated as Creator",
527 nonAnnotatedParamIndex, ctor);
528                 }
529             }
530             // [#725]: as a fallback, all-implicit names may work as well
531             if (!creators.hasDefaultCreator()) {
532                 if (implicitCtors == null) {
533                     implicitCtors = new LinkedList<>();
534                 }
535                 implicitCtors.add(ctor);
536             }
537         }
538         // last option, as per [#725]: consider implicit-names-only, visible constructor,
539         // if just one found
540         if ((implicitCtors != null) && !creators.hasDelegatingCreator()
541                 && !creators.hasPropertyBasedCreator()) {
542             _checkImplicitlyNamedConstructors(ctxt, beanDesc, vchecker, intr,
543                     creators, implicitCtors);
544         }
545     }
546
547     /**
548      * Helper method called when there is the explicit "is-creator" with mode of "delegating"
549      *
550      * @since 2.9.2
551      */

552     protected void _addExplicitDelegatingCreator(DeserializationContext ctxt,
553             BeanDescription beanDesc, CreatorCollector creators,
554             CreatorCandidate candidate)
555         throws JsonMappingException
556     {
557         // Somewhat simple: find injectable values, if any, ensure there is one
558         // and just one delegated argument; report violations if any
559
560         int ix = -1;
561         final int argCount = candidate.paramCount();
562         SettableBeanProperty[] properties = new SettableBeanProperty[argCount];
563         for (int i = 0; i < argCount; ++i) {
564             AnnotatedParameter param = candidate.parameter(i);
565             JacksonInject.Value injectId = candidate.injection(i);
566             if (injectId != null) {
567                 properties[i] = constructCreatorProperty(ctxt, beanDesc, null, i, param, injectId);
568                 continue;
569             }
570             if (ix < 0) {
571                 ix = i;
572                 continue;
573             }
574             // Illegal to have more than one value to delegate to
575             ctxt.reportBadTypeDefinition(beanDesc,
576                     "More than one argument (#%d and #%d) left as delegating for Creator %s: only one allowed",
577                     ix, i, candidate);
578         }
579         // Also, let's require that one Delegating argument does eixt
580         if (ix < 0) {
581             ctxt.reportBadTypeDefinition(beanDesc,
582                     "No argument left as delegating for Creator %s: exactly one required", candidate);
583         }
584         // 17-Jan-2018, tatu: as per [databind#1853] need to ensure we will distinguish
585         //   "well-known" single-arg variants (String, int/longboolean) from "generic" delegating...
586         if (argCount == 1) {
587             _handleSingleArgumentCreator(creators, candidate.creator(), truetrue);
588             // one more thing: sever link to creator property, to avoid possible later
589             // problems with "unresolved" constructor property
590             BeanPropertyDefinition paramDef = candidate.propertyDef(0);
591             if (paramDef != null) {
592                 ((POJOPropertyBuilder) paramDef).removeConstructors();
593             }
594             return;
595         }
596         creators.addDelegatingCreator(candidate.creator(), true, properties, ix);
597     }
598
599     /**
600      * Helper method called when there is the explicit "is-creator" with mode of "properties-based"
601      *
602      * @since 2.9.2
603      */

604     protected void _addExplicitPropertyCreator(DeserializationContext ctxt,
605             BeanDescription beanDesc, CreatorCollector creators,
606             CreatorCandidate candidate)
607         throws JsonMappingException
608     {
609         final int paramCount = candidate.paramCount();
610         SettableBeanProperty[] properties = new SettableBeanProperty[paramCount];
611
612         for (int i = 0; i < paramCount; ++i) {
613             JacksonInject.Value injectId = candidate.injection(i);
614             AnnotatedParameter param = candidate.parameter(i);
615             PropertyName name = candidate.paramName(i);
616             if (name == null) {
617                 // 21-Sep-2017, tatu: Looks like we want to block accidental use of Unwrapped,
618                 //   as that will not work with Creators well at all
619                 NameTransformer unwrapper = ctxt.getAnnotationIntrospector().findUnwrappingNameTransformer(param);
620                 if (unwrapper != null) {
621                     _reportUnwrappedCreatorProperty(ctxt, beanDesc, param);
622                     /*
623                     properties[i] = constructCreatorProperty(ctxt, beanDesc, UNWRAPPED_CREATOR_PARAM_NAME, i, param, null);
624                     ++explicitNameCount;
625                     */

626                 }
627                 name = candidate.findImplicitParamName(i);
628                 // Must be injectable or have name; without either won't work
629                 if ((name == null) && (injectId == null)) {
630                     ctxt.reportBadTypeDefinition(beanDesc,
631 "Argument #%d has no property name, is not Injectable: can not use as Creator %s", i, candidate);
632                 }
633             }
634             properties[i] = constructCreatorProperty(ctxt, beanDesc, name, i, param, injectId);
635         }
636         creators.addPropertyCreator(candidate.creator(), true, properties);
637     }
638
639     /**
640      * Helper method called when there is explicit "is-creator" marker, but no mode declaration.
641      *
642      * @since 2.9.2
643      */

644     protected void _addExplicitAnyCreator(DeserializationContext ctxt,
645             BeanDescription beanDesc, CreatorCollector creators,
646             CreatorCandidate candidate)
647         throws JsonMappingException
648     {
649         // Looks like there's bit of magic regarding 1-parameter creators; others simpler:
650         if (1 != candidate.paramCount()) {
651             // Ok: for delegates, we want one and exactly one parameter without
652             // injection AND without name
653             int oneNotInjected = candidate.findOnlyParamWithoutInjection();
654             if (oneNotInjected >= 0) {
655                 // getting close; but most not have name
656                 if (candidate.paramName(oneNotInjected) == null) {
657                     _addExplicitDelegatingCreator(ctxt, beanDesc, creators, candidate);
658                     return;
659                 }
660             }
661             _addExplicitPropertyCreator(ctxt, beanDesc, creators, candidate);
662             return;
663         }
664         AnnotatedParameter param = candidate.parameter(0);
665         JacksonInject.Value injectId = candidate.injection(0);
666         PropertyName paramName = candidate.explicitParamName(0);
667         BeanPropertyDefinition paramDef = candidate.propertyDef(0);
668
669         // If there's injection or explicit name, should be properties-based
670         boolean useProps = (paramName != null) || (injectId != null);
671         if (!useProps && (paramDef != null)) {
672             // One more thing: if implicit name matches property with a getter
673             // or field, we'll consider it property-based as well
674
675             // 25-May-2018, tatu: as per [databind#2051], looks like we have to get
676             //    not implicit name, but name with possible strategy-based-rename
677 //            paramName = candidate.findImplicitParamName(0);
678             paramName = candidate.paramName(0);
679             useProps = (paramName != null) && paramDef.couldSerialize();
680         }
681         if (useProps) {
682             SettableBeanProperty[] properties = new SettableBeanProperty[] {
683                     constructCreatorProperty(ctxt, beanDesc, paramName, 0, param, injectId)
684             };
685             creators.addPropertyCreator(candidate.creator(), true, properties);
686             return;
687         }
688         _handleSingleArgumentCreator(creators, candidate.creator(), truetrue);
689
690         // one more thing: sever link to creator property, to avoid possible later
691         // problems with "unresolved" constructor property
692         if (paramDef != null) {
693             ((POJOPropertyBuilder) paramDef).removeConstructors();
694         }
695     }
696
697     private boolean _checkIfCreatorPropertyBased(AnnotationIntrospector intr,
698             AnnotatedWithParams creator, BeanPropertyDefinition propDef)
699     {
700         // If explicit name, or inject id, property-based
701         if (((propDef != null) && propDef.isExplicitlyNamed())
702                 || (intr.findInjectableValue(creator.getParameter(0)) != null)) {
703             return true;
704         }
705         if (propDef != null) {
706             // One more thing: if implicit name matches property with a getter
707             // or field, we'll consider it property-based as well
708             String implName = propDef.getName();
709             if (implName != null && !implName.isEmpty()) {
710                 if (propDef.couldSerialize()) {
711                     return true;
712                 }
713             }
714         }
715         // in absence of everything elsedefault to delegating
716         return false;
717     }
718
719     private void _checkImplicitlyNamedConstructors(DeserializationContext ctxt,
720             BeanDescription beanDesc, VisibilityChecker<?> vchecker,
721             AnnotationIntrospector intr, CreatorCollector creators,
722             List<AnnotatedWithParams> implicitCtors) throws JsonMappingException
723     {
724         AnnotatedWithParams found = null;
725         SettableBeanProperty[] foundProps = null;
726
727         // Further checks: (a) must have names for all parameters, (b) only one visible
728         // Also, since earlier matching of properties and creators relied on existence of
729         // `@JsonCreator` (or equivalent) annotation, we need to do bit more re-inspection...
730
731         main_loop:
732         for (AnnotatedWithParams ctor : implicitCtors) {
733             if (!vchecker.isCreatorVisible(ctor)) {
734                 continue;
735             }
736             // as per earlier notes, only end up here if no properties associated with creator
737             final int argCount = ctor.getParameterCount();
738             SettableBeanProperty[] properties = new SettableBeanProperty[argCount];
739             for (int i = 0; i < argCount; ++i) {
740                 final AnnotatedParameter param = ctor.getParameter(i);
741                 final PropertyName name = _findParamName(param, intr);
742
743                 // must have name (implicit fine)
744                 if (name == null || name.isEmpty()) {
745                     continue main_loop;
746                 }
747                 properties[i] = constructCreatorProperty(ctxt, beanDesc, name, param.getIndex(),
748                         param, /*injectId*/ null);
749             }
750             if (found != null) { // only one allowed; but multiple not an error
751                 found = null;
752                 break;
753             }
754             found = ctor;
755             foundProps = properties;
756         }
757         // found one and only one visible? Ship it!
758         if (found != null) {
759             creators.addPropertyCreator(found, /*isCreator*/ false, foundProps);
760             BasicBeanDescription bbd = (BasicBeanDescription) beanDesc;
761             // Also: add properties, to keep error messages complete wrt known properties...
762             for (SettableBeanProperty prop : foundProps) {
763                 PropertyName pn = prop.getFullName();
764                 if (!bbd.hasProperty(pn)) {
765                     BeanPropertyDefinition newDef = SimpleBeanPropertyDefinition.construct(
766                             ctxt.getConfig(), prop.getMember(), pn);
767                     bbd.addProperty(newDef);
768                 }
769             }
770         }
771     }
772
773     protected void _addDeserializerFactoryMethods
774         (DeserializationContext ctxt, BeanDescription beanDesc, VisibilityChecker<?> vchecker,
775          AnnotationIntrospector intr, CreatorCollector creators,
776          Map<AnnotatedWithParams,BeanPropertyDefinition[]> creatorParams)
777         throws JsonMappingException
778     {
779         List<CreatorCandidate> nonAnnotated = new LinkedList<>();
780         int explCount = 0;
781
782         // 21-Sep-2017, tatu: First let's handle explicitly annotated ones
783         for (AnnotatedMethod factory : beanDesc.getFactoryMethods()) {
784             JsonCreator.Mode creatorMode = intr.findCreatorAnnotation(ctxt.getConfig(), factory);
785             final int argCount = factory.getParameterCount();
786             if (creatorMode == null) {
787                 // Only potentially accept 1-argument factory methods
788                 if ((argCount == 1) && vchecker.isCreatorVisible(factory)) {
789                     nonAnnotated.add(CreatorCandidate.construct(intr, factory, null));
790                 }
791                 continue;
792             }
793             if (creatorMode == Mode.DISABLED) {
794                 continue;
795             }
796             
797             // zero-arg method factory methods fine, as long as explicit
798             if (argCount == 0) {
799                 creators.setDefaultCreator(factory);
800                 continue;
801             }
802
803             switch (creatorMode) {
804             case DELEGATING:
805                 _addExplicitDelegatingCreator(ctxt, beanDesc, creators,
806                         CreatorCandidate.construct(intr, factory, null));
807                 break;
808             case PROPERTIES:
809                 _addExplicitPropertyCreator(ctxt, beanDesc, creators,
810                         CreatorCandidate.construct(intr, factory, creatorParams.get(factory)));
811                 break;
812             case DEFAULT:
813             default:
814                 _addExplicitAnyCreator(ctxt, beanDesc, creators,
815                         CreatorCandidate.construct(intr, factory, creatorParams.get(factory)));
816                 break;
817             }
818             ++explCount;
819         }
820         // And only if and when those handled, consider potentially visible ones
821         if (explCount > 0) { // TODO: split method into two since we could have expl factories
822             return;
823         }
824         // And then implicitly found
825         for (CreatorCandidate candidate : nonAnnotated) {
826             final int argCount = candidate.paramCount();
827             AnnotatedWithParams factory = candidate.creator();
828             final BeanPropertyDefinition[] propDefs = creatorParams.get(factory);
829             // some single-arg factory methods (String, number) are auto-detected
830             if (argCount != 1) {
831                 continue// 2 and more args? Must be explicit, handled earlier
832             }
833             BeanPropertyDefinition argDef = candidate.propertyDef(0);
834             boolean useProps = _checkIfCreatorPropertyBased(intr, factory, argDef);
835             if (!useProps) { // not property based but delegating
836                 /*boolean added=*/ _handleSingleArgumentCreator(creators,
837                         factory, false, vchecker.isCreatorVisible(factory));
838                 // 23-Sep-2016, tatu: [databind#1383]: Need to also sever link to avoid possible
839                 //    later problems with "unresolved" constructor property
840                 if (argDef != null) {
841                     ((POJOPropertyBuilder) argDef).removeConstructors();
842                 }
843                 continue;
844             }
845             AnnotatedParameter nonAnnotatedParam = null;            
846             SettableBeanProperty[] properties = new SettableBeanProperty[argCount];
847             int implicitNameCount = 0;
848             int explicitNameCount = 0;
849             int injectCount = 0;
850             
851             for (int i = 0; i < argCount; ++i) {
852                 final AnnotatedParameter param = factory.getParameter(i);
853                 BeanPropertyDefinition propDef = (propDefs == null) ? null : propDefs[i];
854                 JacksonInject.Value injectable = intr.findInjectableValue(param);
855                 final PropertyName name = (propDef == null) ? null : propDef.getFullName();
856
857                 if (propDef != null && propDef.isExplicitlyNamed()) {
858                     ++explicitNameCount;
859                     properties[i] = constructCreatorProperty(ctxt, beanDesc, name, i, param, injectable);
860                     continue;
861                 }
862                 if (injectable != null) {
863                     ++injectCount;
864                     properties[i] = constructCreatorProperty(ctxt, beanDesc, name, i, param, injectable);
865                     continue;
866                 }
867                 NameTransformer unwrapper = intr.findUnwrappingNameTransformer(param);
868                 if (unwrapper != null) {
869                     _reportUnwrappedCreatorProperty(ctxt, beanDesc, param);
870                     /*
871                     properties[i] = constructCreatorProperty(ctxt, beanDesc, UNWRAPPED_CREATOR_PARAM_NAME, i, param, null);
872                     ++implicitNameCount;
873                     */

874                     continue;
875                 }
876                 // One more thing: implicit names are ok iff ctor has creator annotation
877                 /*
878                 if (isCreator) {
879                     if (name != null && !name.isEmpty()) {
880                         ++implicitNameCount;
881                         properties[i] = constructCreatorProperty(ctxt, beanDesc, name, i, param, injectable);
882                         continue;
883                     }
884                 }
885                 */

886                 /* 25-Sep-2014, tatu: Actually, we may end up "losing" naming due to higher-priority constructor
887                  *  (see TestCreators#testConstructorCreator() test). And just to avoid running into that problem,
888                  *  let's add one more work around
889                  */

890                 /*
891                 PropertyName name2 = _findExplicitParamName(param, intr);
892                 if (name2 != null && !name2.isEmpty()) {
893                     // Hmmh. Ok, fine. So what are we to do with it... ?
894                     // For now... skip. May need to revisit this, should this become problematic
895                     continue main_loop;
896                 }
897                 */

898                 if (nonAnnotatedParam == null) {
899                     nonAnnotatedParam = param;
900                 }
901             }
902             final int namedCount = explicitNameCount + implicitNameCount;
903             
904             // Ok: if named or injectable, we have more work to do
905             if (explicitNameCount > 0 || injectCount > 0) {
906                 // simple case; everything covered:
907                 if ((namedCount + injectCount) == argCount) {
908                     creators.addPropertyCreator(factory, false, properties);
909                 } else if ((explicitNameCount == 0) && ((injectCount + 1) == argCount)) {
910                     // secondary: all but one injectable, one un-annotated (un-named)
911                     creators.addDelegatingCreator(factory, false, properties, 0);
912                 } else { // otherwise, epic fail
913                     ctxt.reportBadTypeDefinition(beanDesc,
914 "Argument #%d of factory method %s has no property name annotation; must have name when multiple-parameter constructor annotated as Creator",
915                     nonAnnotatedParam.getIndex(), factory);
916                 }
917             }
918         }
919     }
920
921     protected boolean _handleSingleArgumentCreator(CreatorCollector creators,
922             AnnotatedWithParams ctor, boolean isCreator, boolean isVisible)
923     {
924         // otherwise either 'simple' number, String, or general delegate:
925         Class<?> type = ctor.getRawParameterType(0);
926         if (type == String.class || type == CLASS_CHAR_SEQUENCE) {
927             if (isCreator || isVisible) {
928                 creators.addStringCreator(ctor, isCreator);
929             }
930             return true;
931         }
932         if (type == int.class || type == Integer.class) {
933             if (isCreator || isVisible) {
934                 creators.addIntCreator(ctor, isCreator);
935             }
936             return true;
937         }
938         if (type == long.class || type == Long.class) {
939             if (isCreator || isVisible) {
940                 creators.addLongCreator(ctor, isCreator);
941             }
942             return true;
943         }
944         if (type == double.class || type == Double.class) {
945             if (isCreator || isVisible) {
946                 creators.addDoubleCreator(ctor, isCreator);
947             }
948             return true;
949         }
950         if (type == boolean.class || type == Boolean.class) {
951             if (isCreator || isVisible) {
952                 creators.addBooleanCreator(ctor, isCreator);
953             }
954             return true;
955         }
956         // Delegating Creator ok iff it has @JsonCreator (etc)
957         if (isCreator) {
958             creators.addDelegatingCreator(ctor, isCreator, null, 0);
959             return true;
960         }
961         return false;
962     }
963
964     // 01-Dec-2016, tatu: As per [databind#265] we cannot yet support passing
965     //   of unwrapped values through creator properties, so fail fast
966     protected void _reportUnwrappedCreatorProperty(DeserializationContext ctxt,
967             BeanDescription beanDesc, AnnotatedParameter param)
968         throws JsonMappingException
969     {
970         ctxt.reportBadDefinition(beanDesc.getType(), String.format(
971                 "Cannot define Creator parameter %d as `@JsonUnwrapped`: combination not yet supported",
972                 param.getIndex()));
973     }
974
975     /**
976      * Method that will construct a property object that represents
977      * a logical property passed via Creator (constructor or static
978      * factory method)
979      */

980     protected SettableBeanProperty constructCreatorProperty(DeserializationContext ctxt,
981             BeanDescription beanDesc, PropertyName name, int index,
982             AnnotatedParameter param,
983             JacksonInject.Value injectable)
984         throws JsonMappingException
985     {
986         final DeserializationConfig config = ctxt.getConfig();
987         final AnnotationIntrospector intr = ctxt.getAnnotationIntrospector();
988         PropertyMetadata metadata;
989         {
990             if (intr == null) {
991                 metadata = PropertyMetadata.STD_REQUIRED_OR_OPTIONAL;
992             } else {
993                 Boolean b = intr.hasRequiredMarker(param);
994                 String desc = intr.findPropertyDescription(param);
995                 Integer idx = intr.findPropertyIndex(param);
996                 String def = intr.findPropertyDefaultValue(param);
997                 metadata = PropertyMetadata.construct(b, desc, idx, def);
998             }
999         }
1000         JavaType type = resolveMemberAndTypeAnnotations(ctxt, param, param.getType());
1001         BeanProperty.Std property = new BeanProperty.Std(name, type,
1002                 intr.findWrapperName(param), param, metadata);
1003         // Type deserializer: either comes from property (and already resolved)
1004         TypeDeserializer typeDeser = (TypeDeserializer) type.getTypeHandler();
1005         // or if not, based on type being referenced:
1006         if (typeDeser == null) {
1007             typeDeser = findTypeDeserializer(config, type);
1008         }
1009
1010         // 22-Sep-2019, tatu: for [databind#2458] need more work on getting metadata
1011         //   about SetterInfo, mergeability
1012         metadata = _getSetterInfo(ctxt, property, metadata);
1013
1014         // Note: contextualization of typeDeser _should_ occur in constructor of CreatorProperty
1015         // so it is not called directly here
1016         SettableBeanProperty prop = CreatorProperty.construct(name, type, property.getWrapperName(),
1017                 typeDeser, beanDesc.getClassAnnotations(), param, index, injectable,
1018                 metadata);
1019         JsonDeserializer<?> deser = findDeserializerFromAnnotation(ctxt, param);
1020         if (deser == null) {
1021             deser = type.getValueHandler();
1022         }
1023         if (deser != null) {
1024             // As per [databind#462] need to ensure we contextualize deserializer before passing it on
1025             deser = ctxt.handlePrimaryContextualization(deser, prop, type);
1026             prop = prop.withValueDeserializer(deser);
1027         }
1028         return prop;
1029     }
1030
1031     private PropertyName _findParamName(AnnotatedParameter param, AnnotationIntrospector intr)
1032     {
1033         if (param != null && intr != null) {
1034             PropertyName name = intr.findNameForDeserialization(param);
1035             if (name != null) {
1036                 return name;
1037             }
1038             // 14-Apr-2014, tatu: Need to also consider possible implicit name
1039             //  (for JDK8, or via paranamer)
1040
1041             String str = intr.findImplicitPropertyName(param);
1042             if (str != null && !str.isEmpty()) {
1043                 return PropertyName.construct(str);
1044             }
1045         }
1046         return null;
1047     }
1048
1049     /**
1050      * Helper method copied from {@code POJOPropertyBuilder} since that won't be
1051      * applied to creator parameters
1052      *
1053      * @since 2.10
1054      */

1055     protected PropertyMetadata _getSetterInfo(DeserializationContext ctxt,
1056             BeanProperty prop, PropertyMetadata metadata)
1057     {
1058         final AnnotationIntrospector intr = ctxt.getAnnotationIntrospector();
1059         final DeserializationConfig config = ctxt.getConfig();
1060
1061         boolean needMerge = true;
1062         Nulls valueNulls = null;
1063         Nulls contentNulls = null;
1064
1065         // NOTE: compared to `POJOPropertyBuilder`, we only have access to creator
1066         // parameter, not other accessors, so code bit simpler
1067         AnnotatedMember prim = prop.getMember();
1068
1069         if (prim != null) {
1070             // Ok, first: does property itself have something to say?
1071             if (intr != null) {
1072                 JsonSetter.Value setterInfo = intr.findSetterInfo(prim);
1073                 if (setterInfo != null) {
1074                     valueNulls = setterInfo.nonDefaultValueNulls();
1075                     contentNulls = setterInfo.nonDefaultContentNulls();
1076                 }
1077             }
1078             // If not, config override?
1079             // 25-Oct-2016, tatu: Either this, or type of accessor...
1080             if (needMerge || (valueNulls == null) || (contentNulls == null)) {
1081                 ConfigOverride co = config.getConfigOverride(prop.getType().getRawClass());
1082                 JsonSetter.Value setterInfo = co.getSetterInfo();
1083                 if (setterInfo != null) {
1084                     if (valueNulls == null) {
1085                         valueNulls = setterInfo.nonDefaultValueNulls();
1086                     }
1087                     if (contentNulls == null) {
1088                         contentNulls = setterInfo.nonDefaultContentNulls();
1089                     }
1090                 }
1091             }
1092         }
1093         if (needMerge || (valueNulls == null) || (contentNulls == null)) {
1094             JsonSetter.Value setterInfo = config.getDefaultSetterInfo();
1095             if (valueNulls == null) {
1096                 valueNulls = setterInfo.nonDefaultValueNulls();
1097             }
1098             if (contentNulls == null) {
1099                 contentNulls = setterInfo.nonDefaultContentNulls();
1100             }
1101         }
1102         if ((valueNulls != null) || (contentNulls != null)) {
1103             metadata = metadata.withNulls(valueNulls, contentNulls);
1104         }
1105         return metadata;
1106     }
1107
1108     /*
1109     /**********************************************************
1110     /* DeserializerFactory impl: array deserializers
1111     /**********************************************************
1112      */

1113         
1114     @Override
1115     public JsonDeserializer<?> createArrayDeserializer(DeserializationContext ctxt,
1116             ArrayType type, final BeanDescription beanDesc)
1117         throws JsonMappingException
1118     {
1119         final DeserializationConfig config = ctxt.getConfig();
1120         JavaType elemType = type.getContentType();
1121         
1122         // Very first thing: is deserializer hard-coded for elements?
1123         JsonDeserializer<Object> contentDeser = elemType.getValueHandler();
1124         // Then optional type info: if type has been resolved, we may already know type deserializer:
1125         TypeDeserializer elemTypeDeser = elemType.getTypeHandler();
1126         // but if not, may still be possible to find:
1127         if (elemTypeDeser == null) {
1128             elemTypeDeser = findTypeDeserializer(config, elemType);
1129         }
1130         // 23-Nov-2010, tatu: Custom array deserializer?
1131         JsonDeserializer<?>  deser = _findCustomArrayDeserializer(type,
1132                 config, beanDesc, elemTypeDeser, contentDeser);
1133         if (deser == null) {
1134             if (contentDeser == null) {
1135                 Class<?> raw = elemType.getRawClass();
1136                 if (elemType.isPrimitive()) {
1137                     return PrimitiveArrayDeserializers.forType(raw);
1138                 }
1139                 if (raw == String.class) {
1140                     return StringArrayDeserializer.instance;
1141                 }
1142             }
1143             deser = new ObjectArrayDeserializer(type, contentDeser, elemTypeDeser);
1144         }
1145         // and then new with 2.2: ability to post-process it too (databind#120)
1146         if (_factoryConfig.hasDeserializerModifiers()) {
1147             for (BeanDeserializerModifier mod : _factoryConfig.deserializerModifiers()) {
1148                 deser = mod.modifyArrayDeserializer(config, type, beanDesc, deser);
1149             }
1150         }
1151         return deser;
1152     }
1153
1154     /*
1155     /**********************************************************************
1156     /* DeserializerFactory impl: Collection(-like) deserializers
1157     /**********************************************************************
1158      */

1159
1160     @Override
1161     public JsonDeserializer<?> createCollectionDeserializer(DeserializationContext ctxt,
1162             CollectionType type, BeanDescription beanDesc)
1163         throws JsonMappingException
1164     {
1165         JavaType contentType = type.getContentType();
1166         // Very first thing: is deserializer hard-coded for elements?
1167         JsonDeserializer<Object> contentDeser = contentType.getValueHandler();
1168         final DeserializationConfig config = ctxt.getConfig();
1169
1170         // Then optional type info: if type has been resolved, we may already know type deserializer:
1171         TypeDeserializer contentTypeDeser = contentType.getTypeHandler();
1172         // but if not, may still be possible to find:
1173         if (contentTypeDeser == null) {
1174             contentTypeDeser = findTypeDeserializer(config, contentType);
1175         }
1176         // 23-Nov-2010, tatu: Custom deserializer?
1177         JsonDeserializer<?> deser = _findCustomCollectionDeserializer(type,
1178                 config, beanDesc, contentTypeDeser, contentDeser);
1179         if (deser == null) {
1180             Class<?> collectionClass = type.getRawClass();
1181             if (contentDeser == null) { // not defined by annotation
1182                 // One special type: EnumSet:
1183                 if (EnumSet.class.isAssignableFrom(collectionClass)) {
1184                     deser = new EnumSetDeserializer(contentType, null);
1185                 }
1186             }
1187         }
1188
1189         /* One twist: if we are being asked to instantiate an interface or
1190          * abstract Collection, we need to either find something that implements
1191          * the thing, or give up.
1192          *
1193          * Note that we do NOT try to guess based on secondary interfaces
1194          * here; that would probably not work correctly since casts would
1195          * fail later on (as the primary type is not the interface we'd
1196          * be implementing)
1197          */

1198         if (deser == null) {
1199             if (type.isInterface() || type.isAbstract()) {
1200                 CollectionType implType = _mapAbstractCollectionType(type, config);
1201                 if (implType == null) {
1202                     // [databind#292]: Actually, may be fine, but only if polymorphich deser enabled
1203                     if (type.getTypeHandler() == null) {
1204                         throw new IllegalArgumentException("Cannot find a deserializer for non-concrete Collection type "+type);
1205                     }
1206                     deser = AbstractDeserializer.constructForNonPOJO(beanDesc);
1207                 } else {
1208                     type = implType;
1209                     // But if so, also need to re-check creators...
1210                     beanDesc = config.introspectForCreation(type);
1211                 }
1212             }
1213             if (deser == null) {
1214                 ValueInstantiator inst = findValueInstantiator(ctxt, beanDesc);
1215                 if (!inst.canCreateUsingDefault()) {
1216                     // [databind#161]: No default constructor for ArrayBlockingQueue...
1217                     if (type.hasRawClass(ArrayBlockingQueue.class)) {
1218                         return new ArrayBlockingQueueDeserializer(type, contentDeser, contentTypeDeser, inst);
1219                     }
1220                     // 10-Jan-2017, tatu: `java.util.Collections` types need help:
1221                     deser = JavaUtilCollectionsDeserializers.findForCollection(ctxt, type);
1222                     if (deser != null) {
1223                         return deser;
1224                     }
1225                 }
1226                 // Can use more optimal deserializer if content type is String, so:
1227                 if (contentType.hasRawClass(String.class)) {
1228                     // no value type deserializer because Strings are one of natural/native types:
1229                     deser = new StringCollectionDeserializer(type, contentDeser, inst);
1230                 } else {
1231                     deser = new CollectionDeserializer(type, contentDeser, contentTypeDeser, inst);
1232                 }
1233             }
1234         }
1235         // allow post-processing it too
1236         if (_factoryConfig.hasDeserializerModifiers()) {
1237             for (BeanDeserializerModifier mod : _factoryConfig.deserializerModifiers()) {
1238                 deser = mod.modifyCollectionDeserializer(config, type, beanDesc, deser);
1239             }
1240         }
1241         return deser;
1242     }
1243
1244     protected CollectionType _mapAbstractCollectionType(JavaType type, DeserializationConfig config)
1245     {
1246         final Class<?> collectionClass = ContainerDefaultMappings.findCollectionFallback(type);
1247         if (collectionClass != null) {
1248             return (CollectionType) config.getTypeFactory()
1249                     .constructSpecializedType(type, collectionClass, true);
1250         }
1251         return null;
1252     }
1253
1254     // Copied almost verbatim from "createCollectionDeserializer" -- should try to share more code
1255     @Override
1256     public JsonDeserializer<?> createCollectionLikeDeserializer(DeserializationContext ctxt,
1257             CollectionLikeType type, final BeanDescription beanDesc)
1258         throws JsonMappingException
1259     {
1260         JavaType contentType = type.getContentType();
1261         // Very first thing: is deserializer hard-coded for elements?
1262         JsonDeserializer<Object> contentDeser = contentType.getValueHandler();
1263         final DeserializationConfig config = ctxt.getConfig();
1264
1265         // Then optional type info (1.5): if type has been resolved, we may already know type deserializer:
1266         TypeDeserializer contentTypeDeser = contentType.getTypeHandler();
1267         // but if not, may still be possible to find:
1268         if (contentTypeDeser == null) {
1269             contentTypeDeser = findTypeDeserializer(config, contentType);
1270         }
1271         JsonDeserializer<?> deser = _findCustomCollectionLikeDeserializer(type, config, beanDesc,
1272                 contentTypeDeser, contentDeser);
1273         if (deser != null) {
1274             // and then new with 2.2: ability to post-process it too (Issue#120)
1275             if (_factoryConfig.hasDeserializerModifiers()) {
1276                 for (BeanDeserializerModifier mod : _factoryConfig.deserializerModifiers()) {
1277                     deser = mod.modifyCollectionLikeDeserializer(config, type, beanDesc, deser);
1278                 }
1279             }
1280         }
1281         return deser;
1282     }
1283
1284     /*
1285     /**********************************************************
1286     /* DeserializerFactory impl: Map(-like) deserializers
1287     /**********************************************************
1288      */

1289
1290     @Override
1291     public JsonDeserializer<?> createMapDeserializer(DeserializationContext ctxt,
1292             MapType type, BeanDescription beanDesc)
1293         throws JsonMappingException
1294     {
1295         final DeserializationConfig config = ctxt.getConfig();
1296         JavaType keyType = type.getKeyType();
1297         JavaType contentType = type.getContentType();
1298         
1299         // First: is there annotation-specified deserializer for values?
1300         @SuppressWarnings("unchecked")
1301         JsonDeserializer<Object> contentDeser = (JsonDeserializer<Object>) contentType.getValueHandler();
1302
1303         // Ok: need a key deserializer (null indicates 'default' here)
1304         KeyDeserializer keyDes = (KeyDeserializer) keyType.getValueHandler();
1305         // Then optional type info; either attached to type, or resolved separately:
1306         TypeDeserializer contentTypeDeser = contentType.getTypeHandler();
1307         // but if not, may still be possible to find:
1308         if (contentTypeDeser == null) {
1309             contentTypeDeser = findTypeDeserializer(config, contentType);
1310         }
1311
1312         // 23-Nov-2010, tatu: Custom deserializer?
1313         JsonDeserializer<?> deser = _findCustomMapDeserializer(type, config, beanDesc,
1314                 keyDes, contentTypeDeser, contentDeser);
1315
1316         if (deser == null) {
1317             // Value handling is identical for all, but EnumMap requires special handling for keys
1318             Class<?> mapClass = type.getRawClass();
1319             if (EnumMap.class.isAssignableFrom(mapClass)) {
1320                 ValueInstantiator inst;
1321
1322                 // 06-Mar-2017, tatu: Should only need to check ValueInstantiator for
1323                 //    custom sub-classes, see [databind#1544]
1324                 if (mapClass == EnumMap.class) {
1325                     inst = null;
1326                 } else {
1327                     inst = findValueInstantiator(ctxt, beanDesc);
1328                 }
1329                 if (!keyType.isEnumImplType()) {
1330                     throw new IllegalArgumentException("Cannot construct EnumMap; generic (key) type not available");
1331                 }
1332                 deser = new EnumMapDeserializer(type, inst, null,
1333                         contentDeser, contentTypeDeser, null);
1334             }
1335
1336             // Otherwise, generic handler works ok.
1337     
1338             /* But there is one more twist: if we are being asked to instantiate
1339              * an interface or abstract Map, we need to either find something
1340              * that implements the thing, or give up.
1341              *
1342              * Note that we do NOT try to guess based on secondary interfaces
1343              * here; that would probably not work correctly since casts would
1344              * fail later on (as the primary type is not the interface we'd
1345              * be implementing)
1346              */

1347             if (deser == null) {
1348                 if (type.isInterface() || type.isAbstract()) {
1349                     MapType fallback = _mapAbstractMapType(type, config);
1350                     if (fallback != null) {
1351                         type = (MapType) fallback;
1352                         mapClass = type.getRawClass();
1353                         // But if so, also need to re-check creators...
1354                         beanDesc = config.introspectForCreation(type);
1355                     } else {
1356                         // [databind#292]: Actually, may be fine, but only if polymorphic deser enabled
1357                         if (type.getTypeHandler() == null) {
1358                             throw new IllegalArgumentException("Cannot find a deserializer for non-concrete Map type "+type);
1359                         }
1360                         deser = AbstractDeserializer.constructForNonPOJO(beanDesc);
1361                     }
1362                 } else {
1363                     // 10-Jan-2017, tatu: `java.util.Collections` types need help:
1364                     deser = JavaUtilCollectionsDeserializers.findForMap(ctxt, type);
1365                     if (deser != null) {
1366                         return deser;
1367                     }
1368                 }
1369                 if (deser == null) {
1370                     ValueInstantiator inst = findValueInstantiator(ctxt, beanDesc);
1371                     // 01-May-2016, tatu: Which base type to use here gets tricky, since
1372                     //   most often it ought to be `Map` or `EnumMap`, but due to abstract
1373                     //   mapping it will more likely be concrete type like `HashMap`.
1374                     //   So, for time being, just pass `Map.class`
1375                     MapDeserializer md = new MapDeserializer(type, inst, keyDes, contentDeser, contentTypeDeser);
1376                     JsonIgnoreProperties.Value ignorals = config.getDefaultPropertyIgnorals(Map.class,
1377                             beanDesc.getClassInfo());
1378                     Set<String> ignored = (ignorals == null) ? null
1379                             : ignorals.findIgnoredForDeserialization();
1380                     md.setIgnorableProperties(ignored);
1381                     deser = md;
1382                 }
1383             }
1384         }
1385         if (_factoryConfig.hasDeserializerModifiers()) {
1386             for (BeanDeserializerModifier mod : _factoryConfig.deserializerModifiers()) {
1387                 deser = mod.modifyMapDeserializer(config, type, beanDesc, deser);
1388             }
1389         }
1390         return deser;
1391     }
1392
1393     protected MapType _mapAbstractMapType(JavaType type, DeserializationConfig config)
1394     {
1395         final Class<?> mapClass = ContainerDefaultMappings.findMapFallback(type);
1396         if (mapClass != null) {
1397             return (MapType) config.getTypeFactory()
1398                     .constructSpecializedType(type, mapClass, true);
1399         }
1400         return null;
1401     }
1402
1403     // Copied almost verbatim from "createMapDeserializer" -- should try to share more code
1404     @Override
1405     public JsonDeserializer<?> createMapLikeDeserializer(DeserializationContext ctxt,
1406             MapLikeType type, final BeanDescription beanDesc)
1407         throws JsonMappingException
1408     {
1409         JavaType keyType = type.getKeyType();
1410         JavaType contentType = type.getContentType();
1411         final DeserializationConfig config = ctxt.getConfig();
1412         
1413         // First: is there annotation-specified deserializer for values?
1414         @SuppressWarnings("unchecked")
1415         JsonDeserializer<Object> contentDeser = (JsonDeserializer<Object>) contentType.getValueHandler();
1416         
1417         // Ok: need a key deserializer (null indicates 'default' here)
1418         KeyDeserializer keyDes = (KeyDeserializer) keyType.getValueHandler();
1419         /* !!! 24-Jan-2012, tatu: NOTE: impls MUST use resolve() to find key deserializer!
1420         if (keyDes == null) {
1421             keyDes = p.findKeyDeserializer(config, keyType, property);
1422         }
1423         */

1424         // Then optional type info (1.5); either attached to type, or resolve separately:
1425         TypeDeserializer contentTypeDeser = contentType.getTypeHandler();
1426         // but if not, may still be possible to find:
1427         if (contentTypeDeser == null) {
1428             contentTypeDeser = findTypeDeserializer(config, contentType);
1429         }
1430         JsonDeserializer<?> deser = _findCustomMapLikeDeserializer(type, config,
1431                 beanDesc, keyDes, contentTypeDeser, contentDeser);
1432         if (deser != null) {
1433             // and then new with 2.2: ability to post-process it too (Issue#120)
1434             if (_factoryConfig.hasDeserializerModifiers()) {
1435                 for (BeanDeserializerModifier mod : _factoryConfig.deserializerModifiers()) {
1436                     deser = mod.modifyMapLikeDeserializer(config, type, beanDesc, deser);
1437                 }
1438             }
1439         }
1440         return deser;
1441     }
1442
1443     /*
1444     /**********************************************************
1445     /* DeserializerFactory impl: other types
1446     /**********************************************************
1447      */

1448     
1449     /**
1450      * Factory method for constructing serializers of {@link Enum} types.
1451      */

1452     @Override
1453     public JsonDeserializer<?> createEnumDeserializer(DeserializationContext ctxt,
1454             JavaType type, BeanDescription beanDesc)
1455         throws JsonMappingException
1456     {
1457         final DeserializationConfig config = ctxt.getConfig();
1458         final Class<?> enumClass = type.getRawClass();
1459         // 23-Nov-2010, tatu: Custom deserializer?
1460         JsonDeserializer<?> deser = _findCustomEnumDeserializer(enumClass, config, beanDesc);
1461
1462         if (deser == null) {
1463             // 12-Feb-2020, tatu: while we can't really create real deserializer for `Enum.class`,
1464             //    it is necessary to allow it in one specific case: see [databind#2605] for details
1465             //    but basically it can be used as polymorphic base.
1466             //    We could check `type.getTypeHandler()` to look for that case but seems like we
1467             //    may as well simply create placeholder (AbstractDeserializer) regardless
1468             if (enumClass == Enum.class) {
1469                 return AbstractDeserializer.constructForNonPOJO(beanDesc);
1470             }
1471
1472             ValueInstantiator valueInstantiator = _constructDefaultValueInstantiator(ctxt, beanDesc);
1473             SettableBeanProperty[] creatorProps = (valueInstantiator == null) ? null
1474                     : valueInstantiator.getFromObjectArguments(ctxt.getConfig());
1475             // May have @JsonCreator for static factory method:
1476             for (AnnotatedMethod factory : beanDesc.getFactoryMethods()) {
1477                 if (_hasCreatorAnnotation(ctxt, factory)) {
1478                     if (factory.getParameterCount() == 0) { // [databind#960]
1479                         deser = EnumDeserializer.deserializerForNoArgsCreator(config, enumClass, factory);
1480                         break;
1481                     }
1482                     Class<?> returnType = factory.getRawReturnType();
1483                     // usually should be class, but may be just plain Enum<?> (for Enum.valueOf()?)
1484                     if (!returnType.isAssignableFrom(enumClass)) {
1485                         ctxt.reportBadDefinition(type, String.format(
1486 "Invalid `@JsonCreator` annotated Enum factory method [%s]: needs to return compatible type",
1487 factory.toString()));
1488                     }
1489                     deser = EnumDeserializer.deserializerForCreator(config, enumClass, factory, valueInstantiator, creatorProps);
1490                     break;
1491                 }
1492             }
1493            
1494             // Need to consider @JsonValue if one found
1495             if (deser == null) {
1496                 deser = new EnumDeserializer(constructEnumResolver(enumClass,
1497                         config, beanDesc.findJsonValueAccessor()),
1498                         config.isEnabled(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS));
1499             }
1500         }
1501
1502         // and then post-process it too
1503         if (_factoryConfig.hasDeserializerModifiers()) {
1504             for (BeanDeserializerModifier mod : _factoryConfig.deserializerModifiers()) {
1505                 deser = mod.modifyEnumDeserializer(config, type, beanDesc, deser);
1506             }
1507         }
1508         return deser;
1509     }
1510
1511     @Override
1512     public JsonDeserializer<?> createTreeDeserializer(DeserializationConfig config,
1513             JavaType nodeType, BeanDescription beanDesc)
1514         throws JsonMappingException
1515     {
1516         @SuppressWarnings("unchecked")
1517         Class<? extends JsonNode> nodeClass = (Class<? extends JsonNode>) nodeType.getRawClass();
1518         // 23-Nov-2010, tatu: Custom deserializer?
1519         JsonDeserializer<?> custom = _findCustomTreeNodeDeserializer(nodeClass, config,
1520                 beanDesc);
1521         if (custom != null) {
1522             return custom;
1523         }
1524         return JsonNodeDeserializer.getDeserializer(nodeClass);
1525     }
1526
1527     @Override
1528     public JsonDeserializer<?> createReferenceDeserializer(DeserializationContext ctxt,
1529             ReferenceType type, BeanDescription beanDesc)
1530         throws JsonMappingException
1531     {
1532         JavaType contentType = type.getContentType();
1533         // Very first thing: is deserializer hard-coded for elements?
1534         JsonDeserializer<Object> contentDeser = contentType.getValueHandler();
1535         final DeserializationConfig config = ctxt.getConfig();
1536         // Then optional type info: if type has been resolved, we may already know type deserializer:
1537         TypeDeserializer contentTypeDeser = contentType.getTypeHandler();
1538         if (contentTypeDeser == null) { // or if not, may be able to find:
1539             contentTypeDeser = findTypeDeserializer(config, contentType);
1540         }
1541         JsonDeserializer<?> deser = _findCustomReferenceDeserializer(type, config, beanDesc,
1542                 contentTypeDeser, contentDeser);
1543
1544         if (deser == null) {
1545             // Just one referential type as of JDK 1.7 / Java 7: AtomicReference (Java 8 adds Optional)
1546             if (type.isTypeOrSubTypeOf(AtomicReference.class)) {
1547                 Class<?> rawType = type.getRawClass();
1548                 ValueInstantiator inst;
1549                 if (rawType == AtomicReference.class) {
1550                     inst = null;
1551                 } else {
1552                     /* 23-Oct-2016, tatu: Note that subtypes are probably not supportable
1553                      *    without either forcing merging (to avoid having to create instance)
1554                      *    or something else...
1555                      */

1556                     inst = findValueInstantiator(ctxt, beanDesc);
1557                 }
1558                 return new AtomicReferenceDeserializer(type, inst, contentTypeDeser, contentDeser);
1559             }
1560         }
1561         if (deser != null) {
1562             // and then post-process
1563             if (_factoryConfig.hasDeserializerModifiers()) {
1564                 for (BeanDeserializerModifier mod : _factoryConfig.deserializerModifiers()) {
1565                     deser = mod.modifyReferenceDeserializer(config, type, beanDesc, deser);
1566                 }
1567             }
1568         }
1569         return deser;
1570     }
1571
1572     /*
1573     /**********************************************************
1574     /* DeserializerFactory impl (partial): type deserializers
1575     /**********************************************************
1576      */

1577
1578     @Override
1579     public TypeDeserializer findTypeDeserializer(DeserializationConfig config,
1580             JavaType baseType)
1581         throws JsonMappingException
1582     {
1583         BeanDescription bean = config.introspectClassAnnotations(baseType.getRawClass());
1584         AnnotatedClass ac = bean.getClassInfo();
1585         AnnotationIntrospector ai = config.getAnnotationIntrospector();
1586         TypeResolverBuilder<?> b = ai.findTypeResolver(config, ac, baseType);
1587
1588         // Ok: if there is no explicit type info handler, we may want to
1589         // use a default. If so, config object knows what to use.
1590         Collection<NamedType> subtypes = null;
1591         if (b == null) {
1592             b = config.getDefaultTyper(baseType);
1593             if (b == null) {
1594                 return null;
1595             }
1596         } else {
1597             subtypes = config.getSubtypeResolver().collectAndResolveSubtypesByTypeId(config, ac);
1598         }
1599         // May need to figure out default implementation, if none found yet
1600         // (note: check for abstract type is not 100% mandatory, more of an optimization)
1601         if ((b.getDefaultImpl() == null) && baseType.isAbstract()) {
1602             JavaType defaultType = mapAbstractType(config, baseType);
1603             if ((defaultType != null) && !defaultType.hasRawClass(baseType.getRawClass())) {
1604                 b = b.defaultImpl(defaultType.getRawClass());
1605             }
1606         }
1607         // 05-Apt-2018, tatu: Since we get non-mapping exception due to various limitations,
1608         //    map to better type here
1609         try {
1610             return b.buildTypeDeserializer(config, baseType, subtypes);
1611         } catch (IllegalArgumentException e0) {
1612             InvalidDefinitionException e = InvalidDefinitionException.from((JsonParser) null,
1613                     ClassUtil.exceptionMessage(e0), baseType);
1614             e.initCause(e0);
1615             throw e;
1616         }
1617     }
1618
1619     /**
1620      * Overridable method called after checking all other types.
1621      * 
1622      * @since 2.2
1623      */

1624     protected JsonDeserializer<?> findOptionalStdDeserializer(DeserializationContext ctxt,
1625             JavaType type, BeanDescription beanDesc)
1626         throws JsonMappingException
1627     {
1628         return OptionalHandlerFactory.instance.findDeserializer(type, ctxt.getConfig(), beanDesc);
1629     }
1630
1631     /*
1632     /**********************************************************
1633     /* DeserializerFactory impl (partial): key deserializers
1634     /**********************************************************
1635      */

1636
1637     @Override
1638     public KeyDeserializer createKeyDeserializer(DeserializationContext ctxt,
1639             JavaType type)
1640         throws JsonMappingException
1641     {
1642         final DeserializationConfig config = ctxt.getConfig();
1643         BeanDescription beanDesc = null;
1644         KeyDeserializer deser = null;
1645         if (_factoryConfig.hasKeyDeserializers()) {
1646             beanDesc = config.introspectClassAnnotations(type);
1647             for (KeyDeserializers d  : _factoryConfig.keyDeserializers()) {
1648                 deser = d.findKeyDeserializer(type, config, beanDesc);
1649                 if (deser != null) {
1650                     break;
1651                 }
1652             }
1653         }
1654
1655         // the only non-standard thing is this:
1656         if (deser == null) {
1657             // [databind#2452]: Support `@JsonDeserialize(keyUsing = ...)`
1658             if (beanDesc == null) {
1659                 beanDesc = config.introspectClassAnnotations(type.getRawClass());
1660             }
1661             deser = findKeyDeserializerFromAnnotation(ctxt, beanDesc.getClassInfo());
1662             if (deser == null) {
1663                 if (type.isEnumType()) {
1664                     deser = _createEnumKeyDeserializer(ctxt, type);
1665                 } else {
1666                     deser = StdKeyDeserializers.findStringBasedKeyDeserializer(config, type);
1667                 }
1668             }
1669         }
1670         // and then post-processing
1671         if (deser != null) {
1672             if (_factoryConfig.hasDeserializerModifiers()) {
1673                 for (BeanDeserializerModifier mod : _factoryConfig.deserializerModifiers()) {
1674                     deser = mod.modifyKeyDeserializer(config, type, deser);
1675                 }
1676             }
1677         }
1678         return deser;
1679     }
1680
1681     private KeyDeserializer _createEnumKeyDeserializer(DeserializationContext ctxt,
1682             JavaType type)
1683         throws JsonMappingException
1684     {
1685         final DeserializationConfig config = ctxt.getConfig();
1686         Class<?> enumClass = type.getRawClass();
1687
1688         BeanDescription beanDesc = config.introspect(type);
1689         // 24-Sep-2015, bim: a key deserializer is the preferred thing.
1690         KeyDeserializer des = findKeyDeserializerFromAnnotation(ctxt, beanDesc.getClassInfo());
1691         if (des != null) {
1692             return des;
1693         } else {
1694             // 24-Sep-2015, bim: if no key deser, look for enum deserializer first, then a plain deser.
1695             JsonDeserializer<?> custom = _findCustomEnumDeserializer(enumClass, config, beanDesc);
1696             if (custom != null) {
1697                 return StdKeyDeserializers.constructDelegatingKeyDeserializer(config, type, custom);
1698             }
1699             JsonDeserializer<?> valueDesForKey = findDeserializerFromAnnotation(ctxt, beanDesc.getClassInfo());
1700             if (valueDesForKey != null) {
1701                 return StdKeyDeserializers.constructDelegatingKeyDeserializer(config, type, valueDesForKey);
1702             }
1703         }
1704         EnumResolver enumRes = constructEnumResolver(enumClass, config, beanDesc.findJsonValueAccessor());
1705
1706         // May have @JsonCreator for static factory method
1707         for (AnnotatedMethod factory : beanDesc.getFactoryMethods()) {
1708             if (_hasCreatorAnnotation(ctxt, factory)) {
1709                 int argCount = factory.getParameterCount();
1710                 if (argCount == 1) {
1711                     Class<?> returnType = factory.getRawReturnType();
1712                     // usually should be class, but may be just plain Enum<?> (for Enum.valueOf()?)
1713                     if (returnType.isAssignableFrom(enumClass)) {
1714                         // note: mostly copied from 'EnumDeserializer.deserializerForCreator(...)'
1715                         if (factory.getRawParameterType(0) != String.class) {
1716                             // [databind#2725]: Should not error out because (1) there may be good creator
1717                             //   method and (2) this method may be valid for "regular" enum value deserialization
1718                             // (leaving aside potential for multiple conflicting creators)
1719 //                            throw new IllegalArgumentException("Parameter #0 type for factory method ("+factory+") not suitable, must be java.lang.String");
1720                             continue;
1721                         }
1722                         if (config.canOverrideAccessModifiers()) {
1723                             ClassUtil.checkAndFixAccess(factory.getMember(),
1724                                     ctxt.isEnabled(MapperFeature.OVERRIDE_PUBLIC_ACCESS_MODIFIERS));
1725                         }
1726                         return StdKeyDeserializers.constructEnumKeyDeserializer(enumRes, factory);
1727                     }
1728                 }
1729                 throw new IllegalArgumentException("Unsuitable method ("+factory+") decorated with @JsonCreator (for Enum type "
1730                         +enumClass.getName()+")");
1731             }
1732         }
1733         // Also, need to consider @JsonValue, if one found
1734         return StdKeyDeserializers.constructEnumKeyDeserializer(enumRes);
1735     }
1736
1737     /*
1738     /**********************************************************
1739     /* DeserializerFactory impl: checking explicitly registered desers
1740     /**********************************************************
1741      */

1742
1743     @Override
1744     public boolean hasExplicitDeserializerFor(DeserializationConfig config,
1745             Class<?> valueType)
1746     {
1747         // First things first: unpeel Array types as the element type is
1748         // what we are interested in -- this because we will always support array
1749         // types via composition, and since array types are JDK provided (and hence
1750         // can not be custom or customized).
1751         while (valueType.isArray()) {
1752             valueType = valueType.getComponentType();
1753         }
1754
1755         // Yes, we handle all Enum types
1756         if (Enum.class.isAssignableFrom(valueType)) {
1757             return true;
1758         }
1759         // Numbers?
1760         final String clsName = valueType.getName();
1761         if (clsName.startsWith("java.")) {
1762             if (Collection.class.isAssignableFrom(valueType)) {
1763                 return true;
1764             }
1765             if (Map.class.isAssignableFrom(valueType)) {
1766                 return true;
1767             }
1768             if (Number.class.isAssignableFrom(valueType)) {
1769                 return NumberDeserializers.find(valueType, clsName) != null;
1770             }
1771             if (JdkDeserializers.hasDeserializerFor(valueType)
1772                     || (valueType == CLASS_STRING)
1773                     || (valueType == Boolean.class)
1774                     || (valueType == EnumMap.class)
1775                     || (valueType == AtomicReference.class)
1776                     ) {
1777                 return true;
1778             }
1779             if (DateDeserializers.hasDeserializerFor(valueType)) {
1780                 return true;
1781             }
1782         } else if (clsName.startsWith("com.fasterxml.")) {
1783             return JsonNode.class.isAssignableFrom(valueType)
1784                    || (valueType == TokenBuffer.class);
1785         } else {
1786             return OptionalHandlerFactory.instance.hasDeserializerFor(valueType);
1787         }
1788         return false;
1789     }
1790
1791     /*
1792     /**********************************************************
1793     /* Extended API
1794     /**********************************************************
1795      */

1796
1797     /**
1798      * Method called to create a type information deserializer for values of
1799      * given non-container property, if one is needed.
1800      * If not needed (no polymorphic handling configured for property), should return null.
1801      *<p>
1802      * Note that this method is only called for non-container bean properties,
1803      * and not for values in container types or root values (or container properties)
1804      *
1805      * @param baseType Declared base type of the value to deserializer (actual
1806      *    deserializer type will be this type or its subtype)
1807      * 
1808      * @return Type deserializer to use for given base type, if one is needed; null if not.
1809      */

1810     public TypeDeserializer findPropertyTypeDeserializer(DeserializationConfig config,
1811             JavaType baseType, AnnotatedMember annotated)
1812         throws JsonMappingException
1813     {
1814         AnnotationIntrospector ai = config.getAnnotationIntrospector();
1815         TypeResolverBuilder<?> b = ai.findPropertyTypeResolver(config, annotated, baseType);        
1816         // Defaulting: if no annotations on member, check value class
1817         if (b == null) {
1818             return findTypeDeserializer(config, baseType);
1819         }
1820         // but if annotations found, may need to resolve subtypes:
1821         Collection<NamedType> subtypes = config.getSubtypeResolver().collectAndResolveSubtypesByTypeId(
1822                 config, annotated, baseType);
1823         try {
1824             return b.buildTypeDeserializer(config, baseType, subtypes);
1825         } catch (IllegalArgumentException e0) {
1826             InvalidDefinitionException e = InvalidDefinitionException.from((JsonParser) null,
1827                     ClassUtil.exceptionMessage(e0), baseType);
1828             e.initCause(e0);
1829             throw e;
1830         }
1831     }
1832     
1833     /**
1834      * Method called to find and create a type information deserializer for values of
1835      * given container (list, array, map) property, if one is needed.
1836      * If not needed (no polymorphic handling configured for property), should return null.
1837      *<p>
1838      * Note that this method is only called for container bean properties,
1839      * and not for values in container types or root values (or non-container properties)
1840      * 
1841      * @param containerType Type of property; must be a container type
1842      * @param propertyEntity Field or method that contains container property
1843      */
    
1844     public TypeDeserializer findPropertyContentTypeDeserializer(DeserializationConfig config,
1845             JavaType containerType, AnnotatedMember propertyEntity)
1846         throws JsonMappingException
1847     {
1848         AnnotationIntrospector ai = config.getAnnotationIntrospector();
1849         TypeResolverBuilder<?> b = ai.findPropertyContentTypeResolver(config, propertyEntity, containerType);        
1850         JavaType contentType = containerType.getContentType();
1851         // Defaulting: if no annotations on member, check class
1852         if (b == null) {
1853             return findTypeDeserializer(config, contentType);
1854         }
1855         // but if annotations found, may need to resolve subtypes:
1856         Collection<NamedType> subtypes = config.getSubtypeResolver().collectAndResolveSubtypesByTypeId(
1857                 config, propertyEntity, contentType);
1858         return b.buildTypeDeserializer(config, contentType, subtypes);
1859     }
1860
1861     /**
1862      * Helper method called to find one of default serializers for "well-known"
1863      * platform types: JDK-provided types, and small number of public Jackson
1864      * API types.
1865      * 
1866      * @since 2.2
1867      */

1868     public JsonDeserializer<?> findDefaultDeserializer(DeserializationContext ctxt,
1869             JavaType type, BeanDescription beanDesc)
1870         throws JsonMappingException
1871     {
1872         Class<?> rawType = type.getRawClass();
1873         // Object ("untyped"), and as of 2.10 (see [databind#2115]), `java.io.Serializable`
1874         if ((rawType == CLASS_OBJECT) || (rawType == CLASS_SERIALIZABLE)) {
1875             // 11-Feb-2015, tatu: As per [databind#700] need to be careful wrt non-default Map, List.
1876             DeserializationConfig config = ctxt.getConfig();
1877             JavaType lt, mt;
1878             
1879             if (_factoryConfig.hasAbstractTypeResolvers()) {
1880                 lt = _findRemappedType(config, List.class);
1881                 mt = _findRemappedType(config, Map.class);
1882             } else {
1883                 lt = mt = null;
1884             }
1885             return new UntypedObjectDeserializer(lt, mt);
1886         }
1887         // String and equivalents
1888         if (rawType == CLASS_STRING || rawType == CLASS_CHAR_SEQUENCE) {
1889             return StringDeserializer.instance;
1890         }
1891         if (rawType == CLASS_ITERABLE) {
1892             // [databind#199]: Can and should 'upgrade' to a Collection type:
1893             TypeFactory tf = ctxt.getTypeFactory();
1894             JavaType[] tps = tf.findTypeParameters(type, CLASS_ITERABLE);
1895             JavaType elemType = (tps == null || tps.length != 1) ? TypeFactory.unknownType() : tps[0];
1896             CollectionType ct = tf.constructCollectionType(Collection.class, elemType);
1897             // Should we re-introspect beanDesc? For now let's not...
1898             return createCollectionDeserializer(ctxt, ct, beanDesc);
1899         }
1900         if (rawType == CLASS_MAP_ENTRY) {
1901             // 28-Apr-2015, tatu: TypeFactory does it all for us already so
1902             JavaType kt = type.containedTypeOrUnknown(0);
1903             JavaType vt = type.containedTypeOrUnknown(1);
1904             TypeDeserializer vts = (TypeDeserializer) vt.getTypeHandler();
1905             if (vts == null) {
1906                 vts = findTypeDeserializer(ctxt.getConfig(), vt);
1907             }
1908             JsonDeserializer<Object> valueDeser = vt.getValueHandler();
1909             KeyDeserializer keyDes = (KeyDeserializer) kt.getValueHandler();
1910             return new MapEntryDeserializer(type, keyDes, valueDeser, vts);
1911         }
1912         String clsName = rawType.getName();
1913         if (rawType.isPrimitive() || clsName.startsWith("java.")) {
1914             // Primitives/wrappers, other Numbers:
1915             JsonDeserializer<?> deser = NumberDeserializers.find(rawType, clsName);
1916             if (deser == null) {
1917                 deser = DateDeserializers.find(rawType, clsName);
1918             }
1919             if (deser != null) {
1920                 return deser;
1921             }
1922         }
1923         // and a few Jackson types as well:
1924         if (rawType == TokenBuffer.class) {
1925             return new TokenBufferDeserializer();
1926         }
1927         JsonDeserializer<?> deser = findOptionalStdDeserializer(ctxt, type, beanDesc);
1928         if (deser != null) {
1929             return deser;
1930         }
1931         return JdkDeserializers.find(rawType, clsName);
1932     }
1933
1934     protected JavaType _findRemappedType(DeserializationConfig config, Class<?> rawType) throws JsonMappingException {
1935         JavaType type = mapAbstractType(config, config.constructType(rawType));
1936         return (type == null || type.hasRawClass(rawType)) ? null : type;
1937     }
1938
1939     /*
1940     /**********************************************************
1941     /* Helper methods, finding custom deserializers
1942     /**********************************************************
1943      */

1944
1945     protected JsonDeserializer<?> _findCustomTreeNodeDeserializer(Class<? extends JsonNode> type,
1946             DeserializationConfig config, BeanDescription beanDesc)
1947         throws JsonMappingException
1948     {
1949         for (Deserializers d  : _factoryConfig.deserializers()) {
1950             JsonDeserializer<?> deser = d.findTreeNodeDeserializer(type, config, beanDesc);
1951             if (deser != null) {
1952                 return deser;
1953             }
1954         }
1955         return null;
1956     }
1957
1958     protected JsonDeserializer<?> _findCustomReferenceDeserializer(ReferenceType type,
1959             DeserializationConfig config, BeanDescription beanDesc,
1960             TypeDeserializer contentTypeDeserializer, JsonDeserializer<?> contentDeserializer)
1961         throws JsonMappingException
1962     {
1963         for (Deserializers d  : _factoryConfig.deserializers()) {
1964             JsonDeserializer<?> deser = d.findReferenceDeserializer(type, config, beanDesc,
1965                     contentTypeDeserializer, contentDeserializer);
1966             if (deser != null) {
1967                 return deser;
1968             }
1969         }
1970         return null;
1971     }
1972
1973     @SuppressWarnings("unchecked")
1974     protected JsonDeserializer<Object> _findCustomBeanDeserializer(JavaType type,
1975             DeserializationConfig config, BeanDescription beanDesc)
1976         throws JsonMappingException
1977     {
1978         for (Deserializers d  : _factoryConfig.deserializers()) {
1979             JsonDeserializer<?> deser = d.findBeanDeserializer(type, config, beanDesc);
1980             if (deser != null) {
1981                 return (JsonDeserializer<Object>) deser;
1982             }
1983         }
1984         return null;
1985     }
1986
1987     protected JsonDeserializer<?> _findCustomArrayDeserializer(ArrayType type,
1988             DeserializationConfig config, BeanDescription beanDesc,
1989             TypeDeserializer elementTypeDeserializer, JsonDeserializer<?> elementDeserializer)
1990         throws JsonMappingException
1991     {
1992         for (Deserializers d  : _factoryConfig.deserializers()) {
1993             JsonDeserializer<?> deser = d.findArrayDeserializer(type, config,
1994                     beanDesc, elementTypeDeserializer, elementDeserializer);
1995             if (deser != null) {
1996                 return deser;
1997             }
1998         }
1999         return null;
2000     }
2001     
2002     protected JsonDeserializer<?> _findCustomCollectionDeserializer(CollectionType type,
2003             DeserializationConfig config, BeanDescription beanDesc,
2004             TypeDeserializer elementTypeDeserializer, JsonDeserializer<?> elementDeserializer)
2005         throws JsonMappingException
2006     {
2007         for (Deserializers d  : _factoryConfig.deserializers()) {
2008             JsonDeserializer<?> deser = d.findCollectionDeserializer(type, config, beanDesc,
2009                     elementTypeDeserializer, elementDeserializer);
2010             if (deser != null) {
2011                 return deser;
2012             }
2013         }
2014         return null;
2015     }
2016     
2017     protected JsonDeserializer<?> _findCustomCollectionLikeDeserializer(CollectionLikeType type,
2018             DeserializationConfig config, BeanDescription beanDesc,
2019             TypeDeserializer elementTypeDeserializer, JsonDeserializer<?> elementDeserializer)
2020         throws JsonMappingException
2021     {
2022         for (Deserializers d  : _factoryConfig.deserializers()) {
2023             JsonDeserializer<?> deser = d.findCollectionLikeDeserializer(type, config, beanDesc,
2024                     elementTypeDeserializer, elementDeserializer);
2025             if (deser != null) {
2026                 return deser;
2027             }
2028         }
2029         return null;
2030     }
2031
2032     protected JsonDeserializer<?> _findCustomEnumDeserializer(Class<?> type,
2033             DeserializationConfig config, BeanDescription beanDesc)
2034         throws JsonMappingException
2035     {
2036         for (Deserializers d  : _factoryConfig.deserializers()) {
2037             JsonDeserializer<?> deser = d.findEnumDeserializer(type, config, beanDesc);
2038             if (deser != null) {
2039                 return deser;
2040             }
2041         }
2042         return null;
2043     }
2044     
2045     protected JsonDeserializer<?> _findCustomMapDeserializer(MapType type,
2046             DeserializationConfig config, BeanDescription beanDesc,
2047             KeyDeserializer keyDeserializer,
2048             TypeDeserializer elementTypeDeserializer, JsonDeserializer<?> elementDeserializer)
2049         throws JsonMappingException
2050     {
2051         for (Deserializers d  : _factoryConfig.deserializers()) {
2052             JsonDeserializer<?> deser = d.findMapDeserializer(type, config, beanDesc,
2053                     keyDeserializer, elementTypeDeserializer, elementDeserializer);
2054             if (deser != null) {
2055                 return deser;
2056             }
2057         }
2058         return null;
2059     }
2060
2061     protected JsonDeserializer<?> _findCustomMapLikeDeserializer(MapLikeType type,
2062             DeserializationConfig config, BeanDescription beanDesc,
2063             KeyDeserializer keyDeserializer,
2064             TypeDeserializer elementTypeDeserializer, JsonDeserializer<?> elementDeserializer)
2065         throws JsonMappingException
2066     {
2067         for (Deserializers d  : _factoryConfig.deserializers()) {
2068             JsonDeserializer<?> deser = d.findMapLikeDeserializer(type, config, beanDesc,
2069                     keyDeserializer, elementTypeDeserializer, elementDeserializer);
2070             if (deser != null) {
2071                 return deser;
2072             }
2073         }
2074         return null;
2075     }
2076
2077     /*
2078     /**********************************************************
2079     /* Helper methods, value/content/key type introspection
2080     /**********************************************************
2081      */

2082     
2083     /**
2084      * Helper method called to check if a class or method
2085      * has annotation that tells which class to use for deserialization; and if
2086      * so, to instantiate, that deserializer to use.
2087      * Note that deserializer will NOT yet be contextualized so caller needs to
2088      * take care to call contextualization appropriately.
2089      * Returns null if no such annotation found.
2090      */

2091     protected JsonDeserializer<Object> findDeserializerFromAnnotation(DeserializationContext ctxt,
2092             Annotated ann)
2093         throws JsonMappingException
2094     {
2095         AnnotationIntrospector intr = ctxt.getAnnotationIntrospector();
2096         if (intr != null) {
2097             Object deserDef = intr.findDeserializer(ann);
2098             if (deserDef != null) {
2099                 return ctxt.deserializerInstance(ann, deserDef);
2100             }
2101         }
2102         return null;
2103     }
2104
2105     /**
2106      * Helper method called to check if a class or method
2107      * has annotation that tells which class to use for deserialization of {@link java.util.Map} keys.
2108      * Returns null if no such annotation found.
2109      */

2110     protected KeyDeserializer findKeyDeserializerFromAnnotation(DeserializationContext ctxt,
2111             Annotated ann)
2112             throws JsonMappingException
2113     {
2114         AnnotationIntrospector intr = ctxt.getAnnotationIntrospector();
2115         if (intr != null) {
2116             Object deserDef = intr.findKeyDeserializer(ann);
2117             if (deserDef != null) {
2118                 return ctxt.keyDeserializerInstance(ann, deserDef);
2119             }
2120         }
2121         return null;
2122     }
2123
2124     /**
2125      * @since 2.9
2126      */

2127     protected JsonDeserializer<Object> findContentDeserializerFromAnnotation(DeserializationContext ctxt,
2128             Annotated ann)
2129         throws JsonMappingException
2130     {
2131         AnnotationIntrospector intr = ctxt.getAnnotationIntrospector();
2132         if (intr != null) {
2133             Object deserDef = intr.findContentDeserializer(ann);
2134             if (deserDef != null) {
2135                 return ctxt.deserializerInstance(ann, deserDef);
2136             }
2137         }
2138         return null;
2139     }
2140     
2141     /**
2142      * Helper method used to resolve additional type-related annotation information
2143      * like type overrides, or handler (serializer, deserializer) overrides,
2144      * so that from declared field, property or constructor parameter type
2145      * is used as the base and modified based on annotations, if any.
2146      * 
2147      * @since 2.8 Combines functionality of <code>modifyTypeByAnnotation</code>
2148      *     and <code>resolveType</code>
2149      */

2150     protected JavaType resolveMemberAndTypeAnnotations(DeserializationContext ctxt,
2151             AnnotatedMember member, JavaType type)
2152         throws JsonMappingException
2153     {
2154         AnnotationIntrospector intr = ctxt.getAnnotationIntrospector();
2155         if (intr == null) {
2156             return type;
2157         }
2158
2159         // First things first: see if we can find annotations on declared
2160         // type
2161
2162         if (type.isMapLikeType()) {
2163             JavaType keyType = type.getKeyType();
2164             if (keyType != null) {
2165                 Object kdDef = intr.findKeyDeserializer(member);
2166                 KeyDeserializer kd = ctxt.keyDeserializerInstance(member, kdDef);
2167                 if (kd != null) {
2168                     type = ((MapLikeType) type).withKeyValueHandler(kd);
2169                     keyType = type.getKeyType(); // just in case it's used below
2170                 }
2171             }
2172         }
2173
2174         if (type.hasContentType()) { // that is, is either container- or reference-type
2175             Object cdDef = intr.findContentDeserializer(member);
2176             JsonDeserializer<?> cd = ctxt.deserializerInstance(member, cdDef);
2177             if (cd != null) {
2178                 type = type.withContentValueHandler(cd);
2179             }
2180             TypeDeserializer contentTypeDeser = findPropertyContentTypeDeserializer(
2181                     ctxt.getConfig(), type, (AnnotatedMember) member);                
2182             if (contentTypeDeser != null) {
2183                 type = type.withContentTypeHandler(contentTypeDeser);
2184             }
2185         }
2186         TypeDeserializer valueTypeDeser = findPropertyTypeDeserializer(ctxt.getConfig(),
2187                     type, (AnnotatedMember) member);
2188         if (valueTypeDeser != null) {
2189             type = type.withTypeHandler(valueTypeDeser);
2190         }
2191
2192         // Second part: find actual type-override annotations on member, if any
2193
2194         // 18-Jun-2016, tatu: Should we re-do checks for annotations on refined
2195         //   subtypes as well? Code pre-2.8 did not do this, but if we get bug
2196         //   reports may need to consider
2197         type = intr.refineDeserializationType(ctxt.getConfig(), member, type);
2198         return type;
2199     }
2200
2201     protected EnumResolver constructEnumResolver(Class<?> enumClass,
2202             DeserializationConfig config, AnnotatedMember jsonValueAccessor)
2203     {
2204         if (jsonValueAccessor != null) {
2205             if (config.canOverrideAccessModifiers()) {
2206                 ClassUtil.checkAndFixAccess(jsonValueAccessor.getMember(),
2207                         config.isEnabled(MapperFeature.OVERRIDE_PUBLIC_ACCESS_MODIFIERS));
2208             }
2209             return EnumResolver.constructUnsafeUsingMethod(enumClass,
2210                     jsonValueAccessor, config.getAnnotationIntrospector());
2211         }
2212         // 14-Mar-2016, tatu: We used to check `DeserializationFeature.READ_ENUMS_USING_TO_STRING`
2213         //   here, but that won't do: it must be dynamically changeable...
2214         return EnumResolver.constructUnsafe(enumClass, config.getAnnotationIntrospector());
2215     }
2216
2217     /**
2218      * @since 2.9
2219      */

2220     protected boolean _hasCreatorAnnotation(DeserializationContext ctxt,
2221             Annotated ann) {
2222         AnnotationIntrospector intr = ctxt.getAnnotationIntrospector();
2223         if (intr != null) {
2224             JsonCreator.Mode mode = intr.findCreatorAnnotation(ctxt.getConfig(), ann);
2225             return (mode != null) && (mode != JsonCreator.Mode.DISABLED); 
2226         }
2227         return false;
2228     }
2229
2230     /*
2231     /**********************************************************
2232     /* Deprecated helper methods
2233     /**********************************************************
2234      */

2235     
2236     /**
2237      * Method called to see if given method has annotations that indicate
2238      * a more specific type than what the argument specifies.
2239      *
2240      * @deprecated Since 2.8; call {@link #resolveMemberAndTypeAnnotations} instead
2241      */

2242     @Deprecated
2243     protected JavaType modifyTypeByAnnotation(DeserializationContext ctxt,
2244             Annotated a, JavaType type)
2245         throws JsonMappingException
2246     {
2247         AnnotationIntrospector intr = ctxt.getAnnotationIntrospector();
2248         if (intr == null) {
2249             return type;
2250         }
2251         return intr.refineDeserializationType(ctxt.getConfig(), a, type);
2252     }
2253
2254     /**
2255      * @deprecated since 2.8 call {@link #resolveMemberAndTypeAnnotations} instead.
2256      */

2257     @Deprecated // since 2.8
2258     protected JavaType resolveType(DeserializationContext ctxt,
2259             BeanDescription beanDesc, JavaType type, AnnotatedMember member)
2260         throws JsonMappingException
2261     {
2262         return resolveMemberAndTypeAnnotations(ctxt, member, type);
2263     }
2264
2265     /**
2266      * @deprecated since 2.8 call <code>findJsonValueMethod</code> on {@link BeanDescription} instead
2267      */

2268     @Deprecated // not used, possibly remove as early as 2.9
2269     protected AnnotatedMethod _findJsonValueFor(DeserializationConfig config, JavaType enumType)
2270     {
2271         if (enumType == null) {
2272             return null;
2273         }
2274         BeanDescription beanDesc = config.introspect(enumType);
2275         return beanDesc.findJsonValueMethod();
2276     }
2277
2278     /**
2279      * Helper class to contain default mappings for abstract JDK {@link java.util.Collection}
2280      * and {@link java.util.Map} types. Separated out here to defer cost of creating lookups
2281      * until mappings are actually needed.
2282      *
2283      * @since 2.10
2284      */

2285     @SuppressWarnings("rawtypes")
2286     protected static class ContainerDefaultMappings {
2287         // We do some defaulting for abstract Collection classes and
2288         // interfaces, to avoid having to use exact types or annotations in
2289         // cases where the most common concrete Collection will do.
2290         final static HashMap<String, Class<? extends Collection>> _collectionFallbacks;
2291         static {
2292             HashMap<String, Class<? extends Collection>> fallbacks = new HashMap<>();
2293
2294             final Class<? extends Collection> DEFAULT_LIST = ArrayList.class;
2295             final Class<? extends Collection> DEFAULT_SET = HashSet.class;
2296
2297             fallbacks.put(Collection.class.getName(), DEFAULT_LIST);
2298             fallbacks.put(List.class.getName(), DEFAULT_LIST);
2299             fallbacks.put(Set.class.getName(), DEFAULT_SET);
2300             fallbacks.put(SortedSet.class.getName(), TreeSet.class);
2301             fallbacks.put(Queue.class.getName(), LinkedList.class);
2302
2303             // 09-Feb-2019, tatu: How did we miss these? Related in [databind#2251] problem
2304             fallbacks.put(AbstractList.class.getName(), DEFAULT_LIST);
2305             fallbacks.put(AbstractSet.class.getName(), DEFAULT_SET);
2306
2307             // 09-Feb-2019, tatu: And more esoteric types added in JDK6
2308             fallbacks.put(Deque.class.getName(), LinkedList.class);
2309             fallbacks.put(NavigableSet.class.getName(), TreeSet.class);
2310
2311             _collectionFallbacks = fallbacks;
2312         }
2313
2314         // We do some defaulting for abstract Map classes and
2315         // interfaces, to avoid having to use exact types or annotations in
2316         // cases where the most common concrete Maps will do.
2317         final static HashMap<String, Class<? extends Map>> _mapFallbacks;
2318         static {
2319             HashMap<String, Class<? extends Map>> fallbacks = new HashMap<>();
2320
2321             final Class<? extends Map> DEFAULT_MAP = LinkedHashMap.class;
2322             fallbacks.put(Map.class.getName(), DEFAULT_MAP);
2323             fallbacks.put(AbstractMap.class.getName(), DEFAULT_MAP);
2324             fallbacks.put(ConcurrentMap.class.getName(), ConcurrentHashMap.class);
2325             fallbacks.put(SortedMap.class.getName(), TreeMap.class);
2326
2327             fallbacks.put(java.util.NavigableMap.class.getName(), TreeMap.class);
2328             fallbacks.put(java.util.concurrent.ConcurrentNavigableMap.class.getName(),
2329                     java.util.concurrent.ConcurrentSkipListMap.class);
2330
2331             _mapFallbacks = fallbacks;
2332         }
2333
2334         public static Class<?> findCollectionFallback(JavaType type) {
2335             return _collectionFallbacks.get(type.getRawClass().getName());
2336         }
2337
2338         public static Class<?> findMapFallback(JavaType type) {
2339             return _mapFallbacks.get(type.getRawClass().getName());
2340         }
2341     }
2342 }
2343