• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package com.fasterxml.jackson.databind.ser.std;
2 
3 import java.io.IOException;
4 import java.lang.reflect.Type;
5 import java.util.*;
6 
7 import com.fasterxml.jackson.annotation.JsonFormat;
8 import com.fasterxml.jackson.annotation.JsonInclude;
9 
10 import com.fasterxml.jackson.core.*;
11 import com.fasterxml.jackson.core.type.WritableTypeId;
12 
13 import com.fasterxml.jackson.databind.*;
14 import com.fasterxml.jackson.databind.annotation.JacksonStdImpl;
15 import com.fasterxml.jackson.databind.introspect.AnnotatedMember;
16 import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatVisitorWrapper;
17 import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonMapFormatVisitor;
18 import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
19 import com.fasterxml.jackson.databind.ser.ContainerSerializer;
20 import com.fasterxml.jackson.databind.ser.ContextualSerializer;
21 import com.fasterxml.jackson.databind.ser.PropertyFilter;
22 import com.fasterxml.jackson.databind.ser.impl.PropertySerializerMap;
23 import com.fasterxml.jackson.databind.type.TypeFactory;
24 import com.fasterxml.jackson.databind.util.ArrayBuilders;
25 import com.fasterxml.jackson.databind.util.BeanUtil;
26 import com.fasterxml.jackson.databind.util.ClassUtil;
27 import com.fasterxml.jackson.databind.util.IgnorePropertiesUtil;
28 
29 /**
30  * Standard serializer implementation for serializing {link java.util.Map} types.
31  *<p>
32  * Note: about the only configurable setting currently is ability to filter out
33  * entries with specified names.
34  */
35 @JacksonStdImpl
36 public class MapSerializer
37     extends ContainerSerializer<Map<?,?>>
38     implements ContextualSerializer
39 {
40     private static final long serialVersionUID = 1L;
41 
42     protected final static JavaType UNSPECIFIED_TYPE = TypeFactory.unknownType();
43 
44     /**
45      * @since 2.9
46      */
47     public final static Object MARKER_FOR_EMPTY = JsonInclude.Include.NON_EMPTY;
48 
49     /*
50     /**********************************************************
51     /* Basic information about referring property, type
52     /**********************************************************
53      */
54 
55     /**
56      * Map-valued property being serialized with this instance
57      */
58     protected final BeanProperty _property;
59 
60     /**
61      * Whether static types should be used for serialization of values
62      * or not (if not, dynamic runtime type is used)
63      */
64     protected final boolean _valueTypeIsStatic;
65 
66     /**
67      * Declared type of keys
68      */
69     protected final JavaType _keyType;
70 
71     /**
72      * Declared type of contained values
73      */
74     protected final JavaType _valueType;
75 
76     /*
77     /**********************************************************
78     /* Serializers used
79     /**********************************************************
80      */
81 
82     /**
83      * Key serializer to use, if it can be statically determined
84      */
85     protected JsonSerializer<Object> _keySerializer;
86 
87     /**
88      * Value serializer to use, if it can be statically determined
89      */
90     protected JsonSerializer<Object> _valueSerializer;
91 
92     /**
93      * Type identifier serializer used for values, if any.
94      */
95     protected final TypeSerializer _valueTypeSerializer;
96 
97     /**
98      * If value type cannot be statically determined, mapping from
99      * runtime value types to serializers are stored in this object.
100      */
101     protected PropertySerializerMap _dynamicValueSerializers;
102 
103     /*
104     /**********************************************************
105     /* Config settings, filtering
106     /**********************************************************
107      */
108 
109     /**
110      * Set of entries to omit during serialization, if any
111      */
112     protected final Set<String> _ignoredEntries;
113 
114     /**
115      * Set of entries to include during serialization, if null, it is ignored, empty will include nothing.
116      *
117      * @since 2.12
118      */
119     protected final Set<String> _includedEntries;
120 
121     /**
122      * Id of the property filter to use, if any; null if none.
123      *
124      * @since 2.3
125      */
126     protected final Object _filterId;
127 
128     /**
129      * Value that indicates suppression mechanism to use for <b>values contained</b>;
130      * either "filter" (of which <code>equals()</code> is called), or marker
131      * value of {@link #MARKER_FOR_EMPTY}, or null to indicate no filtering for
132      * non-null values.
133      * Note that inclusion value for Map instance itself is handled by caller (POJO
134      * property that refers to the Map value).
135      *
136      * @since 2.5
137      */
138     protected final Object _suppressableValue;
139 
140     /**
141      * Flag that indicates what to do with `null` values, distinct from
142      * handling of {@link #_suppressableValue}
143      *
144      * @since 2.9
145      */
146     protected final boolean _suppressNulls;
147 
148     /**
149      * Helper object used for name-based filtering
150      *
151      * @since 2.12
152      */
153     protected final IgnorePropertiesUtil.Checker _inclusionChecker;
154 
155     /*
156     /**********************************************************
157     /* Config settings, other
158     /**********************************************************
159      */
160 
161     /**
162      * Flag set if output is forced to be sorted by keys (usually due
163      * to annotation).
164      *
165      * @since 2.4
166      */
167     protected final boolean _sortKeys;
168 
169     /*
170     /**********************************************************
171     /* Life-cycle
172     /**********************************************************
173      */
174 
175     /**
176      * @since 2.12
177      */
178     @SuppressWarnings("unchecked")
MapSerializer(Set<String> ignoredEntries, Set<String> includedEntries, JavaType keyType, JavaType valueType, boolean valueTypeIsStatic, TypeSerializer vts, JsonSerializer<?> keySerializer, JsonSerializer<?> valueSerializer)179     protected MapSerializer(Set<String> ignoredEntries, Set<String> includedEntries,
180             JavaType keyType, JavaType valueType, boolean valueTypeIsStatic,
181             TypeSerializer vts,
182             JsonSerializer<?> keySerializer, JsonSerializer<?> valueSerializer)
183     {
184         super(Map.class, false);
185         _ignoredEntries = ((ignoredEntries == null) || ignoredEntries.isEmpty())
186                 ? null : ignoredEntries;
187         _includedEntries = includedEntries;
188         _keyType = keyType;
189         _valueType = valueType;
190         _valueTypeIsStatic = valueTypeIsStatic;
191         _valueTypeSerializer = vts;
192         _keySerializer = (JsonSerializer<Object>) keySerializer;
193         _valueSerializer = (JsonSerializer<Object>) valueSerializer;
194         _dynamicValueSerializers = PropertySerializerMap.emptyForProperties();
195         _property = null;
196         _filterId = null;
197         _sortKeys = false;
198         _suppressableValue = null;
199         _suppressNulls = false;
200 
201         _inclusionChecker = IgnorePropertiesUtil.buildCheckerIfNeeded(_ignoredEntries, _includedEntries);
202     }
203 
204     /**
205      * @since 2.5
206      * @deprecated in 2.12, remove from 3.0
207      */
208     @Deprecated
MapSerializer(Set<String> ignoredEntries, JavaType keyType, JavaType valueType, boolean valueTypeIsStatic, TypeSerializer vts, JsonSerializer<?> keySerializer, JsonSerializer<?> valueSerializer)209     protected MapSerializer(Set<String> ignoredEntries,
210             JavaType keyType, JavaType valueType, boolean valueTypeIsStatic,
211             TypeSerializer vts,
212             JsonSerializer<?> keySerializer, JsonSerializer<?> valueSerializer)
213     {
214         this(ignoredEntries, null,
215                 keyType, valueType, valueTypeIsStatic,
216                 vts,
217                 keySerializer, valueSerializer);
218     }
219 
220     /**
221      * @since 2.12
222      */
223     @SuppressWarnings("unchecked")
MapSerializer(MapSerializer src, BeanProperty property, JsonSerializer<?> keySerializer, JsonSerializer<?> valueSerializer, Set<String> ignoredEntries, Set<String> includedEntries)224     protected MapSerializer(MapSerializer src, BeanProperty property,
225             JsonSerializer<?> keySerializer, JsonSerializer<?> valueSerializer,
226             Set<String> ignoredEntries, Set<String> includedEntries)
227     {
228         super(Map.class, false);
229         _ignoredEntries = ((ignoredEntries == null) || ignoredEntries.isEmpty())
230                 ? null : ignoredEntries;
231         _includedEntries = includedEntries;
232         _keyType = src._keyType;
233         _valueType = src._valueType;
234         _valueTypeIsStatic = src._valueTypeIsStatic;
235         _valueTypeSerializer = src._valueTypeSerializer;
236         _keySerializer = (JsonSerializer<Object>) keySerializer;
237         _valueSerializer = (JsonSerializer<Object>) valueSerializer;
238         // [databind#2181]: may not be safe to reuse, start from empty
239         _dynamicValueSerializers = PropertySerializerMap.emptyForProperties();
240         _property = property;
241         _filterId = src._filterId;
242         _sortKeys = src._sortKeys;
243         _suppressableValue = src._suppressableValue;
244         _suppressNulls = src._suppressNulls;
245 
246         _inclusionChecker = IgnorePropertiesUtil.buildCheckerIfNeeded(_ignoredEntries, _includedEntries);
247     }
248 
249     /**
250      * @deprecated in 2.12, remove from 3.0
251      */
252     @Deprecated
MapSerializer(MapSerializer src, BeanProperty property, JsonSerializer<?> keySerializer, JsonSerializer<?> valueSerializer, Set<String> ignoredEntries)253     protected MapSerializer(MapSerializer src, BeanProperty property,
254                             JsonSerializer<?> keySerializer, JsonSerializer<?> valueSerializer,
255                             Set<String> ignoredEntries)
256     {
257         this(src, property, keySerializer, valueSerializer, ignoredEntries, null);
258     }
259 
260     /**
261      * @since 2.9
262      */
MapSerializer(MapSerializer src, TypeSerializer vts, Object suppressableValue, boolean suppressNulls)263     protected MapSerializer(MapSerializer src, TypeSerializer vts,
264             Object suppressableValue, boolean suppressNulls)
265     {
266         super(Map.class, false);
267         _ignoredEntries = src._ignoredEntries;
268         _includedEntries = src._includedEntries;
269         _keyType = src._keyType;
270         _valueType = src._valueType;
271         _valueTypeIsStatic = src._valueTypeIsStatic;
272         _valueTypeSerializer = vts;
273         _keySerializer = src._keySerializer;
274         _valueSerializer = src._valueSerializer;
275         // 22-Nov-2018, tatu: probably safe (even with [databind#2181]) since it's just
276         //   inclusion, type serializer but NOT serializer
277         _dynamicValueSerializers = src._dynamicValueSerializers;
278         _property = src._property;
279         _filterId = src._filterId;
280         _sortKeys = src._sortKeys;
281         _suppressableValue = suppressableValue;
282         _suppressNulls = suppressNulls;
283 
284         _inclusionChecker = src._inclusionChecker;
285     }
286 
MapSerializer(MapSerializer src, Object filterId, boolean sortKeys)287     protected MapSerializer(MapSerializer src, Object filterId, boolean sortKeys)
288     {
289         super(Map.class, false);
290         _ignoredEntries = src._ignoredEntries;
291         _includedEntries = src._includedEntries;
292         _keyType = src._keyType;
293         _valueType = src._valueType;
294         _valueTypeIsStatic = src._valueTypeIsStatic;
295         _valueTypeSerializer = src._valueTypeSerializer;
296         _keySerializer = src._keySerializer;
297         _valueSerializer = src._valueSerializer;
298         // [databind#2181]: may not be safe to reuse, start from empty
299         _dynamicValueSerializers = PropertySerializerMap.emptyForProperties();
300         _property = src._property;
301         _filterId = filterId;
302         _sortKeys = sortKeys;
303         _suppressableValue = src._suppressableValue;
304         _suppressNulls = src._suppressNulls;
305 
306         _inclusionChecker = src._inclusionChecker;
307     }
308 
309     @Override
_withValueTypeSerializer(TypeSerializer vts)310     public MapSerializer _withValueTypeSerializer(TypeSerializer vts) {
311         if (_valueTypeSerializer == vts) {
312             return this;
313         }
314         _ensureOverride("_withValueTypeSerializer");
315         return new MapSerializer(this, vts, _suppressableValue, _suppressNulls);
316     }
317 
318     /**
319      * @since 2.12
320      */
withResolved(BeanProperty property, JsonSerializer<?> keySerializer, JsonSerializer<?> valueSerializer, Set<String> ignored, Set<String> included, boolean sortKeys)321     public MapSerializer withResolved(BeanProperty property,
322              JsonSerializer<?> keySerializer, JsonSerializer<?> valueSerializer,
323              Set<String> ignored, Set<String> included, boolean sortKeys)
324     {
325         _ensureOverride("withResolved");
326         MapSerializer ser = new MapSerializer(this, property, keySerializer, valueSerializer, ignored, included);
327         if (sortKeys != ser._sortKeys) {
328             ser = new MapSerializer(ser, _filterId, sortKeys);
329         }
330         return ser;
331     }
332 
333     /**
334      * @since 2.4
335      */
withResolved(BeanProperty property, JsonSerializer<?> keySerializer, JsonSerializer<?> valueSerializer, Set<String> ignored, boolean sortKeys)336     public MapSerializer withResolved(BeanProperty property,
337             JsonSerializer<?> keySerializer, JsonSerializer<?> valueSerializer,
338             Set<String> ignored, boolean sortKeys)
339     {
340         return withResolved(property, keySerializer, valueSerializer, ignored, null, sortKeys);
341     }
342 
343     @Override
withFilterId(Object filterId)344     public MapSerializer withFilterId(Object filterId) {
345         if (_filterId == filterId) {
346             return this;
347         }
348         _ensureOverride("withFilterId");
349         return new MapSerializer(this, filterId, _sortKeys);
350     }
351 
352     /**
353      * Mutant factory for constructing an instance with different inclusion strategy
354      * for content (Map values).
355      *
356      * @since 2.9
357      */
withContentInclusion(Object suppressableValue, boolean suppressNulls)358     public MapSerializer withContentInclusion(Object suppressableValue, boolean suppressNulls) {
359         if ((suppressableValue == _suppressableValue) && (suppressNulls == _suppressNulls)) {
360             return this;
361         }
362         _ensureOverride("withContentInclusion");
363         return new MapSerializer(this, _valueTypeSerializer, suppressableValue, suppressNulls);
364     }
365 
366     /**
367      * @since 2.12
368      */
construct(Set<String> ignoredEntries, Set<String> includedEntries, JavaType mapType, boolean staticValueType, TypeSerializer vts, JsonSerializer<Object> keySerializer, JsonSerializer<Object> valueSerializer, Object filterId)369     public static MapSerializer construct(Set<String> ignoredEntries, Set<String> includedEntries, JavaType mapType,
370             boolean staticValueType, TypeSerializer vts,
371             JsonSerializer<Object> keySerializer, JsonSerializer<Object> valueSerializer,
372             Object filterId)
373     {
374         JavaType keyType, valueType;
375 
376         if (mapType == null) {
377             keyType = valueType = UNSPECIFIED_TYPE;
378         } else {
379             keyType = mapType.getKeyType();
380             if (mapType.hasRawClass(java.util.Properties.class)) {
381                 // 25-Mar-2020, tatu: [databind#2657] Since non-standard Properties may actually
382                 //     contain non-Strings, demote value type to raw `Object`
383                 valueType = TypeFactory.unknownType();
384             } else {
385                 valueType = mapType.getContentType();
386             }
387         }
388         // If value type is final, it's same as forcing static value typing:
389         if (!staticValueType) {
390             staticValueType = (valueType != null && valueType.isFinal());
391         } else {
392             // also: Object.class cannot be handled as static, ever
393             if (valueType.getRawClass() == Object.class) {
394                 staticValueType = false;
395             }
396         }
397         MapSerializer ser = new MapSerializer(ignoredEntries, includedEntries, keyType, valueType, staticValueType, vts,
398                 keySerializer, valueSerializer);
399         if (filterId != null) {
400             ser = ser.withFilterId(filterId);
401         }
402         return ser;
403     }
404 
405     /**
406      * @since 2.8
407      */
construct(Set<String> ignoredEntries, JavaType mapType, boolean staticValueType, TypeSerializer vts, JsonSerializer<Object> keySerializer, JsonSerializer<Object> valueSerializer, Object filterId)408     public static MapSerializer construct(Set<String> ignoredEntries, JavaType mapType,
409             boolean staticValueType, TypeSerializer vts,
410             JsonSerializer<Object> keySerializer, JsonSerializer<Object> valueSerializer,
411             Object filterId)
412     {
413         return construct(ignoredEntries, null, mapType, staticValueType, vts, keySerializer, valueSerializer, filterId);
414     }
415 
416     /**
417      * @since 2.9
418      */
_ensureOverride(String method)419     protected void _ensureOverride(String method) {
420         ClassUtil.verifyMustOverride(MapSerializer.class, this, method);
421     }
422 
423     /**
424      * @since 2.5
425      */
426     @Deprecated // since 2.9
_ensureOverride()427     protected void _ensureOverride() {
428         _ensureOverride("N/A");
429     }
430 
431     /*
432     /**********************************************************
433     /* Deprecated creators
434     /**********************************************************
435      */
436 
437     /**
438      * @since 2.5
439      * @deprecated // since 2.9
440      */
441     @Deprecated // since 2.9
MapSerializer(MapSerializer src, TypeSerializer vts, Object suppressableValue)442     protected MapSerializer(MapSerializer src, TypeSerializer vts,
443             Object suppressableValue)
444     {
445         this(src, vts, suppressableValue, false);
446     }
447 
448     /**
449      * @deprecated since 2.9
450      */
451     @Deprecated // since 2.9
withContentInclusion(Object suppressableValue)452     public MapSerializer withContentInclusion(Object suppressableValue) {
453         return new MapSerializer(this, _valueTypeSerializer, suppressableValue, _suppressNulls);
454     }
455 
456     /**
457      * @since 2.3
458      *
459      * @deprecated Since 2.8 use the other overload
460      */
461     @Deprecated // since 2.8
construct(String[] ignoredList, JavaType mapType, boolean staticValueType, TypeSerializer vts, JsonSerializer<Object> keySerializer, JsonSerializer<Object> valueSerializer, Object filterId)462     public static MapSerializer construct(String[] ignoredList, JavaType mapType,
463             boolean staticValueType, TypeSerializer vts,
464             JsonSerializer<Object> keySerializer, JsonSerializer<Object> valueSerializer,
465             Object filterId)
466     {
467         Set<String> ignoredEntries = ArrayBuilders.arrayToSet(ignoredList);
468         return construct(ignoredEntries, mapType, staticValueType, vts,
469                 keySerializer, valueSerializer, filterId);
470     }
471 
472     /*
473     /**********************************************************
474     /* Post-processing (contextualization)
475     /**********************************************************
476      */
477 
478     @Override
createContextual(SerializerProvider provider, BeanProperty property)479     public JsonSerializer<?> createContextual(SerializerProvider provider,
480             BeanProperty property)
481         throws JsonMappingException
482     {
483         JsonSerializer<?> ser = null;
484         JsonSerializer<?> keySer = null;
485         final AnnotationIntrospector intr = provider.getAnnotationIntrospector();
486         final AnnotatedMember propertyAcc = (property == null) ? null : property.getMember();
487 
488         // First: if we have a property, may have property-annotation overrides
489         if (_neitherNull(propertyAcc, intr)) {
490             Object serDef = intr.findKeySerializer(propertyAcc);
491             if (serDef != null) {
492                 keySer = provider.serializerInstance(propertyAcc, serDef);
493             }
494             serDef = intr.findContentSerializer(propertyAcc);
495             if (serDef != null) {
496                 ser = provider.serializerInstance(propertyAcc, serDef);
497             }
498         }
499         if (ser == null) {
500             ser = _valueSerializer;
501         }
502         // [databind#124]: May have a content converter
503         ser = findContextualConvertingSerializer(provider, property, ser);
504         if (ser == null) {
505             // 30-Sep-2012, tatu: One more thing -- if explicit content type is annotated,
506             //   we can consider it a static case as well.
507             // 20-Aug-2013, tatu: Need to avoid trying to access serializer for java.lang.Object tho
508             if (_valueTypeIsStatic && !_valueType.isJavaLangObject()) {
509                 ser = provider.findContentValueSerializer(_valueType, property);
510             }
511         }
512         if (keySer == null) {
513             keySer = _keySerializer;
514         }
515         if (keySer == null) {
516             keySer = provider.findKeySerializer(_keyType, property);
517         } else {
518             keySer = provider.handleSecondaryContextualization(keySer, property);
519         }
520         Set<String> ignored = _ignoredEntries;
521         Set<String> included = _includedEntries;
522         boolean sortKeys = false;
523         if (_neitherNull(propertyAcc, intr)) {
524             final SerializationConfig config = provider.getConfig();
525             // ignorals
526             Set<String> newIgnored = intr.findPropertyIgnoralByName(config, propertyAcc).findIgnoredForSerialization();
527             if (_nonEmpty(newIgnored)) {
528                 ignored = (ignored == null) ? new HashSet<String>() : new HashSet<String>(ignored);
529                 for (String str : newIgnored) {
530                     ignored.add(str);
531                 }
532             }
533             // inclusions
534             Set<String> newIncluded = intr.findPropertyInclusionByName(config, propertyAcc).getIncluded();
535             if (newIncluded != null) {
536                 included = (included == null) ? new HashSet<String>() : new HashSet<String>(included);
537                 for (String str : newIncluded) {
538                     included.add(str);
539                 }
540             }
541             // sort key
542             Boolean b = intr.findSerializationSortAlphabetically(propertyAcc);
543             sortKeys = Boolean.TRUE.equals(b);
544         }
545         JsonFormat.Value format = findFormatOverrides(provider, property, Map.class);
546         if (format != null) {
547             Boolean B = format.getFeature(JsonFormat.Feature.WRITE_SORTED_MAP_ENTRIES);
548             if (B != null) {
549                 sortKeys = B.booleanValue();
550             }
551         }
552         MapSerializer mser = withResolved(property, keySer, ser, ignored, included, sortKeys);
553 
554         // [databind#307]: allow filtering
555         if (propertyAcc != null) {
556             Object filterId = intr.findFilterId(propertyAcc);
557             if (filterId != null) {
558                 mser = mser.withFilterId(filterId);
559             }
560         }
561         JsonInclude.Value inclV = findIncludeOverrides(provider, property, Map.class);
562         if (inclV != null) {
563             JsonInclude.Include incl = inclV.getContentInclusion();
564 
565             if (incl != JsonInclude.Include.USE_DEFAULTS) {
566                 Object valueToSuppress;
567                 boolean suppressNulls;
568                 switch (incl) {
569                 case NON_DEFAULT:
570                     valueToSuppress = BeanUtil.getDefaultValue(_valueType);
571                     suppressNulls = true;
572                     if (valueToSuppress != null) {
573                         if (valueToSuppress.getClass().isArray()) {
574                             valueToSuppress = ArrayBuilders.getArrayComparator(valueToSuppress);
575                         }
576                     }
577                     break;
578                 case NON_ABSENT:
579                     suppressNulls = true;
580                     valueToSuppress = _valueType.isReferenceType() ? MARKER_FOR_EMPTY : null;
581                     break;
582                 case NON_EMPTY:
583                     suppressNulls = true;
584                     valueToSuppress = MARKER_FOR_EMPTY;
585                     break;
586                 case CUSTOM:
587                     valueToSuppress = provider.includeFilterInstance(null, inclV.getContentFilter());
588                     if (valueToSuppress == null) { // is this legal?
589                         suppressNulls = true;
590                     } else {
591                         suppressNulls = provider.includeFilterSuppressNulls(valueToSuppress);
592                     }
593                     break;
594                 case NON_NULL:
595                     valueToSuppress = null;
596                     suppressNulls = true;
597                     break;
598                 case ALWAYS: // default
599                 default:
600                     valueToSuppress = null;
601                     // 30-Sep-2016, tatu: Should not need to check global flags here,
602                     //   if inclusion forced to be ALWAYS
603                     suppressNulls = false;
604                     break;
605                 }
606                 mser = mser.withContentInclusion(valueToSuppress, suppressNulls);
607             }
608         }
609         return mser;
610     }
611 
612     /*
613     /**********************************************************
614     /* Accessors
615     /**********************************************************
616      */
617 
618     @Override
getContentType()619     public JavaType getContentType() {
620         return _valueType;
621     }
622 
623     @Override
getContentSerializer()624     public JsonSerializer<?> getContentSerializer() {
625         return _valueSerializer;
626     }
627 
628     @Override
isEmpty(SerializerProvider prov, Map<?,?> value)629     public boolean isEmpty(SerializerProvider prov, Map<?,?> value)
630     {
631         if (value.isEmpty()) {
632             return true;
633         }
634 
635         // 05-Nove-2015, tatu: Simple cases are cheap, but for recursive
636         //   emptiness checking we actually need to see if values are empty as well.
637         Object supp = _suppressableValue;
638         if ((supp == null) && !_suppressNulls) {
639             return false;
640         }
641         JsonSerializer<Object> valueSer = _valueSerializer;
642         final boolean checkEmpty = (MARKER_FOR_EMPTY == supp);
643         if (valueSer != null) {
644             for (Object elemValue : value.values()) {
645                 if (elemValue == null) {
646                     if (_suppressNulls) {
647                         continue;
648                     }
649                     return false;
650                 }
651                 if (checkEmpty) {
652                     if (!valueSer.isEmpty(prov, elemValue)) {
653                         return false;
654                     }
655                 } else if ((supp == null) || !supp.equals(value)) {
656                     return false;
657                 }
658             }
659             return true;
660         }
661         // But if not statically known, try this:
662         for (Object elemValue : value.values()) {
663             if (elemValue == null) {
664                 if (_suppressNulls) {
665                     continue;
666                 }
667                 return false;
668             }
669             try {
670                 valueSer = _findSerializer(prov, elemValue);
671             } catch (JsonMappingException e) { // Ugh... cannot just throw as-is, so...
672                 // 05-Nov-2015, tatu: For now, probably best not to assume empty then
673                 return false;
674             }
675             if (checkEmpty) {
676                 if (!valueSer.isEmpty(prov, elemValue)) {
677                     return false;
678                 }
679             } else if ((supp == null) || !supp.equals(value)) {
680                 return false;
681             }
682         }
683         return true;
684     }
685 
686     @Override
hasSingleElement(Map<?,?> value)687     public boolean hasSingleElement(Map<?,?> value) {
688         return (value.size() == 1);
689     }
690 
691     /*
692     /**********************************************************
693     /* Extended API
694     /**********************************************************
695      */
696 
697     /**
698      * Accessor for currently assigned key serializer. Note that
699      * this may return null during construction of <code>MapSerializer</code>:
700      * depedencies are resolved during {@link #createContextual} method
701      * (which can be overridden by custom implementations), but for some
702      * dynamic types, it is possible that serializer is only resolved
703      * during actual serialization.
704      */
getKeySerializer()705     public JsonSerializer<?> getKeySerializer() {
706         return _keySerializer;
707     }
708 
709     /*
710     /**********************************************************
711     /* JsonSerializer implementation
712     /**********************************************************
713      */
714 
715     @Override
serialize(Map<?,?> value, JsonGenerator gen, SerializerProvider provider)716     public void serialize(Map<?,?> value, JsonGenerator gen, SerializerProvider provider)
717         throws IOException
718     {
719         gen.writeStartObject(value);
720         serializeWithoutTypeInfo(value, gen, provider);
721         gen.writeEndObject();
722     }
723 
724     @Override
serializeWithType(Map<?,?> value, JsonGenerator gen, SerializerProvider provider, TypeSerializer typeSer)725     public void serializeWithType(Map<?,?> value, JsonGenerator gen, SerializerProvider provider,
726             TypeSerializer typeSer)
727         throws IOException
728     {
729         // [databind#631]: Assign current value, to be accessible by custom serializers
730         gen.setCurrentValue(value);
731         WritableTypeId typeIdDef = typeSer.writeTypePrefix(gen,
732                 typeSer.typeId(value, JsonToken.START_OBJECT));
733         serializeWithoutTypeInfo(value, gen, provider);
734         typeSer.writeTypeSuffix(gen, typeIdDef);
735     }
736 
737     /*
738     /**********************************************************
739     /* Secondary serialization methods
740     /**********************************************************
741      */
742 
743     /**
744      * General-purpose serialization for contents without writing object type. Will suppress, filter and
745      * use custom serializers.
746      *<p>
747      * Public since it also is called by {@code AnyGetterWriter}.
748      *
749      * @since 2.11
750      */
serializeWithoutTypeInfo(Map<?, ?> value, JsonGenerator gen, SerializerProvider provider)751     public void serializeWithoutTypeInfo(Map<?, ?> value, JsonGenerator gen, SerializerProvider provider) throws IOException {
752         if (!value.isEmpty()) {
753             if (_sortKeys || provider.isEnabled(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS)) {
754                 value = _orderEntries(value, gen, provider);
755             }
756             PropertyFilter pf;
757             if ((_filterId != null) && (pf = findPropertyFilter(provider, _filterId, value)) != null) {
758                 serializeFilteredFields(value, gen, provider, pf, _suppressableValue);
759             } else if ((_suppressableValue != null) || _suppressNulls) {
760                 serializeOptionalFields(value, gen, provider, _suppressableValue);
761             } else if (_valueSerializer != null) {
762                 serializeFieldsUsing(value, gen, provider, _valueSerializer);
763             } else {
764                 serializeFields(value, gen, provider);
765             }
766         }
767     }
768 
769     /**
770      * General-purpose serialization for contents, where we do not necessarily know
771      * the value serialization, but
772      * we do know that no value suppression is needed (which simplifies processing a bit)
773      */
serializeFields(Map<?,?> value, JsonGenerator gen, SerializerProvider provider)774     public void serializeFields(Map<?,?> value, JsonGenerator gen, SerializerProvider provider)
775         throws IOException
776     {
777         // If value type needs polymorphic type handling, some more work needed:
778         if (_valueTypeSerializer != null) {
779             serializeTypedFields(value, gen, provider, null);
780             return;
781         }
782         final JsonSerializer<Object> keySerializer = _keySerializer;
783         Object keyElem = null;
784 
785         try {
786             for (Map.Entry<?,?> entry : value.entrySet()) {
787                 Object valueElem = entry.getValue();
788                 // First, serialize key
789                 keyElem = entry.getKey();
790                 if (keyElem == null) {
791                     provider.findNullKeySerializer(_keyType, _property).serialize(null, gen, provider);
792                 } else {
793                     // One twist: is entry ignorable? If so, skip
794                     if ((_inclusionChecker != null) && _inclusionChecker.shouldIgnore(keyElem)) {
795                         continue;
796                     }
797                     keySerializer.serialize(keyElem, gen, provider);
798                 }
799                 // And then value
800                 if (valueElem == null) {
801                     provider.defaultSerializeNull(gen);
802                     continue;
803                 }
804                 JsonSerializer<Object> serializer = _valueSerializer;
805                 if (serializer == null) {
806                     serializer = _findSerializer(provider, valueElem);
807                 }
808                 serializer.serialize(valueElem, gen, provider);
809             }
810         } catch (Exception e) { // Add reference information
811             wrapAndThrow(provider, e, value, String.valueOf(keyElem));
812         }
813     }
814 
815     /**
816      * Serialization method called when exclusion filtering needs to be applied.
817      */
serializeOptionalFields(Map<?,?> value, JsonGenerator gen, SerializerProvider provider, Object suppressableValue)818     public void serializeOptionalFields(Map<?,?> value, JsonGenerator gen, SerializerProvider provider,
819             Object suppressableValue)
820         throws IOException
821     {
822         // If value type needs polymorphic type handling, some more work needed:
823         if (_valueTypeSerializer != null) {
824             serializeTypedFields(value, gen, provider, suppressableValue);
825             return;
826         }
827         final boolean checkEmpty = (MARKER_FOR_EMPTY == suppressableValue);
828 
829         for (Map.Entry<?,?> entry : value.entrySet()) {
830             // First find key serializer
831             final Object keyElem = entry.getKey();
832             JsonSerializer<Object> keySerializer;
833             if (keyElem == null) {
834                 keySerializer = provider.findNullKeySerializer(_keyType, _property);
835             } else {
836                 if ((_inclusionChecker != null) && _inclusionChecker.shouldIgnore(keyElem)) {
837                     continue;
838                 }
839                 keySerializer = _keySerializer;
840             }
841 
842             // Then value serializer
843             final Object valueElem = entry.getValue();
844             JsonSerializer<Object> valueSer;
845             if (valueElem == null) {
846                 if (_suppressNulls) { // all suppressions include null-suppression
847                     continue;
848                 }
849                 valueSer = provider.getDefaultNullValueSerializer();
850             } else {
851                 valueSer = _valueSerializer;
852                 if (valueSer == null) {
853                     valueSer = _findSerializer(provider, valueElem);
854                 }
855                 // also may need to skip non-empty values:
856                 if (checkEmpty) {
857                     if (valueSer.isEmpty(provider, valueElem)) {
858                         continue;
859                     }
860                 } else if (suppressableValue != null) {
861                     if (suppressableValue.equals(valueElem)) {
862                         continue;
863                     }
864                 }
865             }
866             // and then serialize, if all went well
867             try {
868                 keySerializer.serialize(keyElem, gen, provider);
869                 valueSer.serialize(valueElem, gen, provider);
870             } catch (Exception e) {
871                 wrapAndThrow(provider, e, value, String.valueOf(keyElem));
872             }
873         }
874     }
875 
876     /**
877      * Method called to serialize fields, when the value type is statically known,
878      * so that value serializer is passed and does not need to be fetched from
879      * provider.
880      */
serializeFieldsUsing(Map<?,?> value, JsonGenerator gen, SerializerProvider provider, JsonSerializer<Object> ser)881     public void serializeFieldsUsing(Map<?,?> value, JsonGenerator gen, SerializerProvider provider,
882             JsonSerializer<Object> ser)
883         throws IOException
884     {
885         final JsonSerializer<Object> keySerializer = _keySerializer;
886         final TypeSerializer typeSer = _valueTypeSerializer;
887 
888         for (Map.Entry<?,?> entry : value.entrySet()) {
889             Object keyElem = entry.getKey();
890             if ((_inclusionChecker != null) && _inclusionChecker.shouldIgnore(keyElem)) {
891                 continue;
892             }
893 
894             if (keyElem == null) {
895                 provider.findNullKeySerializer(_keyType, _property).serialize(null, gen, provider);
896             } else {
897                 keySerializer.serialize(keyElem, gen, provider);
898             }
899             final Object valueElem = entry.getValue();
900             if (valueElem == null) {
901                 provider.defaultSerializeNull(gen);
902             } else {
903                 try {
904                     if (typeSer == null) {
905                         ser.serialize(valueElem, gen, provider);
906                     } else {
907                         ser.serializeWithType(valueElem, gen, provider, typeSer);
908                     }
909                 } catch (Exception e) {
910                     wrapAndThrow(provider, e, value, String.valueOf(keyElem));
911                 }
912             }
913         }
914     }
915 
916     /**
917      * Helper method used when we have a JSON Filter to use for potentially
918      * filtering out Map entries.
919      *
920      * @since 2.5
921      */
serializeFilteredFields(Map<?,?> value, JsonGenerator gen, SerializerProvider provider, PropertyFilter filter, Object suppressableValue)922     public void serializeFilteredFields(Map<?,?> value, JsonGenerator gen, SerializerProvider provider,
923             PropertyFilter filter,
924             Object suppressableValue) // since 2.5
925         throws IOException
926     {
927         final MapProperty prop = new MapProperty(_valueTypeSerializer, _property);
928         final boolean checkEmpty = (MARKER_FOR_EMPTY == suppressableValue);
929 
930         for (Map.Entry<?,?> entry : value.entrySet()) {
931             // First, serialize key; unless ignorable by key
932             final Object keyElem = entry.getKey();
933             if ((_inclusionChecker != null) && _inclusionChecker.shouldIgnore(keyElem)) {
934                 continue;
935             }
936 
937             JsonSerializer<Object> keySerializer;
938             if (keyElem == null) {
939                 keySerializer = provider.findNullKeySerializer(_keyType, _property);
940             } else {
941                 keySerializer = _keySerializer;
942             }
943             // or by value; nulls often suppressed
944             final Object valueElem = entry.getValue();
945 
946             JsonSerializer<Object> valueSer;
947             // And then value
948             if (valueElem == null) {
949                 if (_suppressNulls) {
950                     continue;
951                 }
952                 valueSer = provider.getDefaultNullValueSerializer();
953             } else {
954                 valueSer = _valueSerializer;
955                 if (valueSer == null) {
956                     valueSer = _findSerializer(provider, valueElem);
957                 }
958                 // also may need to skip non-empty values:
959                 if (checkEmpty) {
960                     if (valueSer.isEmpty(provider, valueElem)) {
961                         continue;
962                     }
963                 } else if (suppressableValue != null) {
964                     if (suppressableValue.equals(valueElem)) {
965                         continue;
966                     }
967                 }
968             }
969             // and with that, ask filter to handle it
970             prop.reset(keyElem, valueElem, keySerializer, valueSer);
971             try {
972                 filter.serializeAsField(value, gen, provider, prop);
973             } catch (Exception e) {
974                 wrapAndThrow(provider, e, value, String.valueOf(keyElem));
975             }
976         }
977     }
978 
979     /**
980      * @since 2.5
981      */
serializeTypedFields(Map<?,?> value, JsonGenerator gen, SerializerProvider provider, Object suppressableValue)982     public void serializeTypedFields(Map<?,?> value, JsonGenerator gen, SerializerProvider provider,
983             Object suppressableValue) // since 2.5
984         throws IOException
985     {
986         final boolean checkEmpty = (MARKER_FOR_EMPTY == suppressableValue);
987 
988         for (Map.Entry<?,?> entry : value.entrySet()) {
989             Object keyElem = entry.getKey();
990             JsonSerializer<Object> keySerializer;
991             if (keyElem == null) {
992                 keySerializer = provider.findNullKeySerializer(_keyType, _property);
993             } else {
994                 // One twist: is entry ignorable? If so, skip
995                 if ((_inclusionChecker != null) && _inclusionChecker.shouldIgnore(keyElem)) {
996                     continue;
997                 }
998                 keySerializer = _keySerializer;
999             }
1000             final Object valueElem = entry.getValue();
1001 
1002             // And then value
1003             JsonSerializer<Object> valueSer;
1004             if (valueElem == null) {
1005                 if (_suppressNulls) { // all suppression include null suppression
1006                     continue;
1007                 }
1008                 valueSer = provider.getDefaultNullValueSerializer();
1009             } else {
1010                 valueSer = _valueSerializer;
1011                 if (valueSer == null) {
1012                     valueSer = _findSerializer(provider, valueElem);
1013                 }
1014                 // also may need to skip non-empty values:
1015                 if (checkEmpty) {
1016                     if (valueSer.isEmpty(provider, valueElem)) {
1017                         continue;
1018                     }
1019                 } else if (suppressableValue != null) {
1020                     if (suppressableValue.equals(valueElem)) {
1021                         continue;
1022                     }
1023                 }
1024             }
1025             keySerializer.serialize(keyElem, gen, provider);
1026             try {
1027                 valueSer.serializeWithType(valueElem, gen, provider, _valueTypeSerializer);
1028             } catch (Exception e) {
1029                 wrapAndThrow(provider, e, value, String.valueOf(keyElem));
1030             }
1031         }
1032     }
1033 
1034     /**
1035      * Helper method used when we have a JSON Filter to use AND contents are
1036      * "any properties" of a POJO.
1037      *
1038      * @param bean Enclosing POJO that has any-getter used to obtain "any properties"
1039      *
1040      * @since 2.9
1041      */
serializeFilteredAnyProperties(SerializerProvider provider, JsonGenerator gen, Object bean, Map<?,?> value, PropertyFilter filter, Object suppressableValue)1042     public void serializeFilteredAnyProperties(SerializerProvider provider, JsonGenerator gen,
1043             Object bean, Map<?,?> value, PropertyFilter filter,
1044             Object suppressableValue)
1045         throws IOException
1046     {
1047         final MapProperty prop = new MapProperty(_valueTypeSerializer, _property);
1048         final boolean checkEmpty = (MARKER_FOR_EMPTY == suppressableValue);
1049 
1050         for (Map.Entry<?,?> entry : value.entrySet()) {
1051             // First, serialize key; unless ignorable by key
1052             final Object keyElem = entry.getKey();
1053             if ((_inclusionChecker != null) && _inclusionChecker.shouldIgnore(keyElem)) {
1054                 continue;
1055             }
1056 
1057             JsonSerializer<Object> keySerializer;
1058             if (keyElem == null) {
1059                 keySerializer = provider.findNullKeySerializer(_keyType, _property);
1060             } else {
1061                 keySerializer = _keySerializer;
1062             }
1063             // or by value; nulls often suppressed
1064             final Object valueElem = entry.getValue();
1065 
1066             JsonSerializer<Object> valueSer;
1067             // And then value
1068             if (valueElem == null) {
1069                 if (_suppressNulls) {
1070                     continue;
1071                 }
1072                 valueSer = provider.getDefaultNullValueSerializer();
1073             } else {
1074                 valueSer = _valueSerializer;
1075                 if (valueSer == null) {
1076                     valueSer = _findSerializer(provider, valueElem);
1077                 }
1078                 // also may need to skip non-empty values:
1079                 if (checkEmpty) {
1080                     if (valueSer.isEmpty(provider, valueElem)) {
1081                         continue;
1082                     }
1083                 } else if (suppressableValue != null) {
1084                     if (suppressableValue.equals(valueElem)) {
1085                         continue;
1086                     }
1087                 }
1088             }
1089             // and with that, ask filter to handle it
1090             prop.reset(keyElem, valueElem, keySerializer, valueSer);
1091             try {
1092                 filter.serializeAsField(bean, gen, provider, prop);
1093             } catch (Exception e) {
1094                 wrapAndThrow(provider, e, value, String.valueOf(keyElem));
1095             }
1096         }
1097     }
1098 
1099     /*
1100     /**********************************************************
1101     /* Schema related functionality
1102     /**********************************************************
1103      */
1104 
1105     @Override
getSchema(SerializerProvider provider, Type typeHint)1106     public JsonNode getSchema(SerializerProvider provider, Type typeHint)
1107     {
1108         // even though it's possible to statically determine the "value" type of the map,
1109         // there's no way to statically determine the keys, so the "Entries" can't be determined.
1110         return createSchemaNode("object", true);
1111     }
1112 
1113     @Override
acceptJsonFormatVisitor(JsonFormatVisitorWrapper visitor, JavaType typeHint)1114     public void acceptJsonFormatVisitor(JsonFormatVisitorWrapper visitor, JavaType typeHint)
1115         throws JsonMappingException
1116     {
1117         JsonMapFormatVisitor v2 = visitor.expectMapFormat(typeHint);
1118         if (v2 != null) {
1119             v2.keyFormat(_keySerializer, _keyType);
1120             JsonSerializer<?> valueSer = _valueSerializer;
1121             if (valueSer == null) {
1122                 valueSer = _findAndAddDynamic(_dynamicValueSerializers,
1123                             _valueType, visitor.getProvider());
1124             }
1125             v2.valueFormat(valueSer, _valueType);
1126         }
1127     }
1128 
1129     /*
1130     /**********************************************************
1131     /* Internal helper methods
1132     /**********************************************************
1133      */
1134 
_findAndAddDynamic(PropertySerializerMap map, Class<?> type, SerializerProvider provider)1135     protected final JsonSerializer<Object> _findAndAddDynamic(PropertySerializerMap map,
1136             Class<?> type, SerializerProvider provider) throws JsonMappingException
1137     {
1138         PropertySerializerMap.SerializerAndMapResult result = map.findAndAddSecondarySerializer(type, provider, _property);
1139         // did we get a new map of serializers? If so, start using it
1140         if (map != result.map) {
1141             _dynamicValueSerializers = result.map;
1142         }
1143         return result.serializer;
1144     }
1145 
_findAndAddDynamic(PropertySerializerMap map, JavaType type, SerializerProvider provider)1146     protected final JsonSerializer<Object> _findAndAddDynamic(PropertySerializerMap map,
1147             JavaType type, SerializerProvider provider) throws JsonMappingException
1148     {
1149         PropertySerializerMap.SerializerAndMapResult result = map.findAndAddSecondarySerializer(type, provider, _property);
1150         if (map != result.map) {
1151             _dynamicValueSerializers = result.map;
1152         }
1153         return result.serializer;
1154     }
1155 
_orderEntries(Map<?,?> input, JsonGenerator gen, SerializerProvider provider)1156     protected Map<?,?> _orderEntries(Map<?,?> input, JsonGenerator gen,
1157             SerializerProvider provider) throws IOException
1158     {
1159         // minor optimization: may already be sorted?
1160         if (input instanceof SortedMap<?,?>) {
1161             return input;
1162         }
1163         // [databind#1411]: TreeMap does not like null key... (although note that
1164         //   check above should prevent this code from being called in that case)
1165         // [databind#153]: but, apparently, some custom Maps do manage hit this
1166         //   problem.
1167         if (_hasNullKey(input)) {
1168             TreeMap<Object,Object> result = new TreeMap<Object,Object>();
1169             for (Map.Entry<?,?> entry : input.entrySet()) {
1170                 Object key = entry.getKey();
1171                 if (key == null) {
1172                     _writeNullKeyedEntry(gen, provider, entry.getValue());
1173                     continue;
1174                 }
1175                 result.put(key, entry.getValue());
1176             }
1177             return result;
1178         }
1179         return new TreeMap<Object,Object>(input);
1180     }
1181 
1182     /**
1183      * @since 2.8.7
1184      */
_hasNullKey(Map<?,?> input)1185     protected boolean _hasNullKey(Map<?,?> input) {
1186         // 19-Feb-2017, tatu: As per [databind#1513] there are many cases where `null`
1187         //   keys are not allowed, and even attempt to check for presence can cause
1188         //   problems. Without resorting to external sorting (and internal API change),
1189         //   or custom sortable Map implementation (more code) we can try black- or
1190         //   white-listing (that is; either skip known problem cases; or only apply for
1191         //   known good cases).
1192         //   While my first instinct was to do black-listing (remove Hashtable and ConcurrentHashMap),
1193         //   all in all it is probably better to just white list `HashMap` (and its sub-classes).
1194 
1195         return (input instanceof HashMap) && input.containsKey(null);
1196     }
1197 
_writeNullKeyedEntry(JsonGenerator gen, SerializerProvider provider, Object value)1198     protected void _writeNullKeyedEntry(JsonGenerator gen, SerializerProvider provider,
1199             Object value) throws IOException
1200     {
1201         JsonSerializer<Object> keySerializer = provider.findNullKeySerializer(_keyType, _property);
1202         JsonSerializer<Object> valueSer;
1203         if (value == null) {
1204             if (_suppressNulls) {
1205                 return;
1206             }
1207             valueSer = provider.getDefaultNullValueSerializer();
1208         } else {
1209             valueSer = _valueSerializer;
1210             if (valueSer == null) {
1211                 valueSer = _findSerializer(provider, value);
1212             }
1213             if (_suppressableValue == MARKER_FOR_EMPTY) {
1214                 if (valueSer.isEmpty(provider, value)) {
1215                     return;
1216                 }
1217             } else if ((_suppressableValue != null)
1218                 && (_suppressableValue.equals(value))) {
1219                 return;
1220             }
1221         }
1222 
1223         try {
1224             keySerializer.serialize(null, gen, provider);
1225             valueSer.serialize(value, gen, provider);
1226         } catch (Exception e) {
1227             wrapAndThrow(provider, e, value, "");
1228         }
1229     }
1230 
_findSerializer(SerializerProvider provider, Object value)1231     private final JsonSerializer<Object> _findSerializer(SerializerProvider provider,
1232             Object value) throws JsonMappingException
1233     {
1234         final Class<?> cc = value.getClass();
1235         JsonSerializer<Object> valueSer = _dynamicValueSerializers.serializerFor(cc);
1236         if (valueSer != null) {
1237             return valueSer;
1238         }
1239         if (_valueType.hasGenericTypes()) {
1240             return _findAndAddDynamic(_dynamicValueSerializers,
1241                     provider.constructSpecializedType(_valueType, cc), provider);
1242         }
1243         return _findAndAddDynamic(_dynamicValueSerializers, cc, provider);
1244     }
1245 }
1246