1 package com.fasterxml.jackson.databind.introspect;
2
3 import java.lang.annotation.Annotation;
4 import java.lang.reflect.Field;
5 import java.util.*;
6
7 import com.fasterxml.jackson.annotation.*;
8 import com.fasterxml.jackson.core.Version;
9 import com.fasterxml.jackson.databind.*;
10 import com.fasterxml.jackson.databind.annotation.*;
11 import com.fasterxml.jackson.databind.cfg.HandlerInstantiator;
12 import com.fasterxml.jackson.databind.cfg.MapperConfig;
13 import com.fasterxml.jackson.databind.ext.Java7Support;
14 import com.fasterxml.jackson.databind.jsontype.NamedType;
15 import com.fasterxml.jackson.databind.jsontype.TypeIdResolver;
16 import com.fasterxml.jackson.databind.jsontype.TypeResolverBuilder;
17 import com.fasterxml.jackson.databind.jsontype.impl.StdTypeResolverBuilder;
18 import com.fasterxml.jackson.databind.ser.BeanPropertyWriter;
19 import com.fasterxml.jackson.databind.ser.VirtualBeanPropertyWriter;
20 import com.fasterxml.jackson.databind.ser.impl.AttributePropertyWriter;
21 import com.fasterxml.jackson.databind.ser.std.RawSerializer;
22 import com.fasterxml.jackson.databind.type.MapLikeType;
23 import com.fasterxml.jackson.databind.type.TypeFactory;
24 import com.fasterxml.jackson.databind.util.*;
25
26 /**
27  * {@link AnnotationIntrospector} implementation that handles standard
28  * Jackson annotations.
29  */

30 public class JacksonAnnotationIntrospector
31     extends AnnotationIntrospector
32     implements java.io.Serializable
33 {
34     private static final long serialVersionUID = 1L;
35
36     @SuppressWarnings("unchecked")
37     private final static Class<? extends Annotation>[] ANNOTATIONS_TO_INFER_SER = (Class<? extends Annotation>[])
38             new Class<?>[] {
39         JsonSerialize.class,
40         JsonView.class,
41         JsonFormat.class,
42         JsonTypeInfo.class,
43         JsonRawValue.class,
44         JsonUnwrapped.class,
45         JsonBackReference.class,
46         JsonManagedReference.class
47     };
48
49     @SuppressWarnings("unchecked")
50     private final static Class<? extends Annotation>[] ANNOTATIONS_TO_INFER_DESER = (Class<? extends Annotation>[])
51             new Class<?>[] {
52         JsonDeserialize.class,
53         JsonView.class,
54         JsonFormat.class,
55         JsonTypeInfo.class,
56         JsonUnwrapped.class,
57         JsonBackReference.class,
58         JsonManagedReference.class,
59         JsonMerge.class // since 2.9
60     };
61
62     // NOTE: loading of Java7 dependencies is encapsulated by handlers in Java7Support,
63     //  here we do not really need any handling; but for extra-safety use try-catch
64     private static final Java7Support _java7Helper;
65     static {
66         Java7Support x = null;
67         try {
68             x = Java7Support.instance();
69         } catch (Throwable t) { }
70         _java7Helper = x;
71     }
72     
73     /**
74      * Since introspection of annotation types is a performance issue in some
75      * use cases (rare, but do exist), let's try a simple cache to reduce
76      * need for actual meta-annotation introspection.
77      *<p>
78      * Non-final only because it needs to be re-created after deserialization.
79      *
80      * @since 2.7
81      */

82     protected transient LRUMap<Class<?>,Boolean> _annotationsInside = new LRUMap<Class<?>,Boolean>(48, 48);
83
84     /*
85     /**********************************************************
86     /* Local configuration settings
87     /**********************************************************
88      */

89
90     /**
91      * See {@link #setConstructorPropertiesImpliesCreator(boolean)} for
92      * explanation.
93      *<p>
94      * Defaults to true.
95      * 
96      * @since 2.7.4
97      */

98     protected boolean _cfgConstructorPropertiesImpliesCreator = true;
99
100     /*
101     /**********************************************************
102     /* Life-cycle
103     /**********************************************************
104      */

105
106     public JacksonAnnotationIntrospector() { }
107
108     @Override
109     public Version version() {
110         return com.fasterxml.jackson.databind.cfg.PackageVersion.VERSION;
111     }
112
113     protected Object readResolve() {
114         if (_annotationsInside == null) {
115             _annotationsInside = new LRUMap<Class<?>,Boolean>(48, 48);
116         }
117         return this;
118     }
119
120     /*
121     /**********************************************************
122     /* Configuration
123     /**********************************************************
124      */

125
126     /**
127      * Method for changing behavior of {@link java.beans.ConstructorProperties}:
128      * if set to `true`, existence DOES indicate that the given constructor should
129      * be considered a creator; `false` that it should NOT be considered a creator
130      * without explicit use of <code>JsonCreator</code> annotation.
131      *<p>
132      * Default setting is `true`
133      *
134      * @since 2.7.4
135      */

136     public JacksonAnnotationIntrospector setConstructorPropertiesImpliesCreator(boolean b)
137     {
138         _cfgConstructorPropertiesImpliesCreator = b;
139         return this;
140     }
141     
142     /*
143     /**********************************************************
144     /* General annotation properties
145     /**********************************************************
146      */

147
148     /**
149      * Annotations with meta-annotation {@link JacksonAnnotationsInside}
150      * are considered bundles.
151      */

152     @Override
153     public boolean isAnnotationBundle(Annotation ann) {
154         // 22-Sep-2015, tatu: Caching here has modest effect on JavaSE, and only
155         //   mostly in degenerate cases where introspection used more often than
156         //   it should (like recreating ObjectMapper once per read/write).
157         //   But it may be more beneficial on platforms like Android (should verify)
158         Class<?> type = ann.annotationType();
159         Boolean b = _annotationsInside.get(type);
160         if (b == null) {
161             b = type.getAnnotation(JacksonAnnotationsInside.class) != null;
162             _annotationsInside.putIfAbsent(type, b);
163         }
164         return b.booleanValue();
165     }
166
167     /*
168     /**********************************************************
169     /* General annotations
170     /**********************************************************
171      */

172
173     /**
174      * Since 2.6, we have supported use of {@link JsonProperty} for specifying
175      * explicit serialized name
176      */

177     @Override
178     @Deprecated // since 2.8
179     public String findEnumValue(Enum<?> value)
180     {
181         // 11-Jun-2015, tatu: As per [databind#677], need to allow explicit naming.
182         //   Unfortunately cannot quite use standard AnnotatedClass here (due to various
183         //   reasons, including odd representation JVM uses); has to do for now
184         try {
185             // We know that values are actually static fields with matching name so:
186             Field f = value.getClass().getField(value.name());
187             if (f != null) {
188                 JsonProperty prop = f.getAnnotation(JsonProperty.class);
189                 if (prop != null) {
190                     String n = prop.value();
191                     if (n != null && !n.isEmpty()) {
192                         return n;
193                     }
194                 }
195             }
196         } catch (SecurityException e) {
197             // 17-Sep-2015, tatu: Anything we could/should do here?
198         } catch (NoSuchFieldException e) {
199             // 17-Sep-2015, tatu: should not really happen. But... can we do anything?
200         }
201         return value.name();
202     }
203
204     @Override // since 2.7
205     public String[] findEnumValues(Class<?> enumType, Enum<?>[] enumValues, String[] names) {
206         HashMap<String,String> expl = null;
207         for (Field f : enumType.getDeclaredFields()) {
208             if (!f.isEnumConstant()) {
209                 continue;
210             }
211             JsonProperty prop = f.getAnnotation(JsonProperty.class);
212             if (prop == null) {
213                 continue;
214             }
215             String n = prop.value();
216             if (n.isEmpty()) {
217                 continue;
218             }
219             if (expl == null) {
220                 expl = new HashMap<String,String>();
221             }
222             expl.put(f.getName(), n);
223         }
224         // and then stitch them together if and as necessary
225         if (expl != null) {
226             for (int i = 0, end = enumValues.length; i < end; ++i) {
227                 String defName = enumValues[i].name();
228                 String explValue = expl.get(defName);
229                 if (explValue != null) {
230                     names[i] = explValue;
231                 }
232             }
233         }
234         return names;
235     }
236
237     @Override // since 2.11
238     public void findEnumAliases(Class<?> enumType, Enum<?>[] enumValues, String[][] aliasList)
239     {
240         // Main complication: discrepancy between Field that represent enum value,
241         // Enum abstraction; joint by name but not reference
242         for (Field f : enumType.getDeclaredFields()) {
243             if (f.isEnumConstant()) {
244                 JsonAlias aliasAnnotation = f.getAnnotation(JsonAlias.class);
245                 if (aliasAnnotation != null) {
246                     String[] aliases = aliasAnnotation.value();
247                     if (aliases.length != 0) {
248                         final String name = f.getName();
249                         // Find matching enum (could create Ma
250                         for (int i = 0, end = enumValues.length; i < end; ++i) {
251                             if (name.equals(enumValues[i].name())) {
252                                 aliasList[i] = aliases;
253                             }
254                         }
255                     }
256                 }
257             }
258         }
259     }
260
261     /**
262      * Finds the Enum value that should be considered the default value, if possible.
263      * <p>
264      * This implementation relies on {@link JsonEnumDefaultValue} annotation to determine the default value if present.
265      *
266      * @param enumCls The Enum class to scan for the default value.
267      * @return null if none found or it's not possible to determine one.
268      * @since 2.8
269      */

270     @Override
271     public Enum<?> findDefaultEnumValue(Class<Enum<?>> enumCls) {
272         return ClassUtil.findFirstAnnotatedEnumValue(enumCls, JsonEnumDefaultValue.class);
273     }
274
275     /*
276     /**********************************************************
277     /* General class annotations
278     /**********************************************************
279      */

280
281     @Override
282     public PropertyName findRootName(AnnotatedClass ac)
283     {
284         JsonRootName ann = _findAnnotation(ac, JsonRootName.class);
285         if (ann == null) {
286             return null;
287         }
288         String ns = ann.namespace();
289         if (ns != null && ns.length() == 0) {
290             ns = null;
291         }
292         return PropertyName.construct(ann.value(), ns);
293     }
294
295     @Override // since 2.8
296     public JsonIgnoreProperties.Value findPropertyIgnorals(Annotated a)
297     {
298         JsonIgnoreProperties v = _findAnnotation(a, JsonIgnoreProperties.class);
299         if (v == null) {
300             return JsonIgnoreProperties.Value.empty();
301         }
302         return JsonIgnoreProperties.Value.from(v);
303     }
304
305     @Override
306     public Boolean isIgnorableType(AnnotatedClass ac) {
307         JsonIgnoreType ignore = _findAnnotation(ac, JsonIgnoreType.class);
308         return (ignore == null) ? null : ignore.value();
309     }
310  
311     @Override
312     public Object findFilterId(Annotated a) {
313         JsonFilter ann = _findAnnotation(a, JsonFilter.class);
314         if (ann != null) {
315             String id = ann.value();
316             // Empty String is same as not having annotation, to allow overrides
317             if (id.length() > 0) {
318                 return id;
319             }
320         }
321         return null;
322     }
323
324     @Override
325     public Object findNamingStrategy(AnnotatedClass ac)
326     {
327         JsonNaming ann = _findAnnotation(ac, JsonNaming.class);
328         return (ann == null) ? null : ann.value();
329     }
330
331     @Override
332     public String findClassDescription(AnnotatedClass ac) {
333         JsonClassDescription ann = _findAnnotation(ac, JsonClassDescription.class);
334         return (ann == null) ? null : ann.value();
335     }
336
337     /*
338     /**********************************************************
339     /* Property auto-detection
340     /**********************************************************
341      */

342
343     @Override
344     public VisibilityChecker<?> findAutoDetectVisibility(AnnotatedClass ac,
345         VisibilityChecker<?> checker)
346     {
347         JsonAutoDetect ann = _findAnnotation(ac, JsonAutoDetect.class);
348         return (ann == null) ? checker : checker.with(ann);
349     }
350
351     /*
352     /**********************************************************
353     /* General member (field, method/constructor) annotations
354     /**********************************************************
355      */

356
357     @Override
358     public String findImplicitPropertyName(AnnotatedMember m) {
359         PropertyName n = _findConstructorName(m);
360         return (n == null) ? null : n.getSimpleName();
361     }
362
363     @Override
364     public List<PropertyName> findPropertyAliases(Annotated m) {
365         JsonAlias ann = _findAnnotation(m, JsonAlias.class);
366         if (ann == null) {
367             return null;
368         }
369         String[] strs = ann.value();
370         final int len = strs.length;
371         if (len == 0) {
372             return Collections.emptyList();
373         }
374         List<PropertyName> result = new ArrayList<>(len);
375         for (int i = 0; i < len; ++i) {
376             result.add(PropertyName.construct(strs[i]));
377         }
378         return result;
379     }
380
381     @Override
382     public boolean hasIgnoreMarker(AnnotatedMember m) {
383         return _isIgnorable(m);
384     }
385
386     @Override
387     public Boolean hasRequiredMarker(AnnotatedMember m)
388     {
389         JsonProperty ann = _findAnnotation(m, JsonProperty.class);
390         if (ann != null) {
391             return ann.required();
392         }
393         return null;
394     }
395
396     @Override
397     public JsonProperty.Access findPropertyAccess(Annotated m) {
398         JsonProperty ann = _findAnnotation(m, JsonProperty.class);
399         if (ann != null) {
400             return ann.access();
401         }
402         return null;
403     }
404
405     @Override
406     public String findPropertyDescription(Annotated ann) {
407         JsonPropertyDescription desc = _findAnnotation(ann, JsonPropertyDescription.class);
408         return (desc == null) ? null : desc.value();
409     }
410
411     @Override
412     public Integer findPropertyIndex(Annotated ann) {
413         JsonProperty prop = _findAnnotation(ann, JsonProperty.class);
414         if (prop != null) {
415           int ix = prop.index();
416           if (ix != JsonProperty.INDEX_UNKNOWN) {
417                return Integer.valueOf(ix);
418           }
419         }
420         return null;
421     }
422     
423     @Override
424     public String findPropertyDefaultValue(Annotated ann) {
425         JsonProperty prop = _findAnnotation(ann, JsonProperty.class);
426         if (prop == null) {
427             return null;
428         }
429         String str = prop.defaultValue();
430         // Since annotations do not allow nulls, need to assume empty means "none"
431         return str.isEmpty() ? null : str;
432     }
433     
434     @Override
435     public JsonFormat.Value findFormat(Annotated ann) {
436         JsonFormat f = _findAnnotation(ann, JsonFormat.class);
437         // NOTE: could also just call `JsonFormat.Value.from()` with `null`
438         // too, but that returns "empty" instance
439         return (f == null)  ? null : JsonFormat.Value.from(f);
440     }
441
442     @Override        
443     public ReferenceProperty findReferenceType(AnnotatedMember member)
444     {
445         JsonManagedReference ref1 = _findAnnotation(member, JsonManagedReference.class);
446         if (ref1 != null) {
447             return AnnotationIntrospector.ReferenceProperty.managed(ref1.value());
448         }
449         JsonBackReference ref2 = _findAnnotation(member, JsonBackReference.class);
450         if (ref2 != null) {
451             return AnnotationIntrospector.ReferenceProperty.back(ref2.value());
452         }
453         return null;
454     }
455
456     @Override
457     public NameTransformer findUnwrappingNameTransformer(AnnotatedMember member)
458     {
459         JsonUnwrapped ann = _findAnnotation(member, JsonUnwrapped.class);
460         // if not enabled, just means annotation is not enabled; not necessarily
461         // that unwrapping should not be done (relevant when using chained introspectors)
462         if (ann == null || !ann.enabled()) {
463             return null;
464         }
465         String prefix = ann.prefix();
466         String suffix = ann.suffix();
467         return NameTransformer.simpleTransformer(prefix, suffix);
468     }
469
470     @Override // since 2.9
471     public JacksonInject.Value findInjectableValue(AnnotatedMember m) {
472         JacksonInject ann = _findAnnotation(m, JacksonInject.class);
473         if (ann == null) {
474             return null;
475         }
476         // Empty String means that we should use name of declared value class.
477         JacksonInject.Value v = JacksonInject.Value.from(ann);
478         if (!v.hasId()) {
479             Object id;
480             // slight complication; for setters, type 
481             if (!(m instanceof AnnotatedMethod)) {
482                 id = m.getRawType().getName();
483             } else {
484                 AnnotatedMethod am = (AnnotatedMethod) m;
485                 if (am.getParameterCount() == 0) { // getter
486                     id = m.getRawType().getName();
487                 } else { // setter
488                     id = am.getRawParameterType(0).getName();
489                 }
490             }
491             v = v.withId(id);
492         }
493         return v;
494     }
495
496     @Override
497     @Deprecated // since 2.9
498     public Object findInjectableValueId(AnnotatedMember m) {
499         JacksonInject.Value v = findInjectableValue(m);
500         return (v == null) ? null : v.getId();
501     }
502
503     @Override
504     public Class<?>[] findViews(Annotated a)
505     {
506         JsonView ann = _findAnnotation(a, JsonView.class);
507         return (ann == null) ? null : ann.value();
508     }
509
510     @Override // since 2.7
511     public AnnotatedMethod resolveSetterConflict(MapperConfig<?> config,
512             AnnotatedMethod setter1, AnnotatedMethod setter2)
513     {
514         Class<?> cls1 = setter1.getRawParameterType(0);
515         Class<?> cls2 = setter2.getRawParameterType(0);
516         
517         // First: prefer primitives over non-primitives
518         // 11-Dec-2015, tatu: TODO, perhaps consider wrappers for primitives too?
519         if (cls1.isPrimitive()) {
520             if (!cls2.isPrimitive()) {
521                 return setter1;
522             }
523         } else if (cls2.isPrimitive()) {
524             return setter2;
525         }
526         
527         if (cls1 == String.class) {
528             if (cls2 != String.class) {
529                 return setter1;
530             }
531         } else if (cls2 == String.class) {
532             return setter2;
533         }
534
535         return null;
536     }
537
538     @Override // since 2.11
539     public PropertyName findRenameByField(MapperConfig<?> config,
540             AnnotatedField f, PropertyName implName) {
541         // Nothing to report, only used by modules. But define just as documentation
542         return null;
543     }
544     
545     /*
546     /**********************************************************
547     /* Annotations for Polymorphic Type handling
548     /**********************************************************
549      */

550
551     @Override
552     public TypeResolverBuilder<?> findTypeResolver(MapperConfig<?> config,
553             AnnotatedClass ac, JavaType baseType)
554     {
555         return _findTypeResolver(config, ac, baseType);
556     }
557
558     @Override
559     public TypeResolverBuilder<?> findPropertyTypeResolver(MapperConfig<?> config,
560             AnnotatedMember am, JavaType baseType)
561     {
562         /* As per definition of @JsonTypeInfo, should only apply to contents of container
563          * (collection, map) types, not container types themselves:
564          */

565         // 17-Apr-2016, tatu: For 2.7.4 make sure ReferenceType also included
566         if (baseType.isContainerType() || baseType.isReferenceType()) {
567             return null;
568         }
569         // No per-member type overrides (yet)
570         return _findTypeResolver(config, am, baseType);
571     }
572
573     @Override
574     public TypeResolverBuilder<?> findPropertyContentTypeResolver(MapperConfig<?> config,
575             AnnotatedMember am, JavaType containerType)
576     {
577         /* First: let's ensure property is a container type: caller should have
578          * verified but just to be sure
579          */

580         if (containerType.getContentType() == null) {
581             throw new IllegalArgumentException("Must call method with a container or reference type (got "+containerType+")");
582         }
583         return _findTypeResolver(config, am, containerType);
584     }
585     
586     @Override
587     public List<NamedType> findSubtypes(Annotated a)
588     {
589         JsonSubTypes t = _findAnnotation(a, JsonSubTypes.class);
590         if (t == nullreturn null;
591         JsonSubTypes.Type[] types = t.value();
592         ArrayList<NamedType> result = new ArrayList<NamedType>(types.length);
593         for (JsonSubTypes.Type type : types) {
594             result.add(new NamedType(type.value(), type.name()));
595         }
596         return result;
597     }
598
599     @Override        
600     public String findTypeName(AnnotatedClass ac)
601     {
602         JsonTypeName tn = _findAnnotation(ac, JsonTypeName.class);
603         return (tn == null) ? null : tn.value();
604     }
605
606     @Override
607     public Boolean isTypeId(AnnotatedMember member) {
608         return _hasAnnotation(member, JsonTypeId.class);
609     }
610
611     /*
612     /**********************************************************
613     /* Annotations for Object Id handling
614     /**********************************************************
615      */

616
617     @Override
618     public ObjectIdInfo findObjectIdInfo(Annotated ann) {
619         JsonIdentityInfo info = _findAnnotation(ann, JsonIdentityInfo.class);
620         if (info == null || info.generator() == ObjectIdGenerators.None.class) {
621             return null;
622         }
623         // In future may need to allow passing namespace?
624         PropertyName name = PropertyName.construct(info.property());
625         return new ObjectIdInfo(name, info.scope(), info.generator(), info.resolver());
626     }
627
628     @Override
629     public ObjectIdInfo findObjectReferenceInfo(Annotated ann, ObjectIdInfo objectIdInfo) {
630         JsonIdentityReference ref = _findAnnotation(ann, JsonIdentityReference.class);
631         if (ref == null) {
632             return objectIdInfo;
633         }
634         if (objectIdInfo == null) {
635             objectIdInfo = ObjectIdInfo.empty();
636         }
637         return objectIdInfo.withAlwaysAsId(ref.alwaysAsId());
638     }
639
640     /*
641     /**********************************************************
642     /* Serialization: general annotations
643     /**********************************************************
644     */

645
646     @Override
647     public Object findSerializer(Annotated a)
648     {
649         JsonSerialize ann = _findAnnotation(a, JsonSerialize.class);
650         if (ann != null) {
651             @SuppressWarnings("rawtypes")
652             Class<? extends JsonSerializer> serClass = ann.using();
653             if (serClass != JsonSerializer.None.class) {
654                 return serClass;
655             }
656         }
657         
658         /* 18-Oct-2010, tatu: [JACKSON-351] @JsonRawValue handled just here, for now;
659          *  if we need to get raw indicator from other sources need to add
660          *  separate accessor within {@link AnnotationIntrospector} interface.
661          */

662         JsonRawValue annRaw =  _findAnnotation(a, JsonRawValue.class);
663         if ((annRaw != null) && annRaw.value()) {
664             // let's construct instance with nominal type:
665             Class<?> cls = a.getRawType();
666             return new RawSerializer<Object>(cls);
667         }       
668         return null;
669     }
670
671     @Override
672     public Object findKeySerializer(Annotated a)
673     {
674         JsonSerialize ann = _findAnnotation(a, JsonSerialize.class);
675         if (ann != null) {
676             @SuppressWarnings("rawtypes")
677             Class<? extends JsonSerializer> serClass = ann.keyUsing();
678             if (serClass != JsonSerializer.None.class) {
679                 return serClass;
680             }
681         }
682         return null;
683     }
684
685     @Override
686     public Object findContentSerializer(Annotated a)
687     {
688         JsonSerialize ann = _findAnnotation(a, JsonSerialize.class);
689         if (ann != null) {
690             @SuppressWarnings("rawtypes")
691             Class<? extends JsonSerializer> serClass = ann.contentUsing();
692             if (serClass != JsonSerializer.None.class) {
693                 return serClass;
694             }
695         }
696         return null;
697     }
698
699     @Override
700     public Object findNullSerializer(Annotated a)
701     {
702         JsonSerialize ann = _findAnnotation(a, JsonSerialize.class);
703         if (ann != null) {
704             @SuppressWarnings("rawtypes")
705             Class<? extends JsonSerializer> serClass = ann.nullsUsing();
706             if (serClass != JsonSerializer.None.class) {
707                 return serClass;
708             }
709         }
710         return null;
711     }
712
713     @Override
714     public JsonInclude.Value findPropertyInclusion(Annotated a)
715     {
716         JsonInclude inc = _findAnnotation(a, JsonInclude.class);
717         JsonInclude.Value value = (inc == null) ? JsonInclude.Value.empty() : JsonInclude.Value.from(inc);
718
719         // only consider deprecated variant if we didn't have non-deprecated one:
720         if (value.getValueInclusion() == JsonInclude.Include.USE_DEFAULTS) {
721             value = _refinePropertyInclusion(a, value);
722         }
723         return value;
724     }
725
726     @SuppressWarnings("deprecation")
727     private JsonInclude.Value _refinePropertyInclusion(Annotated a, JsonInclude.Value value) {
728         JsonSerialize ann = _findAnnotation(a, JsonSerialize.class);
729         if (ann != null) {
730             switch (ann.include()) {
731             case ALWAYS:
732                 return value.withValueInclusion(JsonInclude.Include.ALWAYS);
733             case NON_NULL:
734                 return value.withValueInclusion(JsonInclude.Include.NON_NULL);
735             case NON_DEFAULT:
736                 return value.withValueInclusion(JsonInclude.Include.NON_DEFAULT);
737             case NON_EMPTY:
738                 return value.withValueInclusion(JsonInclude.Include.NON_EMPTY);
739             case DEFAULT_INCLUSION:
740             default:
741             }
742         }
743         return value;
744     }
745
746     @Override
747     public JsonSerialize.Typing findSerializationTyping(Annotated a)
748     {
749         JsonSerialize ann = _findAnnotation(a, JsonSerialize.class);
750         return (ann == null) ? null : ann.typing();
751     }
752
753     @Override
754     public Object findSerializationConverter(Annotated a) {
755         JsonSerialize ann = _findAnnotation(a, JsonSerialize.class);
756         return (ann == null) ? null : _classIfExplicit(ann.converter(), Converter.None.class);
757     }
758
759     @Override
760     public Object findSerializationContentConverter(AnnotatedMember a) {
761         JsonSerialize ann = _findAnnotation(a, JsonSerialize.class);
762         return (ann == null) ? null : _classIfExplicit(ann.contentConverter(), Converter.None.class);
763     }
764
765     /*
766     /**********************************************************
767     /* Serialization: type refinements
768     /**********************************************************
769      */

770     
771     @Override
772     public JavaType refineSerializationType(final MapperConfig<?> config,
773             final Annotated a, final JavaType baseType) throws JsonMappingException
774     {
775         JavaType type = baseType;
776         final TypeFactory tf = config.getTypeFactory();
777
778         final JsonSerialize jsonSer = _findAnnotation(a, JsonSerialize.class);
779         
780         // Ok: start by refining the main type itself; common to all types
781
782         final Class<?> serClass = (jsonSer == null) ? null : _classIfExplicit(jsonSer.as());
783         if (serClass != null) {
784             if (type.hasRawClass(serClass)) {
785                 // 30-Nov-2015, tatu: As per [databind#1023], need to allow forcing of
786                 //    static typing this way
787                 type = type.withStaticTyping();
788             } else {
789                 Class<?> currRaw = type.getRawClass();
790                 try {
791                     // 11-Oct-2015, tatu: For deser, we call `TypeFactory.constructSpecializedType()`,
792                     //   may be needed here too in future?
793                     if (serClass.isAssignableFrom(currRaw)) { // common case
794                         type = tf.constructGeneralizedType(type, serClass);
795                     } else if (currRaw.isAssignableFrom(serClass)) { // specialization, ok as well
796                         type = tf.constructSpecializedType(type, serClass);
797                     } else if (_primitiveAndWrapper(currRaw, serClass)) {
798                         // 27-Apr-2017, tatu: [databind#1592] ignore primitive<->wrapper refinements
799                         type = type.withStaticTyping();
800                     } else {
801                         throw new JsonMappingException(null,
802                                 String.format("Cannot refine serialization type %s into %s; types not related",
803                                         type, serClass.getName()));
804                     }
805                 } catch (IllegalArgumentException iae) {
806                     throw new JsonMappingException(null,
807                             String.format("Failed to widen type %s with annotation (value %s), from '%s': %s",
808                                     type, serClass.getName(), a.getName(), iae.getMessage()),
809                                     iae);
810                 }
811             }
812         }
813         // Then further processing for container types
814
815         // First, key type (for Maps, Map-like types):
816         if (type.isMapLikeType()) {
817             JavaType keyType = type.getKeyType();
818             final Class<?> keyClass = (jsonSer == null) ? null : _classIfExplicit(jsonSer.keyAs());
819             if (keyClass != null) {
820                 if (keyType.hasRawClass(keyClass)) {
821                     keyType = keyType.withStaticTyping();
822                 } else {
823                     Class<?> currRaw = keyType.getRawClass();
824                     try {
825                         // 19-May-2016, tatu: As per [databind#1231], [databind#1178] may need to actually
826                         //   specialize (narrow) type sometimes, even if more commonly opposite
827                         //   is needed.
828                         if (keyClass.isAssignableFrom(currRaw)) { // common case
829                             keyType = tf.constructGeneralizedType(keyType, keyClass);
830                         } else if (currRaw.isAssignableFrom(keyClass)) { // specialization, ok as well
831                             keyType = tf.constructSpecializedType(keyType, keyClass);
832                         } else if (_primitiveAndWrapper(currRaw, keyClass)) {
833                             // 27-Apr-2017, tatu: [databind#1592] ignore primitive<->wrapper refinements
834                             keyType = keyType.withStaticTyping();
835                         } else {
836                             throw new JsonMappingException(null,
837                                     String.format("Cannot refine serialization key type %s into %s; types not related",
838                                             keyType, keyClass.getName()));
839                         }
840                     } catch (IllegalArgumentException iae) {
841                         throw new JsonMappingException(null,
842                                 String.format("Failed to widen key type of %s with concrete-type annotation (value %s), from '%s': %s",
843                                         type, keyClass.getName(), a.getName(), iae.getMessage()),
844                                         iae);
845                     }
846                 }
847                 type = ((MapLikeType) type).withKeyType(keyType);
848             }
849         }
850
851         JavaType contentType = type.getContentType();
852         if (contentType != null) { // collection[like], map[like], array, reference
853             // And then value types for all containers:
854            final Class<?> contentClass = (jsonSer == null) ? null : _classIfExplicit(jsonSer.contentAs());
855            if (contentClass != null) {
856                if (contentType.hasRawClass(contentClass)) {
857                    contentType = contentType.withStaticTyping();
858                } else {
859                    // 03-Apr-2016, tatu: As per [databind#1178], may need to actually
860                    //   specialize (narrow) type sometimes, even if more commonly opposite
861                    //   is needed.
862                    Class<?> currRaw = contentType.getRawClass();
863                    try {
864                        if (contentClass.isAssignableFrom(currRaw)) { // common case
865                            contentType = tf.constructGeneralizedType(contentType, contentClass);
866                        } else if (currRaw.isAssignableFrom(contentClass)) { // specialization, ok as well
867                            contentType = tf.constructSpecializedType(contentType, contentClass);
868                        } else if (_primitiveAndWrapper(currRaw, contentClass)) {
869                            // 27-Apr-2017, tatu: [databind#1592] ignore primitive<->wrapper refinements
870                            contentType = contentType.withStaticTyping();
871                        } else {
872                            throw new JsonMappingException(null,
873                                    String.format("Cannot refine serialization content type %s into %s; types not related",
874                                            contentType, contentClass.getName()));
875                        }
876                    } catch (IllegalArgumentException iae) { // shouldn't really happen
877                        throw new JsonMappingException(null,
878                                String.format("Internal error: failed to refine value type of %s with concrete-type annotation (value %s), from '%s': %s",
879                                        type, contentClass.getName(), a.getName(), iae.getMessage()),
880                                        iae);
881                    }
882                }
883                type = type.withContentType(contentType);
884            }
885         }
886         return type;
887     }
888
889     @Override
890     @Deprecated // since 2.7
891     public Class<?> findSerializationType(Annotated am) {
892         return null;
893     }
894
895     @Override
896     @Deprecated // since 2.7
897     public Class<?> findSerializationKeyType(Annotated am, JavaType baseType) {
898         return null;
899     }
900
901     @Override
902     @Deprecated // since 2.7
903     public Class<?> findSerializationContentType(Annotated am, JavaType baseType) {
904         return null;
905     }
906
907     /*
908     /**********************************************************
909     /* Serialization: class annotations
910     /**********************************************************
911      */

912
913     @Override
914     public String[] findSerializationPropertyOrder(AnnotatedClass ac) {
915         JsonPropertyOrder order = _findAnnotation(ac, JsonPropertyOrder.class);
916         return (order == null) ? null : order.value();
917     }
918
919     @Override
920     public Boolean findSerializationSortAlphabetically(Annotated ann) {
921         return _findSortAlpha(ann);
922     }
923
924     private final Boolean _findSortAlpha(Annotated ann) {
925         JsonPropertyOrder order = _findAnnotation(ann, JsonPropertyOrder.class);
926         // 23-Jun-2015, tatu: as per [databind#840], let's only consider
927         //  `true` to have any significance.
928         if ((order != null) && order.alphabetic()) {
929             return Boolean.TRUE;
930         }
931         return null;
932     }
933
934     @Override
935     public void findAndAddVirtualProperties(MapperConfig<?> config, AnnotatedClass ac,
936             List<BeanPropertyWriter> properties) {
937         JsonAppend ann = _findAnnotation(ac, JsonAppend.class);
938         if (ann == null) {
939             return;
940         }
941         final boolean prepend = ann.prepend();
942         JavaType propType = null;
943
944         // First: any attribute-backed properties?
945         JsonAppend.Attr[] attrs = ann.attrs();
946         for (int i = 0, len = attrs.length; i < len; ++i) {
947             if (propType == null) {
948                 propType = config.constructType(Object.class);
949             }
950             BeanPropertyWriter bpw = _constructVirtualProperty(attrs[i],
951                     config, ac, propType);
952             if (prepend) {
953                 properties.add(i, bpw);
954             } else {
955                 properties.add(bpw);
956             }
957         }
958
959         // Then: general-purpose virtual properties?
960         JsonAppend.Prop[] props = ann.props();
961         for (int i = 0, len = props.length; i < len; ++i) {
962             BeanPropertyWriter bpw = _constructVirtualProperty(props[i],
963                     config, ac);
964             if (prepend) {
965                 properties.add(i, bpw);
966             } else {
967                 properties.add(bpw);
968             }
969         }
970     }
971
972     protected BeanPropertyWriter _constructVirtualProperty(JsonAppend.Attr attr,
973             MapperConfig<?> config, AnnotatedClass ac, JavaType type)
974     {
975         PropertyMetadata metadata = attr.required() ?
976                     PropertyMetadata.STD_REQUIRED : PropertyMetadata.STD_OPTIONAL;
977         // could add Index, Description in future, if those matter
978         String attrName = attr.value();
979
980         // allow explicit renaming; if none, default to attribute name
981         PropertyName propName = _propertyName(attr.propName(), attr.propNamespace());
982         if (!propName.hasSimpleName()) {
983             propName = PropertyName.construct(attrName);
984         }
985         // now, then, we need a placeholder for member (no real Field/Method):
986         AnnotatedMember member = new VirtualAnnotatedMember(ac, ac.getRawType(),
987                 attrName, type);
988         // and with that and property definition
989         SimpleBeanPropertyDefinition propDef = SimpleBeanPropertyDefinition.construct(config,
990                 member, propName, metadata, attr.include());
991         // can construct the property writer
992         return AttributePropertyWriter.construct(attrName, propDef,
993                 ac.getAnnotations(), type);
994     }
995
996     protected BeanPropertyWriter _constructVirtualProperty(JsonAppend.Prop prop,
997             MapperConfig<?> config, AnnotatedClass ac)
998     {
999         PropertyMetadata metadata = prop.required() ?
1000                     PropertyMetadata.STD_REQUIRED : PropertyMetadata.STD_OPTIONAL;
1001         PropertyName propName = _propertyName(prop.name(), prop.namespace());
1002         JavaType type = config.constructType(prop.type());
1003         // now, then, we need a placeholder for member (no real Field/Method):
1004         AnnotatedMember member = new VirtualAnnotatedMember(ac, ac.getRawType(),
1005                 propName.getSimpleName(), type);
1006         // and with that and property definition
1007         SimpleBeanPropertyDefinition propDef = SimpleBeanPropertyDefinition.construct(config,
1008                 member, propName, metadata, prop.include());
1009
1010         Class<?> implClass = prop.value();
1011
1012         HandlerInstantiator hi = config.getHandlerInstantiator();
1013         VirtualBeanPropertyWriter bpw = (hi == null) ? null
1014                 : hi.virtualPropertyWriterInstance(config, implClass);
1015         if (bpw == null) {
1016             bpw = (VirtualBeanPropertyWriter) ClassUtil.createInstance(implClass,
1017                     config.canOverrideAccessModifiers());
1018         }
1019
1020         // one more thing: give it necessary contextual information
1021         return bpw.withConfig(config, ac, propDef, type);
1022     }
1023
1024     /*
1025     /**********************************************************
1026     /* Serialization: property annotations
1027     /**********************************************************
1028      */

1029
1030     @Override
1031     public PropertyName findNameForSerialization(Annotated a)
1032     {
1033         boolean useDefault = false;
1034         JsonGetter jg = _findAnnotation(a, JsonGetter.class);
1035         if (jg != null) {
1036             String s = jg.value();
1037             // 04-May-2018, tatu: Should allow for "nameless" `@JsonGetter` too
1038             if (!s.isEmpty()) {
1039                 return PropertyName.construct(s);
1040             }
1041             useDefault = true;
1042         }
1043         JsonProperty pann = _findAnnotation(a, JsonProperty.class);
1044         if (pann != null) {
1045             return PropertyName.construct(pann.value());
1046         }
1047         if (useDefault || _hasOneOf(a, ANNOTATIONS_TO_INFER_SER)) {
1048             return PropertyName.USE_DEFAULT;
1049         }
1050         return null;
1051     }
1052
1053     @Override // since 2.9
1054     public Boolean hasAsValue(Annotated a) {
1055         JsonValue ann = _findAnnotation(a, JsonValue.class);
1056         if (ann == null) {
1057             return null;
1058         }
1059         return ann.value();
1060     }
1061
1062     @Override // since 2.9
1063     public Boolean hasAnyGetter(Annotated a) {
1064         JsonAnyGetter ann = _findAnnotation(a, JsonAnyGetter.class);
1065         if (ann == null) {
1066             return null;
1067         }
1068         return ann.enabled();
1069     }
1070
1071     @Override
1072     @Deprecated // since 2.9
1073     public boolean hasAnyGetterAnnotation(AnnotatedMethod am) {
1074         // No dedicated disabling; regular @JsonIgnore used if needs to be ignored (handled separately)
1075         return _hasAnnotation(am, JsonAnyGetter.class);
1076     }
1077
1078     @Override
1079     @Deprecated // since 2.9
1080     public boolean hasAsValueAnnotation(AnnotatedMethod am) {
1081         JsonValue ann = _findAnnotation(am, JsonValue.class);
1082         // value of 'false' means disabled...
1083         return (ann != null) && ann.value();
1084     }
1085
1086     /*
1087     /**********************************************************
1088     /* Deserialization: general annotations
1089     /**********************************************************
1090      */

1091
1092     @Override
1093     public Object findDeserializer(Annotated a)
1094     {
1095         JsonDeserialize ann = _findAnnotation(a, JsonDeserialize.class);
1096         if (ann != null) {
1097             @SuppressWarnings("rawtypes")
1098             Class<? extends JsonDeserializer> deserClass = ann.using();
1099             if (deserClass != JsonDeserializer.None.class) {
1100                 return deserClass;
1101             }
1102         }
1103         return null;
1104     }
1105
1106     @Override
1107     public Object findKeyDeserializer(Annotated a)
1108     {
1109         JsonDeserialize ann = _findAnnotation(a, JsonDeserialize.class);
1110         if (ann != null) {
1111             Class<? extends KeyDeserializer> deserClass = ann.keyUsing();
1112             if (deserClass != KeyDeserializer.None.class) {
1113                 return deserClass;
1114             }
1115         }
1116         return null;
1117     }
1118
1119     @Override
1120     public Object findContentDeserializer(Annotated a)
1121     {
1122         JsonDeserialize ann = _findAnnotation(a, JsonDeserialize.class);
1123         if (ann != null) {
1124             @SuppressWarnings("rawtypes")
1125             Class<? extends JsonDeserializer> deserClass = ann.contentUsing();
1126             if (deserClass != JsonDeserializer.None.class) {
1127                 return deserClass;
1128             }
1129         }
1130         return null;
1131     }
1132
1133     @Override
1134     public Object findDeserializationConverter(Annotated a)
1135     {
1136         JsonDeserialize ann = _findAnnotation(a, JsonDeserialize.class);
1137         return (ann == null) ? null : _classIfExplicit(ann.converter(), Converter.None.class);
1138     }
1139
1140     @Override
1141     public Object findDeserializationContentConverter(AnnotatedMember a)
1142     {
1143         JsonDeserialize ann = _findAnnotation(a, JsonDeserialize.class);
1144         return (ann == null) ? null : _classIfExplicit(ann.contentConverter(), Converter.None.class);
1145     }
1146
1147     /*
1148     /**********************************************************
1149     /* Deserialization: type modifications
1150     /**********************************************************
1151      */

1152
1153     @Override
1154     public JavaType refineDeserializationType(final MapperConfig<?> config,
1155             final Annotated a, final JavaType baseType) throws JsonMappingException
1156     {
1157         JavaType type = baseType;
1158         final TypeFactory tf = config.getTypeFactory();
1159
1160         final JsonDeserialize jsonDeser = _findAnnotation(a, JsonDeserialize.class);
1161         
1162         // Ok: start by refining the main type itself; common to all types
1163         final Class<?> valueClass = (jsonDeser == null) ? null : _classIfExplicit(jsonDeser.as());
1164         if ((valueClass != null) && !type.hasRawClass(valueClass)
1165                 && !_primitiveAndWrapper(type, valueClass)) {
1166             try {
1167                 type = tf.constructSpecializedType(type, valueClass);
1168             } catch (IllegalArgumentException iae) {
1169                 throw new JsonMappingException(null,
1170                         String.format("Failed to narrow type %s with annotation (value %s), from '%s': %s",
1171                                 type, valueClass.getName(), a.getName(), iae.getMessage()),
1172                                 iae);
1173             }
1174         }
1175         // Then further processing for container types
1176
1177         // First, key type (for Maps, Map-like types):
1178         if (type.isMapLikeType()) {
1179             JavaType keyType = type.getKeyType();
1180             final Class<?> keyClass = (jsonDeser == null) ? null : _classIfExplicit(jsonDeser.keyAs());
1181             if ((keyClass != null)
1182                     && !_primitiveAndWrapper(keyType, keyClass)) {
1183                 try {
1184                     keyType = tf.constructSpecializedType(keyType, keyClass);
1185                     type = ((MapLikeType) type).withKeyType(keyType);
1186                 } catch (IllegalArgumentException iae) {
1187                     throw new JsonMappingException(null,
1188                             String.format("Failed to narrow key type of %s with concrete-type annotation (value %s), from '%s': %s",
1189                                     type, keyClass.getName(), a.getName(), iae.getMessage()),
1190                                     iae);
1191                 }
1192             }
1193         }
1194         JavaType contentType = type.getContentType();
1195         if (contentType != null) { // collection[like], map[like], array, reference
1196             // And then value types for all containers:
1197             final Class<?> contentClass = (jsonDeser == null) ? null : _classIfExplicit(jsonDeser.contentAs());
1198             if ((contentClass != null)
1199                     && !_primitiveAndWrapper(contentType, contentClass)) {
1200                 try {
1201                     contentType = tf.constructSpecializedType(contentType, contentClass);
1202                     type = type.withContentType(contentType);
1203                 } catch (IllegalArgumentException iae) {
1204                     throw new JsonMappingException(null,
1205                             String.format("Failed to narrow value type of %s with concrete-type annotation (value %s), from '%s': %s",
1206                                     type, contentClass.getName(), a.getName(), iae.getMessage()),
1207                             iae);
1208                 }
1209             }
1210         }
1211         return type;
1212     }
1213
1214     @Override
1215     @Deprecated // since 2.7
1216     public Class<?> findDeserializationContentType(Annotated am, JavaType baseContentType) {
1217         return null;
1218     }
1219
1220     @Override
1221     @Deprecated // since 2.7
1222     public Class<?> findDeserializationType(Annotated am, JavaType baseType) {
1223         return null;
1224     }
1225
1226     @Override
1227     @Deprecated // since 2.7
1228     public Class<?> findDeserializationKeyType(Annotated am, JavaType baseKeyType) {
1229         return null;
1230     }
1231
1232     /*
1233     /**********************************************************
1234     /* Deserialization: Class annotations
1235     /**********************************************************
1236      */

1237
1238     @Override
1239     public Object findValueInstantiator(AnnotatedClass ac)
1240     {
1241         JsonValueInstantiator ann = _findAnnotation(ac, JsonValueInstantiator.class);
1242         // no 'null' marker yet, so:
1243         return (ann == null) ? null : ann.value();
1244     }
1245
1246     @Override
1247     public Class<?> findPOJOBuilder(AnnotatedClass ac)
1248     {
1249         JsonDeserialize ann = _findAnnotation(ac, JsonDeserialize.class);
1250         return (ann == null) ? null : _classIfExplicit(ann.builder());
1251     }
1252
1253     @Override
1254     public JsonPOJOBuilder.Value findPOJOBuilderConfig(AnnotatedClass ac)
1255     {
1256         JsonPOJOBuilder ann = _findAnnotation(ac, JsonPOJOBuilder.class);
1257         return (ann == null) ? null : new JsonPOJOBuilder.Value(ann);
1258     }
1259     
1260     /*
1261     /**********************************************************
1262     /* Deserialization: property annotations
1263     /**********************************************************
1264      */

1265
1266     @Override
1267     public PropertyName findNameForDeserialization(Annotated a)
1268     {
1269         // @JsonSetter has precedence over @JsonProperty, being more specific
1270
1271         boolean useDefault = false;
1272         JsonSetter js = _findAnnotation(a, JsonSetter.class);
1273         if (js != null) {
1274             String s = js.value();
1275             // 04-May-2018, tatu: Need to allow for "nameless" `@JsonSetter` too
1276             if (s.isEmpty()) {
1277                 useDefault = true;
1278             } else {
1279                 return PropertyName.construct(s);
1280             }
1281         }
1282         JsonProperty pann = _findAnnotation(a, JsonProperty.class);
1283         if (pann != null) {
1284             return PropertyName.construct(pann.value());
1285         }
1286         if (useDefault || _hasOneOf(a, ANNOTATIONS_TO_INFER_DESER)) {
1287             return PropertyName.USE_DEFAULT;
1288         }
1289         return null;
1290     }
1291
1292     @Override
1293     public Boolean hasAnySetter(Annotated a) {
1294         JsonAnySetter ann = _findAnnotation(a, JsonAnySetter.class);
1295         return (ann == null) ? null : ann.enabled();
1296     }
1297
1298     @Override
1299     public JsonSetter.Value findSetterInfo(Annotated a) {
1300         return JsonSetter.Value.from(_findAnnotation(a, JsonSetter.class));
1301     }
1302
1303     @Override // since 2.9
1304     public Boolean findMergeInfo(Annotated a) {
1305         JsonMerge ann = _findAnnotation(a, JsonMerge.class);
1306         return (ann == null) ? null : ann.value().asBoolean();
1307     }
1308
1309     @Override
1310     @Deprecated // since 2.9
1311     public boolean hasAnySetterAnnotation(AnnotatedMethod am) {
1312         return _hasAnnotation(am, JsonAnySetter.class);
1313     }
1314
1315     @Override
1316     @Deprecated // since 2.9
1317     public boolean hasCreatorAnnotation(Annotated a)
1318     {
1319         /* No dedicated disabling; regular @JsonIgnore used if needs to be
1320          * ignored (and if so, is handled prior to this method getting called)
1321          */

1322          JsonCreator ann = _findAnnotation(a, JsonCreator.class);
1323          if (ann != null) {
1324              return (ann.mode() != JsonCreator.Mode.DISABLED);
1325          }
1326          // 19-Apr-2016, tatu: As per [databind#1197], [databind#1122] (and some related),
1327          //    may or may not consider it a creator
1328          if (_cfgConstructorPropertiesImpliesCreator ) {
1329              if (a instanceof AnnotatedConstructor) {
1330                  if (_java7Helper != null) {
1331                      Boolean b = _java7Helper.hasCreatorAnnotation(a);
1332                      if (b != null) {
1333                          return b.booleanValue();
1334                      }
1335                  }
1336              }
1337          }
1338          return false;
1339     }
1340
1341     @Override
1342     @Deprecated // since 2.9
1343     public JsonCreator.Mode findCreatorBinding(Annotated a) {
1344         JsonCreator ann = _findAnnotation(a, JsonCreator.class);
1345         return (ann == null) ? null : ann.mode();
1346     }
1347
1348     @Override
1349     public JsonCreator.Mode findCreatorAnnotation(MapperConfig<?> config, Annotated a) {
1350         JsonCreator ann = _findAnnotation(a, JsonCreator.class);
1351         if (ann != null) {
1352             return ann.mode();
1353         }
1354         if (_cfgConstructorPropertiesImpliesCreator
1355                 && config.isEnabled(MapperFeature.INFER_CREATOR_FROM_CONSTRUCTOR_PROPERTIES)
1356             ) {
1357             if (a instanceof AnnotatedConstructor) {
1358                 if (_java7Helper != null) {
1359                     Boolean b = _java7Helper.hasCreatorAnnotation(a);
1360                     if ((b != null) && b.booleanValue()) {
1361                         // 13-Sep-2016, tatu: Judgment call, but I don't think JDK ever implies
1362                         //    use of delegate; assumes as-properties implicitly
1363                         return JsonCreator.Mode.PROPERTIES;
1364                     }
1365                 }
1366             }
1367         }
1368         return null;
1369     }
1370
1371     /*
1372     /**********************************************************
1373     /* Helper methods
1374     /**********************************************************
1375      */

1376
1377     protected boolean _isIgnorable(Annotated a)
1378     {
1379         JsonIgnore ann = _findAnnotation(a, JsonIgnore.class);
1380         if (ann != null) {
1381             return ann.value();
1382         }
1383         if (_java7Helper != null) {
1384             Boolean b = _java7Helper.findTransient(a);
1385             if (b != null) {
1386                 return b.booleanValue();
1387             }
1388         }
1389         return false;
1390     }
1391
1392     protected Class<?> _classIfExplicit(Class<?> cls) {
1393         if (cls == null || ClassUtil.isBogusClass(cls)) {
1394             return null;
1395         }
1396         return cls;
1397     }
1398
1399     protected Class<?> _classIfExplicit(Class<?> cls, Class<?> implicit) {
1400         cls = _classIfExplicit(cls);
1401         return (cls == null || cls == implicit) ? null : cls;
1402     }
1403
1404     protected PropertyName _propertyName(String localName, String namespace) {
1405         if (localName.isEmpty()) {
1406             return PropertyName.USE_DEFAULT;
1407         }
1408         if (namespace == null || namespace.isEmpty()) {
1409             return PropertyName.construct(localName);
1410         }
1411         return PropertyName.construct(localName, namespace);
1412     }
1413
1414     protected PropertyName _findConstructorName(Annotated a)
1415     {
1416         if (a instanceof AnnotatedParameter) {
1417             AnnotatedParameter p = (AnnotatedParameter) a;
1418             AnnotatedWithParams ctor = p.getOwner();
1419
1420             if (ctor != null) {
1421                 if (_java7Helper != null) {
1422                     PropertyName name = _java7Helper.findConstructorName(p);
1423                     if (name != null) {
1424                         return name;
1425                     }
1426                 }
1427             }
1428         }
1429         return null;
1430     }
1431
1432     /**
1433      * Helper method called to construct and initialize instance of {@link TypeResolverBuilder}
1434      * if given annotated element indicates one is needed.
1435      */

1436     @SuppressWarnings("deprecation")
1437     protected TypeResolverBuilder<?> _findTypeResolver(MapperConfig<?> config,
1438             Annotated ann, JavaType baseType)
1439     {
1440         // First: maybe we have explicit type resolver?
1441         TypeResolverBuilder<?> b;
1442         JsonTypeInfo info = _findAnnotation(ann, JsonTypeInfo.class);
1443         JsonTypeResolver resAnn = _findAnnotation(ann, JsonTypeResolver.class);
1444         
1445         if (resAnn != null) {
1446             if (info == null) {
1447                 return null;
1448             }
1449             // let's not try to force access override (would need to pass
1450             // settings through if we did, since that's not doable on some platforms)
1451             b = config.typeResolverBuilderInstance(ann, resAnn.value());
1452         } else { // if not, use standard one, if indicated by annotations
1453             if (info == null) {
1454                 return null;
1455             }
1456             // bit special; must return 'marker' to block use of default typing:
1457             if (info.use() == JsonTypeInfo.Id.NONE) {
1458                 return _constructNoTypeResolverBuilder();
1459             }
1460             b = _constructStdTypeResolverBuilder();
1461         }
1462         // Does it define a custom type id resolver?
1463         JsonTypeIdResolver idResInfo = _findAnnotation(ann, JsonTypeIdResolver.class);
1464         TypeIdResolver idRes = (idResInfo == null) ? null
1465                 : config.typeIdResolverInstance(ann, idResInfo.value());
1466         if (idRes != null) {
1467             idRes.init(baseType);
1468         }
1469         b = b.init(info.use(), idRes);
1470         // 13-Aug-2011, tatu: One complication; external id only works for properties;
1471         //    so if declared for a Class, we will need to map it to "PROPERTY"
1472         //    instead of "EXTERNAL_PROPERTY"
1473         JsonTypeInfo.As inclusion = info.include();
1474         if (inclusion == JsonTypeInfo.As.EXTERNAL_PROPERTY && (ann instanceof AnnotatedClass)) {
1475             inclusion = JsonTypeInfo.As.PROPERTY;
1476         }
1477         b = b.inclusion(inclusion);
1478         b = b.typeProperty(info.property());
1479         Class<?> defaultImpl = info.defaultImpl();
1480
1481         // 08-Dec-2014, tatu: To deprecate `JsonTypeInfo.None` we need to use other placeholder(s);
1482         //   and since `java.util.Void` has other purpose (to indicate "deser as null"), we'll instead
1483         //   use `JsonTypeInfo.class` itself. But any annotation type will actually do, as they have no
1484         //   valid use (cannot instantiate as default)
1485         if (defaultImpl != JsonTypeInfo.None.class && !defaultImpl.isAnnotation()) {
1486             b = b.defaultImpl(defaultImpl);
1487         }
1488         b = b.typeIdVisibility(info.visible());
1489         return b;
1490     }
1491
1492     /**
1493      * Helper method for constructing standard {@link TypeResolverBuilder}
1494      * implementation.
1495      */

1496     protected StdTypeResolverBuilder _constructStdTypeResolverBuilder() {
1497         return new StdTypeResolverBuilder();
1498     }
1499
1500     /**
1501      * Helper method for dealing with "no type info" marker; can't be null
1502      * (as it'd be replaced by default typing)
1503      */

1504     protected StdTypeResolverBuilder _constructNoTypeResolverBuilder() {
1505         return StdTypeResolverBuilder.noTypeInfoBuilder();
1506     }
1507
1508     private boolean _primitiveAndWrapper(Class<?> baseType, Class<?> refinement)
1509     {
1510         if (baseType.isPrimitive()) {
1511             return baseType == ClassUtil.primitiveType(refinement);
1512         }
1513         if (refinement.isPrimitive()) {
1514             return refinement == ClassUtil.primitiveType(baseType);
1515         }
1516         return false;
1517     }
1518
1519     private boolean _primitiveAndWrapper(JavaType baseType, Class<?> refinement)
1520     {
1521         if (baseType.isPrimitive()) {
1522             return baseType.hasRawClass(ClassUtil.primitiveType(refinement));
1523         }
1524         if (refinement.isPrimitive()) {
1525             return refinement == ClassUtil.primitiveType(baseType.getRawClass());
1526         }
1527         return false;
1528     }
1529 }
1530