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