1 package com.fasterxml.jackson.databind.ser;
2
3 import java.math.BigDecimal;
4 import java.math.BigInteger;
5 import java.net.InetAddress;
6 import java.net.InetSocketAddress;
7 import java.nio.ByteBuffer;
8 import java.util.*;
9 import java.util.concurrent.atomic.AtomicReference;
10
11 import com.fasterxml.jackson.annotation.JsonFormat;
12 import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
13 import com.fasterxml.jackson.annotation.JsonInclude;
14 import com.fasterxml.jackson.databind.*;
15 import com.fasterxml.jackson.databind.annotation.JsonSerialize;
16 import com.fasterxml.jackson.databind.cfg.SerializerFactoryConfig;
17 import com.fasterxml.jackson.databind.ext.OptionalHandlerFactory;
18 import com.fasterxml.jackson.databind.introspect.*;
19 import com.fasterxml.jackson.databind.jsontype.NamedType;
20 import com.fasterxml.jackson.databind.jsontype.TypeResolverBuilder;
21 import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
22 import com.fasterxml.jackson.databind.ser.impl.*;
23 import com.fasterxml.jackson.databind.ser.std.*;
24 import com.fasterxml.jackson.databind.type.*;
25 import com.fasterxml.jackson.databind.util.*;
26
27 /**
28  * Factory class that can provide serializers for standard JDK classes,
29  * as well as custom classes that extend standard classes or implement
30  * one of "well-known" interfaces (such as {@link java.util.Collection}).
31  *<p>
32  * Since all the serializers are eagerly instantiated, and there is
33  * no additional introspection or customizability of these types,
34  * this factory is essentially stateless.
35  */

36 @SuppressWarnings("serial")
37 public abstract class BasicSerializerFactory
38     extends SerializerFactory
39     implements java.io.Serializable
40 {
41     /*
42     /**********************************************************
43     /* Configuration, lookup tables/maps
44     /**********************************************************
45      */

46
47     /**
48      * Since these are all JDK classes, we shouldn't have to worry
49      * about ClassLoader used to load them. Rather, we can just
50      * use the class name, and keep things simple and efficient.
51      */

52     protected final static HashMap<String, JsonSerializer<?>> _concrete;
53     
54     /**
55      * Actually it may not make much sense to eagerly instantiate all
56      * kinds of serializers: so this Map actually contains class references,
57      * not instances
58      */

59     protected final static HashMap<String, Class<? extends JsonSerializer<?>>> _concreteLazy;
60
61     static {
62         HashMap<String, Class<? extends JsonSerializer<?>>> concLazy
63             = new HashMap<String, Class<? extends JsonSerializer<?>>>();
64         HashMap<String, JsonSerializer<?>> concrete
65             = new HashMap<String, JsonSerializer<?>>();
66
67         
68         /* String and string-like types (note: date types explicitly
69          * not included -- can use either textual or numeric serialization)
70          */

71         concrete.put(String.class.getName(), new StringSerializer());
72         final ToStringSerializer sls = ToStringSerializer.instance;
73         concrete.put(StringBuffer.class.getName(), sls);
74         concrete.put(StringBuilder.class.getName(), sls);
75         concrete.put(Character.class.getName(), sls);
76         concrete.put(Character.TYPE.getName(), sls);
77
78         // Primitives/wrappers for primitives (primitives needed for Beans)
79         NumberSerializers.addAll(concrete);
80         concrete.put(Boolean.TYPE.getName(), new BooleanSerializer(true));
81         concrete.put(Boolean.class.getName(), new BooleanSerializer(false));
82
83         // Other numbers, more complicated
84         concrete.put(BigInteger.class.getName(), new NumberSerializer(BigInteger.class));
85         concrete.put(BigDecimal.class.getName(),new NumberSerializer(BigDecimal.class));
86
87         // Other discrete non-container types:
88         // First, Date/Time zoo:
89         concrete.put(Calendar.class.getName(), CalendarSerializer.instance);
90         concrete.put(java.util.Date.class.getName(), DateSerializer.instance);
91
92         // And then other standard non-structured JDK types
93         for (Map.Entry<Class<?>,Object> en : StdJdkSerializers.all()) {
94             Object value = en.getValue();
95             if (value instanceof JsonSerializer<?>) {
96                 concrete.put(en.getKey().getName(), (JsonSerializer<?>) value);
97             } else {
98                 @SuppressWarnings("unchecked")
99                 Class<? extends JsonSerializer<?>> cls = (Class<? extends JsonSerializer<?>>) value;
100                 concLazy.put(en.getKey().getName(), cls);
101             }
102         }
103
104         // Jackson-specific type(s)
105         // (Q: can this ever be sub-classed?)
106         concLazy.put(TokenBuffer.class.getName(), TokenBufferSerializer.class);
107
108         _concrete = concrete;
109         _concreteLazy = concLazy;
110     }
111
112     /*
113     /**********************************************************
114     /* Configuration
115     /**********************************************************
116      */

117     
118     /**
119      * Configuration settings for this factory; immutable instance (just like this
120      * factory), new version created via copy-constructor (fluent-style)
121      */

122     protected final SerializerFactoryConfig _factoryConfig;
123
124     /*
125     /**********************************************************
126     /* Life cycle
127     /**********************************************************
128      */

129
130     /**
131      * We will provide default constructor to allow sub-classing,
132      * but make it protected so that no non-singleton instances of
133      * the class will be instantiated.
134      */

135     protected BasicSerializerFactory(SerializerFactoryConfig config) {
136         _factoryConfig = (config == null) ? new SerializerFactoryConfig() : config;
137     }
138     
139     /**
140      * Method for getting current {@link SerializerFactoryConfig}.
141       *<p>
142      * Note that since instances are immutable, you can NOT change settings
143      * by accessing an instance and calling methods: this will simply create
144      * new instance of config object.
145      */

146     public SerializerFactoryConfig getFactoryConfig() {
147         return _factoryConfig;
148     }
149
150     /**
151      * Method used for creating a new instance of this factory, but with different
152      * configuration. Reason for specifying factory method (instead of plain constructor)
153      * is to allow proper sub-classing of factories.
154      *<p>
155      * Note that custom sub-classes generally <b>must override</b> implementation
156      * of this method, as it usually requires instantiating a new instance of
157      * factory type. Check out javadocs for
158      * {@link com.fasterxml.jackson.databind.ser.BeanSerializerFactory} for more details.
159      */

160     public abstract SerializerFactory withConfig(SerializerFactoryConfig config);
161
162     /**
163      * Convenience method for creating a new factory instance with an additional
164      * serializer provider.
165      */

166     @Override
167     public final SerializerFactory withAdditionalSerializers(Serializers additional) {
168         return withConfig(_factoryConfig.withAdditionalSerializers(additional));
169     }
170
171     /**
172      * Convenience method for creating a new factory instance with an additional
173      * key serializer provider.
174      */

175     @Override
176     public final SerializerFactory withAdditionalKeySerializers(Serializers additional) {
177         return withConfig(_factoryConfig.withAdditionalKeySerializers(additional));
178     }
179     
180     /**
181      * Convenience method for creating a new factory instance with additional bean
182      * serializer modifier.
183      */

184     @Override
185     public final SerializerFactory withSerializerModifier(BeanSerializerModifier modifier) {
186         return withConfig(_factoryConfig.withSerializerModifier(modifier));
187     }
188
189     /*
190     /**********************************************************
191     /* SerializerFactory impl
192     /**********************************************************
193      */

194     
195     // Implemented by sub-classes
196     @Override
197     public abstract JsonSerializer<Object> createSerializer(SerializerProvider prov,
198             JavaType type)
199         throws JsonMappingException;
200
201     @Override // since 2.11
202     @SuppressWarnings("unchecked")
203     public JsonSerializer<Object> createKeySerializer(SerializerProvider ctxt,
204             JavaType keyType, JsonSerializer<Object> defaultImpl) throws JsonMappingException
205     {
206         // 16-Oct-2019, tatu: use to only introspect class annotations but we'll
207         //    need methods too for `@JsonValue` later; and custom lookup might want it, too
208         final SerializationConfig config = ctxt.getConfig();
209         BeanDescription beanDesc = config.introspect(keyType);
210         JsonSerializer<?> ser = null;
211         // Minor optimization: to avoid constructing beanDesc, bail out if none registered
212         if (_factoryConfig.hasKeySerializers()) {
213             // Only thing we have here are module-provided key serializers:
214             for (Serializers serializers : _factoryConfig.keySerializers()) {
215                 ser = serializers.findSerializer(config, keyType, beanDesc);
216                 if (ser != null) {
217                     break;
218                 }
219             }
220         }
221         if (ser == null) {
222             // [databind#2452]: Support `@JsonSerialize(keyUsing = ...)` -- new in 2.11
223             ser = _findKeySerializer(ctxt, beanDesc.getClassInfo());
224             if (ser == null) {
225                 ser = defaultImpl;
226                 if (ser == null) {
227                     ser = StdKeySerializers.getStdKeySerializer(config, keyType.getRawClass(), false);
228                     // As per [databind#47], also need to support @JsonValue
229                     if (ser == null) {
230                         AnnotatedMember am = beanDesc.findJsonValueAccessor();
231                         if (am != null) {
232                             final Class<?> rawType = am.getRawType();
233                             JsonSerializer<?> delegate = StdKeySerializers.getStdKeySerializer(config,
234                                     rawType, true);
235                             if (config.canOverrideAccessModifiers()) {
236                                 ClassUtil.checkAndFixAccess(am.getMember(),
237                                         config.isEnabled(MapperFeature.OVERRIDE_PUBLIC_ACCESS_MODIFIERS));
238                             }
239                             ser = new JsonValueSerializer(am, delegate);
240                         } else {
241                             ser = StdKeySerializers.getFallbackKeySerializer(config, keyType.getRawClass());
242                         }
243                     }
244                 }
245             }
246         }
247
248         // [databind#120]: Allow post-processing
249         if (_factoryConfig.hasSerializerModifiers()) {
250             for (BeanSerializerModifier mod : _factoryConfig.serializerModifiers()) {
251                 ser = mod.modifyKeySerializer(config, keyType, beanDesc, ser);
252             }
253         }
254         return (JsonSerializer<Object>) ser;
255     }
256
257     // Old method: to be removed from 3.0 -- similar to above but can't look for "keyUsing"
258     @Override
259     @SuppressWarnings("unchecked")
260     @Deprecated // since 2.11
261     public JsonSerializer<Object> createKeySerializer(SerializationConfig config,
262             JavaType keyType, JsonSerializer<Object> defaultImpl)
263     {
264         BeanDescription beanDesc = config.introspect(keyType);
265         JsonSerializer<?> ser = null;
266         if (_factoryConfig.hasKeySerializers()) {
267             for (Serializers serializers : _factoryConfig.keySerializers()) {
268                 ser = serializers.findSerializer(config, keyType, beanDesc);
269                 if (ser != null) {
270                     break;
271                 }
272             }
273         }
274         if (ser == null) {
275             ser = defaultImpl;
276             if (ser == null) {
277                 ser = StdKeySerializers.getStdKeySerializer(config, keyType.getRawClass(), false);
278                 if (ser == null) {
279                     AnnotatedMember am = beanDesc.findJsonValueAccessor();
280                     if (am != null) {
281                         final Class<?> rawType = am.getRawType();
282                         JsonSerializer<?> delegate = StdKeySerializers.getStdKeySerializer(config,
283                                 rawType, true);
284                         if (config.canOverrideAccessModifiers()) {
285                             ClassUtil.checkAndFixAccess(am.getMember(),
286                                     config.isEnabled(MapperFeature.OVERRIDE_PUBLIC_ACCESS_MODIFIERS));
287                         }
288                         ser = new JsonValueSerializer(am, delegate);
289                     } else {
290                         ser = StdKeySerializers.getFallbackKeySerializer(config, keyType.getRawClass());
291                     }
292                 }
293             }
294         }
295         if (_factoryConfig.hasSerializerModifiers()) {
296             for (BeanSerializerModifier mod : _factoryConfig.serializerModifiers()) {
297                 ser = mod.modifyKeySerializer(config, keyType, beanDesc, ser);
298             }
299         }
300         return (JsonSerializer<Object>) ser;
301     }
302
303     /**
304      * Method called to construct a type serializer for values with given declared
305      * base type. This is called for values other than those of bean property
306      * types.
307      */

308     @Override
309     public TypeSerializer createTypeSerializer(SerializationConfig config,
310             JavaType baseType)
311     {
312         BeanDescription bean = config.introspectClassAnnotations(baseType.getRawClass());
313         AnnotatedClass ac = bean.getClassInfo();
314         AnnotationIntrospector ai = config.getAnnotationIntrospector();
315         TypeResolverBuilder<?> b = ai.findTypeResolver(config, ac, baseType);
316         /* Ok: if there is no explicit type info handler, we may want to
317          * use a default. If so, config object knows what to use.
318          */

319         Collection<NamedType> subtypes = null;
320         if (b == null) {
321             b = config.getDefaultTyper(baseType);
322         } else {
323             subtypes = config.getSubtypeResolver().collectAndResolveSubtypesByClass(config, ac);
324         }
325         if (b == null) {
326             return null;
327         }
328         // 10-Jun-2015, tatu: Since not created for Bean Property, no need for post-processing
329         //    wrt EXTERNAL_PROPERTY
330         return b.buildTypeSerializer(config, baseType, subtypes);
331     }
332
333     /*
334     /**********************************************************
335     /* Additional API for other core classes
336     /**********************************************************
337      */

338
339     protected abstract Iterable<Serializers> customSerializers();
340
341     /*
342     /**********************************************************
343     /* Overridable secondary serializer accessor methods
344     /**********************************************************
345      */

346
347     /**
348      * Method that will use fast lookup (and identity comparison) methods to
349      * see if we know serializer to use for given type.
350      */

351     protected final JsonSerializer<?> findSerializerByLookup(JavaType type,
352             SerializationConfig config, BeanDescription beanDesc,
353             boolean staticTyping)
354     {
355         Class<?> raw = type.getRawClass();
356         String clsName = raw.getName();
357         JsonSerializer<?> ser = _concrete.get(clsName);
358         if (ser == null) {
359             Class<? extends JsonSerializer<?>> serClass = _concreteLazy.get(clsName);
360             if (serClass != null) {
361                 // 07-Jan-2017, tatu: Should never fail (since we control constructors),
362                 //   but if it does will throw `IllegalArgumentException` with description,
363                 //   which we could catch, re-title.
364                 return ClassUtil.createInstance(serClass, false);
365             }
366         }
367         return ser;
368     }
369
370     /**
371      * Method called to see if one of primary per-class annotations
372      * (or related, like implementing of {@link JsonSerializable})
373      * determines the serializer to use.
374      *<p>
375      * Currently handles things like:
376      *<ul>
377      * <li>If type implements {@link JsonSerializable}, use that
378      *  </li>
379      * <li>If type has {@link com.fasterxml.jackson.annotation.JsonValue} annotation (or equivalent), build serializer
380      *    based on that property
381      *  </li>
382      *</ul>
383      *
384      * @since 2.0
385      */

386     protected final JsonSerializer<?> findSerializerByAnnotations(SerializerProvider prov, 
387             JavaType type, BeanDescription beanDesc)
388         throws JsonMappingException
389     {
390         Class<?> raw = type.getRawClass();
391         // First: JsonSerializable?
392         if (JsonSerializable.class.isAssignableFrom(raw)) {
393             return SerializableSerializer.instance;
394         }
395         // Second: @JsonValue for any type
396         AnnotatedMember valueAccessor = beanDesc.findJsonValueAccessor();
397         if (valueAccessor != null) {
398             if (prov.canOverrideAccessModifiers()) {
399                 ClassUtil.checkAndFixAccess(valueAccessor.getMember(),
400                         prov.isEnabled(MapperFeature.OVERRIDE_PUBLIC_ACCESS_MODIFIERS));
401             }
402             JsonSerializer<Object> ser = findSerializerFromAnnotation(prov, valueAccessor);
403             return new JsonValueSerializer(valueAccessor, ser);
404         }
405         // No well-known annotations...
406         return null;
407     }
408     
409     /**
410      * Method for checking if we can determine serializer to use based on set of
411      * known primary types, checking for set of known base types (exact matches
412      * having been compared against with <code>findSerializerByLookup</code>).
413      * This does not include "secondary" interfaces, but
414      * mostly concrete or abstract base classes.
415      */

416     protected final JsonSerializer<?> findSerializerByPrimaryType(SerializerProvider prov, 
417             JavaType type, BeanDescription beanDesc,
418             boolean staticTyping)
419         throws JsonMappingException
420     {
421         if (type.isEnumType()) {
422             return buildEnumSerializer(prov.getConfig(), type, beanDesc);
423         }
424
425         final Class<?> raw = type.getRawClass();
426         // Then check for optional/external serializers 
427         JsonSerializer<?> ser = findOptionalStdSerializer(prov, type, beanDesc, staticTyping);
428         if (ser != null) {
429             return ser;
430         }
431         
432         if (Calendar.class.isAssignableFrom(raw)) {
433             return CalendarSerializer.instance;
434         }
435         if (java.util.Date.class.isAssignableFrom(raw)) {
436             return DateSerializer.instance;
437         }
438         if (Map.Entry.class.isAssignableFrom(raw)) {
439             // 18-Oct-2015, tatu: With 2.7, need to dig type info:
440             JavaType mapEntryType = type.findSuperType(Map.Entry.class);
441
442             // 28-Apr-2015, tatu: TypeFactory does it all for us already so
443             JavaType kt = mapEntryType.containedTypeOrUnknown(0);
444             JavaType vt = mapEntryType.containedTypeOrUnknown(1);
445             return buildMapEntrySerializer(prov, type, beanDesc, staticTyping, kt, vt);
446         }
447         if (ByteBuffer.class.isAssignableFrom(raw)) {
448             return new ByteBufferSerializer();
449         }
450         if (InetAddress.class.isAssignableFrom(raw)) {
451             return new InetAddressSerializer();
452         }
453         if (InetSocketAddress.class.isAssignableFrom(raw)) {
454             return new InetSocketAddressSerializer();
455         }
456         if (TimeZone.class.isAssignableFrom(raw)) {
457             return new TimeZoneSerializer();
458         }
459         if (java.nio.charset.Charset.class.isAssignableFrom(raw)) {
460             return ToStringSerializer.instance;
461         }
462         if (Number.class.isAssignableFrom(raw)) {
463             // 21-May-2014, tatu: Couple of alternatives actually
464             JsonFormat.Value format = beanDesc.findExpectedFormat(null);
465             if (format != null) {
466                 switch (format.getShape()) {
467                 case STRING:
468                     return ToStringSerializer.instance;
469                 case OBJECT: // need to bail out to let it be serialized as POJO
470                 case ARRAY: // or, I guess ARRAY; otherwise no point in speculating
471                     return null;
472                 default:
473                 }
474             }
475             return NumberSerializer.instance;
476         }
477         return null;
478     }
479
480     /**
481      * Overridable method called after checking all other types.
482      * 
483      * @since 2.2
484      */

485     protected JsonSerializer<?> findOptionalStdSerializer(SerializerProvider prov, 
486             JavaType type, BeanDescription beanDesc, boolean staticTyping)
487         throws JsonMappingException
488     {
489         return OptionalHandlerFactory.instance.findSerializer(prov.getConfig(), type, beanDesc);
490     }
491         
492     /**
493      * Reflection-based serialized find method, which checks if
494      * given class implements one of recognized "add-on" interfaces.
495      * Add-on here means a role that is usually or can be a secondary
496      * trait: for example,
497      * bean classes may implement {@link Iterable}, but their main
498      * function is usually something else. The reason for
499      */

500     protected final JsonSerializer<?> findSerializerByAddonType(SerializationConfig config,
501             JavaType javaType, BeanDescription beanDesc, boolean staticTyping) throws JsonMappingException
502     {
503         Class<?> rawType = javaType.getRawClass();
504
505         if (Iterator.class.isAssignableFrom(rawType)) {
506             JavaType[] params = config.getTypeFactory().findTypeParameters(javaType, Iterator.class);
507             JavaType vt = (params == null || params.length != 1) ?
508                     TypeFactory.unknownType() : params[0];
509             return buildIteratorSerializer(config, javaType, beanDesc, staticTyping, vt);
510         }
511         if (Iterable.class.isAssignableFrom(rawType)) {
512             JavaType[] params = config.getTypeFactory().findTypeParameters(javaType, Iterable.class);
513             JavaType vt = (params == null || params.length != 1) ?
514                     TypeFactory.unknownType() : params[0];
515             return buildIterableSerializer(config, javaType, beanDesc,  staticTyping, vt);
516         }
517         if (CharSequence.class.isAssignableFrom(rawType)) {
518             return ToStringSerializer.instance;
519         }
520         return null;
521     }
522     
523     /**
524      * Helper method called to check if a class or method
525      * has an annotation
526      * (@link com.fasterxml.jackson.databind.annotation.JsonSerialize#using)
527      * that tells the class to use for serialization.
528      * Returns null if no such annotation found.
529      */

530     @SuppressWarnings("unchecked")
531     protected JsonSerializer<Object> findSerializerFromAnnotation(SerializerProvider prov,
532             Annotated a)
533         throws JsonMappingException
534     {
535         Object serDef = prov.getAnnotationIntrospector().findSerializer(a);
536         if (serDef == null) {
537             return null;
538         }
539         JsonSerializer<Object> ser = prov.serializerInstance(a, serDef);
540         // One more thing however: may need to also apply a converter:
541         return (JsonSerializer<Object>) findConvertingSerializer(prov, a, ser);
542     }
543
544     /**
545      * Helper method that will check whether given annotated entity (usually class,
546      * but may also be a property accessor) indicates that a {@link Converter} is to
547      * be used; and if so, to construct and return suitable serializer for it.
548      * If not, will simply return given serializer as is.
549      */

550     protected JsonSerializer<?> findConvertingSerializer(SerializerProvider prov,
551             Annotated a, JsonSerializer<?> ser)
552         throws JsonMappingException
553     {
554         Converter<Object,Object> conv = findConverter(prov, a);
555         if (conv == null) {
556             return ser;
557         }
558         JavaType delegateType = conv.getOutputType(prov.getTypeFactory());
559         return new StdDelegatingSerializer(conv, delegateType, ser);
560     }
561
562     protected Converter<Object,Object> findConverter(SerializerProvider prov,
563             Annotated a)
564         throws JsonMappingException
565     {
566         Object convDef = prov.getAnnotationIntrospector().findSerializationConverter(a);
567         if (convDef == null) {
568             return null;
569         }
570         return prov.converterInstance(a, convDef);
571     }
572     
573     /*
574     /**********************************************************
575     /* Factory methods, container types:
576     /**********************************************************
577      */

578
579     /**
580      * @since 2.1
581      */

582     protected JsonSerializer<?> buildContainerSerializer(SerializerProvider prov,
583             JavaType type, BeanDescription beanDesc, boolean staticTyping)
584         throws JsonMappingException
585     {
586         final SerializationConfig config = prov.getConfig();
587
588         /* [databind#23], 15-Mar-2013, tatu: must force static handling of root value type,
589          *   with just one important exception: if value type is "untyped", let's
590          *   leave it as is; no clean way to make it work.
591          */

592         if (!staticTyping && type.useStaticType()) {
593             if (!type.isContainerType() || !type.getContentType().isJavaLangObject()) {
594                 staticTyping = true;
595             }
596         }
597         
598         // Let's see what we can learn about element/content/value type, type serializer for it:
599         JavaType elementType = type.getContentType();
600         TypeSerializer elementTypeSerializer = createTypeSerializer(config,
601                 elementType);
602
603         // if elements have type serializer, cannot force static typing:
604         if (elementTypeSerializer != null) {
605             staticTyping = false;
606         }
607         JsonSerializer<Object> elementValueSerializer = _findContentSerializer(prov,
608                 beanDesc.getClassInfo());
609         if (type.isMapLikeType()) { // implements java.util.Map
610             MapLikeType mlt = (MapLikeType) type;
611             /* 29-Sep-2012, tatu: This is actually too early to (try to) find
612              *  key serializer from property annotations, and can lead to caching
613              *  issues (see [databind#75]). Instead, must be done from 'createContextual()' call.
614              *  But we do need to check class annotations.
615              */

616             JsonSerializer<Object> keySerializer = _findKeySerializer(prov, beanDesc.getClassInfo());
617             if (mlt instanceof MapType) {
618                 return buildMapSerializer(prov, (MapType) mlt, beanDesc, staticTyping,
619                         keySerializer, elementTypeSerializer, elementValueSerializer);
620             }
621             // With Map-like, just 2 options: (1) Custom, (2) Annotations
622             JsonSerializer<?> ser = null;
623             MapLikeType mlType = (MapLikeType) type;
624             for (Serializers serializers : customSerializers()) { // (1) Custom
625                 ser = serializers.findMapLikeSerializer(config,
626                         mlType, beanDesc, keySerializer, elementTypeSerializer, elementValueSerializer);
627                 if (ser != null) {
628                     break;
629                 }
630             }
631             if (ser == null) { // (2) Annotations-based ones:
632                 ser = findSerializerByAnnotations(prov, type, beanDesc);
633             }
634             if (ser != null) {
635                 if (_factoryConfig.hasSerializerModifiers()) {
636                     for (BeanSerializerModifier mod : _factoryConfig.serializerModifiers()) {
637                         ser = mod.modifyMapLikeSerializer(config, mlType, beanDesc, ser);
638                     }
639                 }
640             }
641             return ser;
642         }
643         if (type.isCollectionLikeType()) {
644             CollectionLikeType clt = (CollectionLikeType) type;
645             if (clt instanceof CollectionType) {
646                 return buildCollectionSerializer(prov,  (CollectionType) clt, beanDesc, staticTyping,
647                         elementTypeSerializer, elementValueSerializer);
648             }
649             // With Map-like, just 2 options: (1) Custom, (2) Annotations
650             JsonSerializer<?> ser = null;
651             CollectionLikeType clType = (CollectionLikeType) type;
652             for (Serializers serializers : customSerializers()) { // (1) Custom
653                 ser = serializers.findCollectionLikeSerializer(config,
654                         clType, beanDesc, elementTypeSerializer, elementValueSerializer);
655                 if (ser != null) {
656                     break;
657                 }
658             }
659             if (ser == null) { // (2) Annotations-based ones:
660                 ser = findSerializerByAnnotations(prov, type, beanDesc);
661             }
662             if (ser != null) {
663                 if (_factoryConfig.hasSerializerModifiers()) {
664                     for (BeanSerializerModifier mod : _factoryConfig.serializerModifiers()) {
665                         ser = mod.modifyCollectionLikeSerializer(config, clType, beanDesc, ser);
666                     }
667                 }
668             }
669             return ser;
670         }
671         if (type.isArrayType()) {
672             return buildArraySerializer(prov, (ArrayType) type, beanDesc, staticTyping,
673                     elementTypeSerializer, elementValueSerializer);
674         }
675         return null;
676     }
677
678     /**
679      * Helper method that handles configuration details when constructing serializers for
680      * {@link java.util.List} types that support efficient by-index access
681      * 
682      * @since 2.1
683      */

684     protected JsonSerializer<?> buildCollectionSerializer(SerializerProvider prov,
685             CollectionType type, BeanDescription beanDesc, boolean staticTyping,
686             TypeSerializer elementTypeSerializer, JsonSerializer<Object> elementValueSerializer) 
687         throws JsonMappingException
688     {
689         SerializationConfig config = prov.getConfig();
690         JsonSerializer<?> ser = null;
691         // Order of lookups:
692         // 1. Custom serializers
693         // 2. Annotations (@JsonValue, @JsonDeserialize)
694         // 3. Defaults
695         for (Serializers serializers : customSerializers()) { // (1) Custom
696             ser = serializers.findCollectionSerializer(config,
697                     type, beanDesc, elementTypeSerializer, elementValueSerializer);
698             if (ser != null) {
699                 break;
700             }
701         }
702
703         if (ser == null) {
704             ser = findSerializerByAnnotations(prov, type, beanDesc); // (2) Annotations
705             if (ser == null) {
706                 // We may also want to use serialize Collections "as beans"if (and only if)
707                 // this is specified with `@JsonFormat(shape=Object)`
708                 JsonFormat.Value format = beanDesc.findExpectedFormat(null);
709                 if ((format != null) && format.getShape() == JsonFormat.Shape.OBJECT) {
710                     return null;
711                 }
712                 Class<?> raw = type.getRawClass();
713                 if (EnumSet.class.isAssignableFrom(raw)) {
714                     // this may or may not be available (Class doesn't; type of field/method does)
715                     JavaType enumType = type.getContentType();
716                     // and even if nominally there is something, only use if it really is enum
717                     if (!enumType.isEnumImplType()) { // usually since it's `Enum.class`
718                         enumType = null;
719                     }
720                     ser = buildEnumSetSerializer(enumType);
721                 } else {
722                     Class<?> elementRaw = type.getContentType().getRawClass();
723                     if (isIndexedList(raw)) {
724                         if (elementRaw == String.class) {
725                             // [JACKSON-829] Must NOT use if we have custom serializer
726                             if (ClassUtil.isJacksonStdImpl(elementValueSerializer)) {
727                                 ser = IndexedStringListSerializer.instance;
728                             }
729                         } else {
730                             ser = buildIndexedListSerializer(type.getContentType(), staticTyping,
731                                 elementTypeSerializer, elementValueSerializer);
732                         }
733                     } else if (elementRaw == String.class) {
734                         // [JACKSON-829] Must NOT use if we have custom serializer
735                         if (ClassUtil.isJacksonStdImpl(elementValueSerializer)) {
736                             ser = StringCollectionSerializer.instance;
737                         }
738                     }
739                     if (ser == null) {
740                         ser = buildCollectionSerializer(type.getContentType(), staticTyping,
741                                 elementTypeSerializer, elementValueSerializer);
742                     }
743                 }
744             }
745         }
746         // [databind#120]: Allow post-processing
747         if (_factoryConfig.hasSerializerModifiers()) {
748             for (BeanSerializerModifier mod : _factoryConfig.serializerModifiers()) {
749                 ser = mod.modifyCollectionSerializer(config, type, beanDesc, ser);
750             }
751         }
752         return ser;
753     }
754
755     /*
756     /**********************************************************
757     /* Factory methods, for Collections
758     /**********************************************************
759      */

760
761     protected boolean isIndexedList(Class<?> cls)
762     {
763         return RandomAccess.class.isAssignableFrom(cls);
764     }
765
766     public  ContainerSerializer<?> buildIndexedListSerializer(JavaType elemType,
767             boolean staticTyping, TypeSerializer vts, JsonSerializer<Object> valueSerializer) {
768         return new IndexedListSerializer(elemType, staticTyping, vts, valueSerializer);
769     }
770
771     public ContainerSerializer<?> buildCollectionSerializer(JavaType elemType,
772             boolean staticTyping, TypeSerializer vts, JsonSerializer<Object> valueSerializer) {
773         return new CollectionSerializer(elemType, staticTyping, vts, valueSerializer);
774     }
775
776     public JsonSerializer<?> buildEnumSetSerializer(JavaType enumType) {
777         return new EnumSetSerializer(enumType);
778     }
779
780     /*
781     /**********************************************************
782     /* Factory methods, for Maps
783     /**********************************************************
784      */

785
786     /**
787      * Helper method that handles configuration details when constructing serializers for
788      * {@link java.util.Map} types.
789      */

790     protected JsonSerializer<?> buildMapSerializer(SerializerProvider prov,
791             MapType type, BeanDescription beanDesc,
792             boolean staticTyping, JsonSerializer<Object> keySerializer,
793             TypeSerializer elementTypeSerializer, JsonSerializer<Object> elementValueSerializer)
794         throws JsonMappingException
795     {
796         // [databind#467]: This is where we could allow serialization "as POJO": But! It's
797         // nasty to undo, and does not apply on per-property basis. So, hardly optimal
798         JsonFormat.Value format = beanDesc.findExpectedFormat(null);
799         if ((format != null) && format.getShape() == JsonFormat.Shape.OBJECT) {
800             return null;
801         }
802
803         JsonSerializer<?> ser = null;
804
805         // Order of lookups:
806         // 1. Custom serializers
807         // 2. Annotations (@JsonValue, @JsonDeserialize)
808         // 3. Defaults
809         
810         final SerializationConfig config = prov.getConfig();
811         for (Serializers serializers : customSerializers()) { // (1) Custom
812             ser = serializers.findMapSerializer(config, type, beanDesc,
813                     keySerializer, elementTypeSerializer, elementValueSerializer);
814             if (ser != null) { break; }
815         }
816         if (ser == null) {
817             ser = findSerializerByAnnotations(prov, type, beanDesc); // (2) Annotations
818             if (ser == null) {
819                 Object filterId = findFilterId(config, beanDesc);
820                 // 01-May-2016, tatu: Which base type to use here gets tricky, since
821                 //   most often it ought to be `Map` or `EnumMap`, but due to abstract
822                 //   mapping it will more likely be concrete type like `HashMap`.
823                 //   So, for time being, just pass `Map.class`
824                 JsonIgnoreProperties.Value ignorals = config.getDefaultPropertyIgnorals(Map.class,
825                         beanDesc.getClassInfo());
826                 Set<String> ignored = (ignorals == null) ? null
827                         : ignorals.findIgnoredForSerialization();
828                 MapSerializer mapSer = MapSerializer.construct(ignored,
829                         type, staticTyping, elementTypeSerializer,
830                         keySerializer, elementValueSerializer, filterId);
831                 ser = _checkMapContentInclusion(prov, beanDesc, mapSer);
832             }
833         }
834         // [databind#120]: Allow post-processing
835         if (_factoryConfig.hasSerializerModifiers()) {
836             for (BeanSerializerModifier mod : _factoryConfig.serializerModifiers()) {
837                 ser = mod.modifyMapSerializer(config, type, beanDesc, ser);
838             }
839         }
840         return ser;
841     }
842
843     /**
844      * Helper method that does figures out content inclusion value to use, if any,
845      * and construct re-configured {@link MapSerializer} appropriately.
846      *
847      * @since 2.9
848      */

849     @SuppressWarnings("deprecation")
850     protected MapSerializer _checkMapContentInclusion(SerializerProvider prov,
851             BeanDescription beanDesc, MapSerializer mapSer)
852         throws JsonMappingException
853     {
854         final JavaType contentType = mapSer.getContentType();
855         JsonInclude.Value inclV = _findInclusionWithContent(prov, beanDesc,
856                 contentType, Map.class);
857
858         // Need to support global legacy setting, for now:
859         JsonInclude.Include incl = (inclV == null) ? JsonInclude.Include.USE_DEFAULTS : inclV.getContentInclusion();
860         if (incl == JsonInclude.Include.USE_DEFAULTS
861                 || incl == JsonInclude.Include.ALWAYS) {
862             if (!prov.isEnabled(SerializationFeature.WRITE_NULL_MAP_VALUES)) {
863                 return mapSer.withContentInclusion(nulltrue);
864             }
865             return mapSer;
866         }
867
868         // NOTE: mostly copied from `PropertyBuilder`; would be nice to refactor
869         // but code is not identical nor are these types related
870         Object valueToSuppress;
871         boolean suppressNulls = true// almost always, but possibly not with CUSTOM
872
873         switch (incl) {
874         case NON_DEFAULT:
875             valueToSuppress = BeanUtil.getDefaultValue(contentType);
876             if (valueToSuppress != null) {
877                 if (valueToSuppress.getClass().isArray()) {
878                     valueToSuppress = ArrayBuilders.getArrayComparator(valueToSuppress);
879                 }
880             }
881             break;
882         case NON_ABSENT: // new with 2.6, to support Guava/JDK8 Optionals
883             // and for referential types, also "empty", which in their case means "absent"
884             valueToSuppress = contentType.isReferenceType()
885                     ? MapSerializer.MARKER_FOR_EMPTY : null;
886             break;
887         case NON_EMPTY:
888             valueToSuppress = MapSerializer.MARKER_FOR_EMPTY;
889             break;
890         case CUSTOM: // new with 2.9
891             valueToSuppress = prov.includeFilterInstance(null, inclV.getContentFilter());
892             if (valueToSuppress == null) { // is this legal?
893                 suppressNulls = true;
894             } else {
895                 suppressNulls = prov.includeFilterSuppressNulls(valueToSuppress);
896             }
897             break;
898         case NON_NULL:
899         default// should not matter but...
900             valueToSuppress = null;
901             break;
902         }
903         return mapSer.withContentInclusion(valueToSuppress, suppressNulls);
904     }
905
906     /**
907      * @since 2.9
908      */

909     protected JsonSerializer<?> buildMapEntrySerializer(SerializerProvider prov,
910             JavaType type, BeanDescription beanDesc, boolean staticTyping,
911             JavaType keyType, JavaType valueType)
912         throws JsonMappingException
913     {
914         // [databind#865]: Allow serialization "as POJO" -- note: to undo, declare
915         //   serialization as `Shape.NATURAL` instead; that's JSON Object too.
916         JsonFormat.Value formatOverride = prov.getDefaultPropertyFormat(Map.Entry.class);
917         JsonFormat.Value formatFromAnnotation = beanDesc.findExpectedFormat(null);
918         JsonFormat.Value format = JsonFormat.Value.merge(formatFromAnnotation, formatOverride);
919         if (format.getShape() == JsonFormat.Shape.OBJECT) {
920             return null;
921         }
922         MapEntrySerializer ser = new MapEntrySerializer(valueType, keyType, valueType,
923                 staticTyping, createTypeSerializer(prov.getConfig(), valueType), null);
924
925         final JavaType contentType = ser.getContentType();
926         JsonInclude.Value inclV = _findInclusionWithContent(prov, beanDesc,
927                 contentType, Map.Entry.class);
928
929         // Need to support global legacy setting, for now:
930         JsonInclude.Include incl = (inclV == null) ? JsonInclude.Include.USE_DEFAULTS : inclV.getContentInclusion();
931         if (incl == JsonInclude.Include.USE_DEFAULTS
932                 || incl == JsonInclude.Include.ALWAYS) {
933             return ser;
934         }
935
936         // NOTE: mostly copied from `PropertyBuilder`; would be nice to refactor
937         // but code is not identical nor are these types related
938         Object valueToSuppress;
939         boolean suppressNulls = true// almost always, but possibly not with CUSTOM
940
941         switch (incl) {
942         case NON_DEFAULT:
943             valueToSuppress = BeanUtil.getDefaultValue(contentType);
944             if (valueToSuppress != null) {
945                 if (valueToSuppress.getClass().isArray()) {
946                     valueToSuppress = ArrayBuilders.getArrayComparator(valueToSuppress);
947                 }
948             }
949             break;
950         case NON_ABSENT:
951             valueToSuppress = contentType.isReferenceType()
952                     ? MapSerializer.MARKER_FOR_EMPTY : null;
953             break;
954         case NON_EMPTY:
955             valueToSuppress = MapSerializer.MARKER_FOR_EMPTY;
956             break;
957         case CUSTOM:
958             valueToSuppress = prov.includeFilterInstance(null, inclV.getContentFilter());
959             if (valueToSuppress == null) { // is this legal?
960                 suppressNulls = true;
961             } else {
962                 suppressNulls = prov.includeFilterSuppressNulls(valueToSuppress);
963             }
964             break;
965         case NON_NULL:
966         default// should not matter but...
967             valueToSuppress = null;
968             break;
969         }
970         return ser.withContentInclusion(valueToSuppress, suppressNulls);
971     }
972
973     /**
974      * Helper method used for finding inclusion definitions for structured
975      * container types like <code>Map</code>s and referential types
976      * (like <code>AtomicReference</code>).
977      *
978      * @param contentType Declared full content type of container
979      * @param configType Raw base type under which `configOverride`, if any, needs to be defined
980      */

981     protected JsonInclude.Value _findInclusionWithContent(SerializerProvider prov,
982             BeanDescription beanDesc,
983             JavaType contentType, Class<?> configType)
984         throws JsonMappingException
985     {
986         final SerializationConfig config = prov.getConfig();
987
988         // Defaulting gets complicated because we might have two distinct
989         //   axis to consider: Container type itself , and then value (content) type.
990         //  Start with Container-defaults, then use more-specific value override, if any.
991
992         // Start by getting global setting, overridden by Map-type-override
993         JsonInclude.Value inclV = beanDesc.findPropertyInclusion(config.getDefaultPropertyInclusion());
994         inclV = config.getDefaultPropertyInclusion(configType, inclV);
995
996         // and then merge content-type overrides, if any. But note that there's
997         // content-to-value inclusion shift we have to do
998         JsonInclude.Value valueIncl = config.getDefaultPropertyInclusion(contentType.getRawClass(), null);
999
1000         if (valueIncl != null) {
1001             switch (valueIncl.getValueInclusion()) {
1002             case USE_DEFAULTS:
1003                 break;
1004             case CUSTOM:
1005                 inclV = inclV.withContentFilter(valueIncl.getContentFilter());
1006                 break;
1007             default:
1008                 inclV = inclV.withContentInclusion(valueIncl.getValueInclusion());
1009             }
1010         }
1011         return inclV;
1012     }
1013     
1014     /*
1015     /**********************************************************
1016     /* Factory methods, for Arrays
1017     /**********************************************************
1018      */

1019     
1020     /**
1021      * Helper method that handles configuration details when constructing serializers for
1022      * <code>Object[]</code> (and subtypes, except for String).
1023      */

1024     protected JsonSerializer<?> buildArraySerializer(SerializerProvider prov,
1025             ArrayType type, BeanDescription beanDesc,
1026             boolean staticTyping,
1027             TypeSerializer elementTypeSerializer, JsonSerializer<Object> elementValueSerializer)
1028         throws JsonMappingException
1029     {
1030         // 25-Jun-2015, tatu: Note that unlike with Collection(Like) and Map(Like) types, array
1031         //   types cannot be annotated (in theory I guess we could have mix-ins but... ?)
1032         //   so we need not do primary annotation lookup here.
1033         //   So all we need is (1) Custom, (2) Default array serializers
1034         SerializationConfig config = prov.getConfig();
1035         JsonSerializer<?> ser = null;
1036
1037         for (Serializers serializers : customSerializers()) { // (1) Custom
1038              ser = serializers.findArraySerializer(config,
1039                      type, beanDesc, elementTypeSerializer, elementValueSerializer);
1040              if (ser != null) {
1041                  break;
1042              }
1043         }
1044         
1045         if (ser == null) {
1046              Class<?> raw = type.getRawClass();
1047              // Important: do NOT use standard serializers if non-standard element value serializer specified
1048              if (elementValueSerializer == null || ClassUtil.isJacksonStdImpl(elementValueSerializer)) {
1049                  if (String[].class == raw) {
1050                      ser = StringArraySerializer.instance;
1051                  } else {
1052                      // other standard types?
1053                      ser = StdArraySerializers.findStandardImpl(raw);
1054                  }
1055              }
1056              if (ser == null) {
1057                  ser = new ObjectArraySerializer(type.getContentType(), staticTyping, elementTypeSerializer,
1058                          elementValueSerializer);
1059              }
1060          }
1061          // [databind#120]: Allow post-processing
1062          if (_factoryConfig.hasSerializerModifiers()) {
1063              for (BeanSerializerModifier mod : _factoryConfig.serializerModifiers()) {
1064                  ser = mod.modifyArraySerializer(config, type, beanDesc, ser);
1065              }
1066          }
1067          return ser;
1068     }
1069
1070     /*
1071     /**********************************************************
1072     /* Factory methods for Reference types
1073     /* (demoted from BeanSF down here in 2.9)
1074     /**********************************************************
1075      */

1076
1077     /**
1078      * @since 2.7
1079      */

1080     public JsonSerializer<?> findReferenceSerializer(SerializerProvider prov, ReferenceType refType,
1081             BeanDescription beanDesc, boolean staticTyping)
1082         throws JsonMappingException
1083     {
1084         JavaType contentType = refType.getContentType(); 
1085         TypeSerializer contentTypeSerializer = contentType.getTypeHandler();
1086         final SerializationConfig config = prov.getConfig();
1087         if (contentTypeSerializer == null) {
1088             contentTypeSerializer = createTypeSerializer(config, contentType);
1089         }
1090         JsonSerializer<Object> contentSerializer = contentType.getValueHandler();
1091         for (Serializers serializers : customSerializers()) {
1092             JsonSerializer<?> ser = serializers.findReferenceSerializer(config, refType, beanDesc,
1093                     contentTypeSerializer, contentSerializer);
1094             if (ser != null) {
1095                 return ser;
1096             }
1097         }
1098         if (refType.isTypeOrSubTypeOf(AtomicReference.class)) {
1099             return buildAtomicReferenceSerializer(prov, refType, beanDesc, staticTyping,
1100                     contentTypeSerializer, contentSerializer);
1101         }
1102         return null;
1103     }
1104
1105     protected JsonSerializer<?> buildAtomicReferenceSerializer(SerializerProvider prov,
1106             ReferenceType refType, BeanDescription beanDesc, boolean staticTyping,
1107             TypeSerializer contentTypeSerializer, JsonSerializer<Object> contentSerializer)
1108         throws JsonMappingException
1109     {
1110         final JavaType contentType = refType.getReferencedType();
1111         JsonInclude.Value inclV = _findInclusionWithContent(prov, beanDesc,
1112                 contentType, AtomicReference.class);
1113         
1114         // Need to support global legacy setting, for now:
1115         JsonInclude.Include incl = (inclV == null) ? JsonInclude.Include.USE_DEFAULTS : inclV.getContentInclusion();
1116         Object valueToSuppress;
1117         boolean suppressNulls;
1118
1119         if (incl == JsonInclude.Include.USE_DEFAULTS
1120                 || incl == JsonInclude.Include.ALWAYS) {
1121             valueToSuppress = null;
1122             suppressNulls = false;
1123         } else {
1124             suppressNulls = true;
1125             switch (incl) {
1126             case NON_DEFAULT:
1127                 valueToSuppress = BeanUtil.getDefaultValue(contentType);
1128                 if (valueToSuppress != null) {
1129                     if (valueToSuppress.getClass().isArray()) {
1130                         valueToSuppress = ArrayBuilders.getArrayComparator(valueToSuppress);
1131                     }
1132                 }
1133                 break;
1134             case NON_ABSENT:
1135                 valueToSuppress = contentType.isReferenceType()
1136                         ? MapSerializer.MARKER_FOR_EMPTY : null;
1137                 break;
1138             case NON_EMPTY:
1139                 valueToSuppress = MapSerializer.MARKER_FOR_EMPTY;
1140                 break;
1141             case CUSTOM:
1142                 valueToSuppress = prov.includeFilterInstance(null, inclV.getContentFilter());
1143                 if (valueToSuppress == null) { // is this legal?
1144                     suppressNulls = true;
1145                 } else {
1146                     suppressNulls = prov.includeFilterSuppressNulls(valueToSuppress);
1147                 }
1148                 break;
1149             case NON_NULL:
1150             default// should not matter but...
1151                 valueToSuppress = null;
1152                 break;
1153             }
1154         }
1155         AtomicReferenceSerializer ser = new AtomicReferenceSerializer(refType, staticTyping,
1156                 contentTypeSerializer, contentSerializer);
1157         return ser.withContentInclusion(valueToSuppress, suppressNulls);
1158     }
1159
1160     /*
1161     /**********************************************************
1162     /* Factory methods, for non-container types
1163     /**********************************************************
1164      */

1165
1166     /**
1167      * @since 2.5
1168      */

1169     protected JsonSerializer<?> buildIteratorSerializer(SerializationConfig config,
1170             JavaType type, BeanDescription beanDesc, boolean staticTyping,
1171             JavaType valueType)
1172         throws JsonMappingException
1173     {
1174         return new IteratorSerializer(valueType, staticTyping, createTypeSerializer(config, valueType));
1175     }
1176
1177     /**
1178      * @since 2.5
1179      */

1180     protected JsonSerializer<?> buildIterableSerializer(SerializationConfig config,
1181             JavaType type, BeanDescription beanDesc, boolean staticTyping,
1182             JavaType valueType)
1183         throws JsonMappingException
1184     {
1185         return new IterableSerializer(valueType, staticTyping, createTypeSerializer(config, valueType));
1186     }
1187
1188     protected JsonSerializer<?> buildEnumSerializer(SerializationConfig config,
1189             JavaType type, BeanDescription beanDesc)
1190         throws JsonMappingException
1191     {
1192         /* As per [databind#24], may want to use alternate shape, serialize as JSON Object.
1193          * Challenge here is that EnumSerializer does not know how to produce
1194          * POJO style serialization, so we must handle that special case separately;
1195          * otherwise pass it to EnumSerializer.
1196          */

1197         JsonFormat.Value format = beanDesc.findExpectedFormat(null);
1198         if (format != null && format.getShape() == JsonFormat.Shape.OBJECT) {
1199             // one special case: suppress serialization of "getDeclaringClass()"...
1200             ((BasicBeanDescription) beanDesc).removeProperty("declaringClass");
1201             // returning null will mean that eventually BeanSerializer gets constructed
1202             return null;
1203         }
1204         @SuppressWarnings("unchecked")
1205         Class<Enum<?>> enumClass = (Class<Enum<?>>) type.getRawClass();
1206         JsonSerializer<?> ser = EnumSerializer.construct(enumClass, config, beanDesc, format);
1207         // [databind#120]: Allow post-processing
1208         if (_factoryConfig.hasSerializerModifiers()) {
1209             for (BeanSerializerModifier mod : _factoryConfig.serializerModifiers()) {
1210                 ser = mod.modifyEnumSerializer(config, type, beanDesc, ser);
1211             }
1212         }
1213         return ser;
1214     }
1215
1216     /*
1217     /**********************************************************
1218     /* Other helper methods
1219     /**********************************************************
1220      */

1221
1222     /**
1223      * Helper method called to try to find whether there is an annotation in the
1224      * class that indicates key serializer to use.
1225      * If so, will try to instantiate key serializer and return it; otherwise returns null.
1226      */

1227     protected JsonSerializer<Object> _findKeySerializer(SerializerProvider prov,
1228             Annotated a)
1229         throws JsonMappingException
1230     {
1231         AnnotationIntrospector intr = prov.getAnnotationIntrospector();
1232         Object serDef = intr.findKeySerializer(a);
1233         if (serDef != null) {
1234             return prov.serializerInstance(a, serDef);
1235         }
1236         return null;
1237     }
1238
1239     /**
1240      * Helper method called to try to find whether there is an annotation in the
1241      * class that indicates content ("value") serializer to use.
1242      * If so, will try to instantiate value serializer and return it; otherwise returns null.
1243      */

1244     protected JsonSerializer<Object> _findContentSerializer(SerializerProvider prov,
1245             Annotated a)
1246         throws JsonMappingException
1247     {
1248         AnnotationIntrospector intr = prov.getAnnotationIntrospector();
1249         Object serDef = intr.findContentSerializer(a);
1250         if (serDef != null) {
1251             return prov.serializerInstance(a, serDef);
1252         }
1253         return null;
1254     }
1255
1256     /**
1257      * Method called to find filter that is configured to be used with bean
1258      * serializer being built, if any.
1259      */

1260     protected Object findFilterId(SerializationConfig config, BeanDescription beanDesc) {
1261         return config.getAnnotationIntrospector().findFilterId((Annotated)beanDesc.getClassInfo());
1262     }
1263
1264     /**
1265      * Helper method to check whether global settings and/or class
1266      * annotations for the bean class indicate that static typing
1267      * (declared types)  should be used for properties.
1268      * (instead of dynamic runtime types).
1269      * 
1270      * @since 2.1 (earlier had variant with additional 'property' parameter)
1271      */

1272     protected boolean usesStaticTyping(SerializationConfig config,
1273             BeanDescription beanDesc, TypeSerializer typeSer)
1274     {
1275         /* 16-Aug-2010, tatu: If there is a (value) type serializer, we cannot force
1276          *    static typing; that would make it impossible to handle expected subtypes
1277          */

1278         if (typeSer != null) {
1279             return false;
1280         }
1281         AnnotationIntrospector intr = config.getAnnotationIntrospector();
1282         JsonSerialize.Typing t = intr.findSerializationTyping(beanDesc.getClassInfo());
1283         if (t != null && t != JsonSerialize.Typing.DEFAULT_TYPING) {
1284             return (t == JsonSerialize.Typing.STATIC);
1285         }
1286         return config.isEnabled(MapperFeature.USE_STATIC_TYPING);
1287     }
1288
1289     // Commented out in 2.9
1290     /*
1291     protected Class<?> _verifyAsClass(Object src, String methodName, Class<?> noneClass)
1292     {
1293         if (src == null) {
1294             return null;
1295         }
1296         if (!(src instanceof Class)) {
1297             throw new IllegalStateException("AnnotationIntrospector."+methodName+"() returned value of type "+src.getClass().getName()+": expected type JsonSerializer or Class<JsonSerializer> instead");
1298         }
1299         Class<?> cls = (Class<?>) src;
1300         if (cls == noneClass || ClassUtil.isBogusClass(cls)) {
1301             return null;
1302         }
1303         return cls;
1304     }
1305     */

1306 }
1307