1 package com.fasterxml.jackson.databind.deser.std; 2 3 import java.io.IOException; 4 import java.util.*; 5 6 import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 7 8 import com.fasterxml.jackson.annotation.JsonIncludeProperties; 9 import com.fasterxml.jackson.core.*; 10 11 import com.fasterxml.jackson.databind.*; 12 import com.fasterxml.jackson.databind.annotation.JacksonStdImpl; 13 import com.fasterxml.jackson.databind.deser.*; 14 import com.fasterxml.jackson.databind.deser.impl.PropertyBasedCreator; 15 import com.fasterxml.jackson.databind.deser.impl.PropertyValueBuffer; 16 import com.fasterxml.jackson.databind.deser.impl.ReadableObjectId.Referring; 17 import com.fasterxml.jackson.databind.introspect.AnnotatedMember; 18 import com.fasterxml.jackson.databind.jsontype.TypeDeserializer; 19 import com.fasterxml.jackson.databind.type.LogicalType; 20 import com.fasterxml.jackson.databind.util.ArrayBuilders; 21 import com.fasterxml.jackson.databind.util.IgnorePropertiesUtil; 22 23 /** 24 * Basic deserializer that can take JSON "Object" structure and 25 * construct a {@link java.util.Map} instance, with typed contents. 26 *<p> 27 * Note: for untyped content (one indicated by passing Object.class 28 * as the type), {@link UntypedObjectDeserializer} is used instead. 29 * It can also construct {@link java.util.Map}s, but not with specific 30 * POJO types, only other containers and primitives/wrappers. 31 */ 32 @JacksonStdImpl 33 public class MapDeserializer 34 extends ContainerDeserializerBase<Map<Object,Object>> 35 implements ContextualDeserializer, ResolvableDeserializer 36 { 37 private static final long serialVersionUID = 1L; 38 39 // // Configuration: typing, deserializers 40 41 /** 42 * Key deserializer to use; either passed via constructor 43 * (when indicated by annotations), or resolved when 44 * {@link #resolve} is called; 45 */ 46 protected final KeyDeserializer _keyDeserializer; 47 48 /** 49 * Flag set to indicate that the key type is 50 * {@link java.lang.String} (or {@link java.lang.Object}, for 51 * which String is acceptable), <b>and</b> that the 52 * default Jackson key deserializer would be used. 53 * If both are true, can optimize handling. 54 */ 55 protected boolean _standardStringKey; 56 57 /** 58 * Value deserializer. 59 */ 60 protected final JsonDeserializer<Object> _valueDeserializer; 61 62 /** 63 * If value instances have polymorphic type information, this 64 * is the type deserializer that can handle it 65 */ 66 protected final TypeDeserializer _valueTypeDeserializer; 67 68 // // Instance construction settings: 69 70 protected final ValueInstantiator _valueInstantiator; 71 72 /** 73 * Deserializer that is used iff delegate-based creator is 74 * to be used for deserializing from JSON Object. 75 */ 76 protected JsonDeserializer<Object> _delegateDeserializer; 77 78 /** 79 * If the Map is to be instantiated using non-default constructor 80 * or factory method 81 * that takes one or more named properties as argument(s), 82 * this creator is used for instantiation. 83 */ 84 protected PropertyBasedCreator _propertyBasedCreator; 85 86 protected final boolean _hasDefaultCreator; 87 88 // // Any properties to ignore if seen? 89 90 protected Set<String> _ignorableProperties; 91 92 /** 93 * @since 2.12 94 */ 95 protected Set<String> _includableProperties; 96 97 /** 98 * Helper object used for name-based filtering 99 * 100 * @since 2.12 101 */ 102 protected IgnorePropertiesUtil.Checker _inclusionChecker; 103 104 /* 105 /********************************************************** 106 /* Life-cycle 107 /********************************************************** 108 */ 109 MapDeserializer(JavaType mapType, ValueInstantiator valueInstantiator, KeyDeserializer keyDeser, JsonDeserializer<Object> valueDeser, TypeDeserializer valueTypeDeser)110 public MapDeserializer(JavaType mapType, ValueInstantiator valueInstantiator, 111 KeyDeserializer keyDeser, JsonDeserializer<Object> valueDeser, 112 TypeDeserializer valueTypeDeser) 113 { 114 super(mapType, null, null); 115 _keyDeserializer = keyDeser; 116 _valueDeserializer = valueDeser; 117 _valueTypeDeserializer = valueTypeDeser; 118 _valueInstantiator = valueInstantiator; 119 _hasDefaultCreator = valueInstantiator.canCreateUsingDefault(); 120 _delegateDeserializer = null; 121 _propertyBasedCreator = null; 122 _standardStringKey = _isStdKeyDeser(mapType, keyDeser); 123 _inclusionChecker = null; 124 } 125 126 /** 127 * Copy-constructor that can be used by sub-classes to allow 128 * copy-on-write styling copying of settings of an existing instance. 129 */ MapDeserializer(MapDeserializer src)130 protected MapDeserializer(MapDeserializer src) 131 { 132 super(src); 133 _keyDeserializer = src._keyDeserializer; 134 _valueDeserializer = src._valueDeserializer; 135 _valueTypeDeserializer = src._valueTypeDeserializer; 136 _valueInstantiator = src._valueInstantiator; 137 _propertyBasedCreator = src._propertyBasedCreator; 138 _delegateDeserializer = src._delegateDeserializer; 139 _hasDefaultCreator = src._hasDefaultCreator; 140 // should we make a copy here? 141 _ignorableProperties = src._ignorableProperties; 142 _includableProperties = src._includableProperties; 143 _inclusionChecker = src._inclusionChecker; 144 145 _standardStringKey = src._standardStringKey; 146 } 147 MapDeserializer(MapDeserializer src, KeyDeserializer keyDeser, JsonDeserializer<Object> valueDeser, TypeDeserializer valueTypeDeser, NullValueProvider nuller, Set<String> ignorable)148 protected MapDeserializer(MapDeserializer src, 149 KeyDeserializer keyDeser, JsonDeserializer<Object> valueDeser, 150 TypeDeserializer valueTypeDeser, 151 NullValueProvider nuller, 152 Set<String> ignorable) 153 { 154 this(src, keyDeser,valueDeser, valueTypeDeser, nuller, ignorable, null); 155 } 156 157 /** 158 * @since 2.12 159 */ MapDeserializer(MapDeserializer src, KeyDeserializer keyDeser, JsonDeserializer<Object> valueDeser, TypeDeserializer valueTypeDeser, NullValueProvider nuller, Set<String> ignorable, Set<String> includable)160 protected MapDeserializer(MapDeserializer src, 161 KeyDeserializer keyDeser, JsonDeserializer<Object> valueDeser, 162 TypeDeserializer valueTypeDeser, 163 NullValueProvider nuller, 164 Set<String> ignorable, 165 Set<String> includable) 166 { 167 super(src, nuller, src._unwrapSingle); 168 _keyDeserializer = keyDeser; 169 _valueDeserializer = valueDeser; 170 _valueTypeDeserializer = valueTypeDeser; 171 _valueInstantiator = src._valueInstantiator; 172 _propertyBasedCreator = src._propertyBasedCreator; 173 _delegateDeserializer = src._delegateDeserializer; 174 _hasDefaultCreator = src._hasDefaultCreator; 175 _ignorableProperties = ignorable; 176 _includableProperties = includable; 177 _inclusionChecker = IgnorePropertiesUtil.buildCheckerIfNeeded(ignorable, includable); 178 179 _standardStringKey = _isStdKeyDeser(_containerType, keyDeser); 180 } 181 182 /** 183 * Fluent factory method used to create a copy with slightly 184 * different settings. When sub-classing, MUST be overridden. 185 */ withResolved(KeyDeserializer keyDeser, TypeDeserializer valueTypeDeser, JsonDeserializer<?> valueDeser, NullValueProvider nuller, Set<String> ignorable)186 protected MapDeserializer withResolved(KeyDeserializer keyDeser, 187 TypeDeserializer valueTypeDeser, JsonDeserializer<?> valueDeser, 188 NullValueProvider nuller, 189 Set<String> ignorable) 190 { 191 return withResolved(keyDeser, valueTypeDeser, valueDeser, nuller, ignorable, _includableProperties); 192 } 193 194 /** 195 * @since 2.12 196 */ 197 @SuppressWarnings("unchecked") withResolved(KeyDeserializer keyDeser, TypeDeserializer valueTypeDeser, JsonDeserializer<?> valueDeser, NullValueProvider nuller, Set<String> ignorable, Set<String> includable)198 protected MapDeserializer withResolved(KeyDeserializer keyDeser, 199 TypeDeserializer valueTypeDeser, JsonDeserializer<?> valueDeser, 200 NullValueProvider nuller, 201 Set<String> ignorable, Set<String> includable) 202 { 203 if ((_keyDeserializer == keyDeser) && (_valueDeserializer == valueDeser) 204 && (_valueTypeDeserializer == valueTypeDeser) && (_nullProvider == nuller) 205 && (_ignorableProperties == ignorable) && (_includableProperties == includable)) { 206 return this; 207 } 208 return new MapDeserializer(this, 209 keyDeser, (JsonDeserializer<Object>) valueDeser, valueTypeDeser, 210 nuller, ignorable, includable); 211 } 212 213 /** 214 * Helper method used to check whether we can just use the default key 215 * deserialization, where JSON String becomes Java String. 216 */ _isStdKeyDeser(JavaType mapType, KeyDeserializer keyDeser)217 protected final boolean _isStdKeyDeser(JavaType mapType, KeyDeserializer keyDeser) 218 { 219 if (keyDeser == null) { 220 return true; 221 } 222 JavaType keyType = mapType.getKeyType(); 223 if (keyType == null) { // assumed to be Object 224 return true; 225 } 226 Class<?> rawKeyType = keyType.getRawClass(); 227 return ((rawKeyType == String.class || rawKeyType == Object.class) 228 && isDefaultKeyDeserializer(keyDeser)); 229 } 230 231 /** 232 * @deprecated in 2.12, remove from 3.0 233 */ 234 @Deprecated setIgnorableProperties(String[] ignorable)235 public void setIgnorableProperties(String[] ignorable) { 236 _ignorableProperties = (ignorable == null || ignorable.length == 0) ? 237 null : ArrayBuilders.arrayToSet(ignorable); 238 _inclusionChecker = IgnorePropertiesUtil.buildCheckerIfNeeded(_ignorableProperties, _includableProperties); 239 } 240 setIgnorableProperties(Set<String> ignorable)241 public void setIgnorableProperties(Set<String> ignorable) { 242 _ignorableProperties = (ignorable == null || ignorable.size() == 0) ? 243 null : ignorable; 244 _inclusionChecker = IgnorePropertiesUtil.buildCheckerIfNeeded(_ignorableProperties, _includableProperties); 245 } 246 setIncludableProperties(Set<String> includable)247 public void setIncludableProperties(Set<String> includable) { 248 _includableProperties = includable; 249 _inclusionChecker = IgnorePropertiesUtil.buildCheckerIfNeeded(_ignorableProperties, _includableProperties); 250 } 251 252 /* 253 /********************************************************** 254 /* Validation, post-processing (ResolvableDeserializer) 255 /********************************************************** 256 */ 257 258 @Override resolve(DeserializationContext ctxt)259 public void resolve(DeserializationContext ctxt) throws JsonMappingException 260 { 261 // May need to resolve types for delegate- and/or property-based creators: 262 if (_valueInstantiator.canCreateUsingDelegate()) { 263 JavaType delegateType = _valueInstantiator.getDelegateType(ctxt.getConfig()); 264 if (delegateType == null) { 265 ctxt.reportBadDefinition(_containerType, String.format( 266 "Invalid delegate-creator definition for %s: value instantiator (%s) returned true for 'canCreateUsingDelegate()', but null for 'getDelegateType()'", 267 _containerType, 268 _valueInstantiator.getClass().getName())); 269 } 270 // Theoretically should be able to get CreatorProperty for delegate 271 // parameter to pass; but things get tricky because DelegateCreator 272 // may contain injectable values. So, for now, let's pass nothing. 273 _delegateDeserializer = findDeserializer(ctxt, delegateType, null); 274 } else if (_valueInstantiator.canCreateUsingArrayDelegate()) { 275 JavaType delegateType = _valueInstantiator.getArrayDelegateType(ctxt.getConfig()); 276 if (delegateType == null) { 277 ctxt.reportBadDefinition(_containerType, String.format( 278 "Invalid delegate-creator definition for %s: value instantiator (%s) returned true for 'canCreateUsingArrayDelegate()', but null for 'getArrayDelegateType()'", 279 _containerType, 280 _valueInstantiator.getClass().getName())); 281 } 282 _delegateDeserializer = findDeserializer(ctxt, delegateType, null); 283 } 284 if (_valueInstantiator.canCreateFromObjectWith()) { 285 SettableBeanProperty[] creatorProps = _valueInstantiator.getFromObjectArguments(ctxt.getConfig()); 286 _propertyBasedCreator = PropertyBasedCreator.construct(ctxt, _valueInstantiator, creatorProps, 287 ctxt.isEnabled(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES)); 288 } 289 _standardStringKey = _isStdKeyDeser(_containerType, _keyDeserializer); 290 } 291 292 /** 293 * Method called to finalize setup of this deserializer, 294 * when it is known for which property deserializer is needed for. 295 */ 296 @Override createContextual(DeserializationContext ctxt, BeanProperty property)297 public JsonDeserializer<?> createContextual(DeserializationContext ctxt, 298 BeanProperty property) throws JsonMappingException 299 { 300 KeyDeserializer keyDeser = _keyDeserializer; 301 if (keyDeser == null) { 302 keyDeser = ctxt.findKeyDeserializer(_containerType.getKeyType(), property); 303 } else { 304 if (keyDeser instanceof ContextualKeyDeserializer) { 305 keyDeser = ((ContextualKeyDeserializer) keyDeser).createContextual(ctxt, property); 306 } 307 } 308 309 JsonDeserializer<?> valueDeser = _valueDeserializer; 310 // [databind#125]: May have a content converter 311 if (property != null) { 312 valueDeser = findConvertingContentDeserializer(ctxt, property, valueDeser); 313 } 314 final JavaType vt = _containerType.getContentType(); 315 if (valueDeser == null) { 316 valueDeser = ctxt.findContextualValueDeserializer(vt, property); 317 } else { // if directly assigned, probably not yet contextual, so: 318 valueDeser = ctxt.handleSecondaryContextualization(valueDeser, property, vt); 319 } 320 TypeDeserializer vtd = _valueTypeDeserializer; 321 if (vtd != null) { 322 vtd = vtd.forProperty(property); 323 } 324 Set<String> ignored = _ignorableProperties; 325 Set<String> included = _includableProperties; 326 AnnotationIntrospector intr = ctxt.getAnnotationIntrospector(); 327 if (_neitherNull(intr, property)) { 328 AnnotatedMember member = property.getMember(); 329 if (member != null) { 330 final DeserializationConfig config = ctxt.getConfig(); 331 JsonIgnoreProperties.Value ignorals = intr.findPropertyIgnoralByName(config, member); 332 if (ignorals != null) { 333 Set<String> ignoresToAdd = ignorals.findIgnoredForDeserialization(); 334 if (!ignoresToAdd.isEmpty()) { 335 ignored = (ignored == null) ? new HashSet<String>() : new HashSet<String>(ignored); 336 for (String str : ignoresToAdd) { 337 ignored.add(str); 338 } 339 } 340 } 341 JsonIncludeProperties.Value inclusions = intr.findPropertyInclusionByName(config, member); 342 if (inclusions != null) { 343 Set<String> includedToAdd = inclusions.getIncluded(); 344 if (includedToAdd != null) { 345 Set<String> newIncluded = new HashSet<>(); 346 if (included == null) { 347 newIncluded = new HashSet<>(includedToAdd); 348 } else { 349 for (String str : includedToAdd) { 350 if (included.contains(str)) { 351 newIncluded.add(str); 352 } 353 } 354 } 355 included = newIncluded; 356 } 357 } 358 } 359 } 360 return withResolved(keyDeser, vtd, valueDeser, 361 findContentNullProvider(ctxt, property, valueDeser), ignored, included); 362 } 363 364 /* 365 /********************************************************** 366 /* ContainerDeserializerBase API 367 /********************************************************** 368 */ 369 370 @Override getContentDeserializer()371 public JsonDeserializer<Object> getContentDeserializer() { 372 return _valueDeserializer; 373 } 374 375 @Override getValueInstantiator()376 public ValueInstantiator getValueInstantiator() { 377 return _valueInstantiator; 378 } 379 380 /* 381 /********************************************************** 382 /* JsonDeserializer API 383 /********************************************************** 384 */ 385 386 /** 387 * Turns out that these are expensive enough to create so that caching 388 * does make sense. 389 *<p> 390 * IMPORTANT: but, note, that instances CAN NOT BE CACHED if there is 391 * a value type deserializer; this caused an issue with 2.4.4 of 392 * JAXB Annotations (failing a test). 393 * It is also possible that some other settings could make deserializers 394 * un-cacheable; but on the other hand, caching can make a big positive 395 * difference with performance... so it's a hard choice. 396 * 397 * @since 2.4.4 398 */ 399 @Override isCachable()400 public boolean isCachable() { 401 // As per [databind#735], existence of value or key deserializer (only passed 402 // if annotated to use non-standard one) should also prevent caching. 403 return (_valueDeserializer == null) 404 && (_keyDeserializer == null) 405 && (_valueTypeDeserializer == null) 406 && (_ignorableProperties == null) 407 && (_includableProperties == null); 408 } 409 410 @Override // since 2.12 logicalType()411 public LogicalType logicalType() { 412 return LogicalType.Map; 413 } 414 415 @Override 416 @SuppressWarnings("unchecked") deserialize(JsonParser p, DeserializationContext ctxt)417 public Map<Object,Object> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException 418 { 419 if (_propertyBasedCreator != null) { 420 return _deserializeUsingCreator(p, ctxt); 421 } 422 if (_delegateDeserializer != null) { 423 return (Map<Object,Object>) _valueInstantiator.createUsingDelegate(ctxt, 424 _delegateDeserializer.deserialize(p, ctxt)); 425 } 426 if (!_hasDefaultCreator) { 427 return (Map<Object,Object> ) ctxt.handleMissingInstantiator(getMapClass(), 428 getValueInstantiator(), p, 429 "no default constructor found"); 430 } 431 switch (p.currentTokenId()) { 432 case JsonTokenId.ID_START_OBJECT: 433 case JsonTokenId.ID_END_OBJECT: 434 case JsonTokenId.ID_FIELD_NAME: 435 final Map<Object,Object> result = (Map<Object,Object>) _valueInstantiator.createUsingDefault(ctxt); 436 if (_standardStringKey) { 437 _readAndBindStringKeyMap(p, ctxt, result); 438 return result; 439 } 440 _readAndBind(p, ctxt, result); 441 return result; 442 case JsonTokenId.ID_STRING: 443 // (empty) String may be ok however; or single-String-arg ctor 444 return _deserializeFromString(p, ctxt); 445 case JsonTokenId.ID_START_ARRAY: 446 // Empty array, or single-value wrapped in array? 447 return _deserializeFromArray(p, ctxt); 448 default: 449 } 450 return (Map<Object,Object>) ctxt.handleUnexpectedToken(getValueType(ctxt), p); 451 } 452 453 @SuppressWarnings("unchecked") 454 @Override deserialize(JsonParser p, DeserializationContext ctxt, Map<Object,Object> result)455 public Map<Object,Object> deserialize(JsonParser p, DeserializationContext ctxt, 456 Map<Object,Object> result) 457 throws IOException 458 { 459 // [databind#631]: Assign current value, to be accessible by custom deserializers 460 p.setCurrentValue(result); 461 462 // Ok: must point to START_OBJECT or FIELD_NAME 463 JsonToken t = p.currentToken(); 464 if (t != JsonToken.START_OBJECT && t != JsonToken.FIELD_NAME) { 465 return (Map<Object,Object>) ctxt.handleUnexpectedToken(getMapClass(), p); 466 } 467 // 21-Apr-2017, tatu: Need separate methods to do proper merging 468 if (_standardStringKey) { 469 _readAndUpdateStringKeyMap(p, ctxt, result); 470 return result; 471 } 472 _readAndUpdate(p, ctxt, result); 473 return result; 474 } 475 476 @Override deserializeWithType(JsonParser p, DeserializationContext ctxt, TypeDeserializer typeDeserializer)477 public Object deserializeWithType(JsonParser p, DeserializationContext ctxt, 478 TypeDeserializer typeDeserializer) 479 throws IOException 480 { 481 // In future could check current token... for now this should be enough: 482 return typeDeserializer.deserializeTypedFromObject(p, ctxt); 483 } 484 485 /* 486 /********************************************************** 487 /* Other public accessors 488 /********************************************************** 489 */ 490 491 @SuppressWarnings("unchecked") getMapClass()492 public final Class<?> getMapClass() { return (Class<Map<Object,Object>>) _containerType.getRawClass(); } 493 getValueType()494 @Override public JavaType getValueType() { return _containerType; } 495 496 /* 497 /********************************************************** 498 /* Internal methods, non-merging deserialization 499 /********************************************************** 500 */ 501 _readAndBind(JsonParser p, DeserializationContext ctxt, Map<Object,Object> result)502 protected final void _readAndBind(JsonParser p, DeserializationContext ctxt, 503 Map<Object,Object> result) throws IOException 504 { 505 final KeyDeserializer keyDes = _keyDeserializer; 506 final JsonDeserializer<Object> valueDes = _valueDeserializer; 507 final TypeDeserializer typeDeser = _valueTypeDeserializer; 508 509 MapReferringAccumulator referringAccumulator = null; 510 boolean useObjectId = valueDes.getObjectIdReader() != null; 511 if (useObjectId) { 512 referringAccumulator = new MapReferringAccumulator(_containerType.getContentType().getRawClass(), 513 result); 514 } 515 516 String keyStr; 517 if (p.isExpectedStartObjectToken()) { 518 keyStr = p.nextFieldName(); 519 } else { 520 JsonToken t = p.currentToken(); 521 if (t != JsonToken.FIELD_NAME) { 522 if (t == JsonToken.END_OBJECT) { 523 return; 524 } 525 ctxt.reportWrongTokenException(this, JsonToken.FIELD_NAME, null); 526 } 527 keyStr = p.currentName(); 528 } 529 530 for (; keyStr != null; keyStr = p.nextFieldName()) { 531 Object key = keyDes.deserializeKey(keyStr, ctxt); 532 // And then the value... 533 JsonToken t = p.nextToken(); 534 if ((_inclusionChecker != null) && _inclusionChecker.shouldIgnore(keyStr)) { 535 p.skipChildren(); 536 continue; 537 } 538 try { 539 // Note: must handle null explicitly here; value deserializers won't 540 Object value; 541 if (t == JsonToken.VALUE_NULL) { 542 if (_skipNullValues) { 543 continue; 544 } 545 value = _nullProvider.getNullValue(ctxt); 546 } else if (typeDeser == null) { 547 value = valueDes.deserialize(p, ctxt); 548 } else { 549 value = valueDes.deserializeWithType(p, ctxt, typeDeser); 550 } 551 if (useObjectId) { 552 referringAccumulator.put(key, value); 553 } else { 554 result.put(key, value); 555 } 556 } catch (UnresolvedForwardReference reference) { 557 handleUnresolvedReference(ctxt, referringAccumulator, key, reference); 558 } catch (Exception e) { 559 wrapAndThrow(e, result, keyStr); 560 } 561 } 562 } 563 564 /** 565 * Optimized method used when keys can be deserialized as plain old 566 * {@link java.lang.String}s, and there is no custom deserialized 567 * specified. 568 */ _readAndBindStringKeyMap(JsonParser p, DeserializationContext ctxt, Map<Object,Object> result)569 protected final void _readAndBindStringKeyMap(JsonParser p, DeserializationContext ctxt, 570 Map<Object,Object> result) throws IOException 571 { 572 final JsonDeserializer<Object> valueDes = _valueDeserializer; 573 final TypeDeserializer typeDeser = _valueTypeDeserializer; 574 MapReferringAccumulator referringAccumulator = null; 575 boolean useObjectId = (valueDes.getObjectIdReader() != null); 576 if (useObjectId) { 577 referringAccumulator = new MapReferringAccumulator(_containerType.getContentType().getRawClass(), result); 578 } 579 580 String key; 581 if (p.isExpectedStartObjectToken()) { 582 key = p.nextFieldName(); 583 } else { 584 JsonToken t = p.currentToken(); 585 if (t == JsonToken.END_OBJECT) { 586 return; 587 } 588 if (t != JsonToken.FIELD_NAME) { 589 ctxt.reportWrongTokenException(this, JsonToken.FIELD_NAME, null); 590 } 591 key = p.currentName(); 592 } 593 594 for (; key != null; key = p.nextFieldName()) { 595 JsonToken t = p.nextToken(); 596 if ((_inclusionChecker != null) && _inclusionChecker.shouldIgnore(key)) { 597 p.skipChildren(); 598 continue; 599 } 600 try { 601 // Note: must handle null explicitly here; value deserializers won't 602 Object value; 603 if (t == JsonToken.VALUE_NULL) { 604 if (_skipNullValues) { 605 continue; 606 } 607 value = _nullProvider.getNullValue(ctxt); 608 } else if (typeDeser == null) { 609 value = valueDes.deserialize(p, ctxt); 610 } else { 611 value = valueDes.deserializeWithType(p, ctxt, typeDeser); 612 } 613 if (useObjectId) { 614 referringAccumulator.put(key, value); 615 } else { 616 result.put(key, value); 617 } 618 } catch (UnresolvedForwardReference reference) { 619 handleUnresolvedReference(ctxt, referringAccumulator, key, reference); 620 } catch (Exception e) { 621 wrapAndThrow(e, result, key); 622 } 623 } 624 // 23-Mar-2015, tatu: TODO: verify we got END_OBJECT? 625 } 626 627 @SuppressWarnings("unchecked") _deserializeUsingCreator(JsonParser p, DeserializationContext ctxt)628 public Map<Object,Object> _deserializeUsingCreator(JsonParser p, DeserializationContext ctxt) throws IOException 629 { 630 final PropertyBasedCreator creator = _propertyBasedCreator; 631 // null -> no ObjectIdReader for Maps (yet?) 632 PropertyValueBuffer buffer = creator.startBuilding(p, ctxt, null); 633 634 final JsonDeserializer<Object> valueDes = _valueDeserializer; 635 final TypeDeserializer typeDeser = _valueTypeDeserializer; 636 637 String key; 638 if (p.isExpectedStartObjectToken()) { 639 key = p.nextFieldName(); 640 } else if (p.hasToken(JsonToken.FIELD_NAME)) { 641 key = p.currentName(); 642 } else { 643 key = null; 644 } 645 646 for (; key != null; key = p.nextFieldName()) { 647 JsonToken t = p.nextToken(); // to get to value 648 if ((_inclusionChecker != null) && _inclusionChecker.shouldIgnore(key)) { 649 p.skipChildren(); // and skip it (in case of array/object) 650 continue; 651 } 652 // creator property? 653 SettableBeanProperty prop = creator.findCreatorProperty(key); 654 if (prop != null) { 655 // Last property to set? 656 if (buffer.assignParameter(prop, prop.deserialize(p, ctxt))) { 657 p.nextToken(); // from value to END_OBJECT or FIELD_NAME 658 Map<Object,Object> result; 659 try { 660 result = (Map<Object,Object>)creator.build(ctxt, buffer); 661 } catch (Exception e) { 662 return wrapAndThrow(e, _containerType.getRawClass(), key); 663 } 664 _readAndBind(p, ctxt, result); 665 return result; 666 } 667 continue; 668 } 669 // other property? needs buffering 670 Object actualKey = _keyDeserializer.deserializeKey(key, ctxt); 671 Object value; 672 673 try { 674 if (t == JsonToken.VALUE_NULL) { 675 if (_skipNullValues) { 676 continue; 677 } 678 value = _nullProvider.getNullValue(ctxt); 679 } else if (typeDeser == null) { 680 value = valueDes.deserialize(p, ctxt); 681 } else { 682 value = valueDes.deserializeWithType(p, ctxt, typeDeser); 683 } 684 } catch (Exception e) { 685 wrapAndThrow(e, _containerType.getRawClass(), key); 686 return null; 687 } 688 buffer.bufferMapProperty(actualKey, value); 689 } 690 // end of JSON object? 691 // if so, can just construct and leave... 692 try { 693 return (Map<Object,Object>)creator.build(ctxt, buffer); 694 } catch (Exception e) { 695 wrapAndThrow(e, _containerType.getRawClass(), key); 696 return null; 697 } 698 } 699 700 /* 701 /********************************************************** 702 /* Internal methods, non-merging deserialization 703 /********************************************************** 704 */ 705 706 /** 707 * @since 2.9 708 */ _readAndUpdate(JsonParser p, DeserializationContext ctxt, Map<Object,Object> result)709 protected final void _readAndUpdate(JsonParser p, DeserializationContext ctxt, 710 Map<Object,Object> result) throws IOException 711 { 712 final KeyDeserializer keyDes = _keyDeserializer; 713 final JsonDeserializer<Object> valueDes = _valueDeserializer; 714 final TypeDeserializer typeDeser = _valueTypeDeserializer; 715 716 // Note: assumption is that Object Id handling can't really work with merging 717 // and thereby we can (and should) just drop that part 718 719 String keyStr; 720 if (p.isExpectedStartObjectToken()) { 721 keyStr = p.nextFieldName(); 722 } else { 723 JsonToken t = p.currentToken(); 724 if (t == JsonToken.END_OBJECT) { 725 return; 726 } 727 if (t != JsonToken.FIELD_NAME) { 728 ctxt.reportWrongTokenException(this, JsonToken.FIELD_NAME, null); 729 } 730 keyStr = p.currentName(); 731 } 732 733 for (; keyStr != null; keyStr = p.nextFieldName()) { 734 Object key = keyDes.deserializeKey(keyStr, ctxt); 735 // And then the value... 736 JsonToken t = p.nextToken(); 737 if ((_inclusionChecker != null) && _inclusionChecker.shouldIgnore(keyStr)) { 738 p.skipChildren(); 739 continue; 740 } 741 try { 742 // Note: must handle null explicitly here, can't merge etc 743 if (t == JsonToken.VALUE_NULL) { 744 if (_skipNullValues) { 745 continue; 746 } 747 result.put(key, _nullProvider.getNullValue(ctxt)); 748 continue; 749 } 750 Object old = result.get(key); 751 Object value; 752 if (old != null) { 753 if (typeDeser == null) { 754 value = valueDes.deserialize(p, ctxt, old); 755 } else { 756 value = valueDes.deserializeWithType(p, ctxt, typeDeser, old); 757 } 758 } else if (typeDeser == null) { 759 value = valueDes.deserialize(p, ctxt); 760 } else { 761 value = valueDes.deserializeWithType(p, ctxt, typeDeser); 762 } 763 if (value != old) { 764 result.put(key, value); 765 } 766 } catch (Exception e) { 767 wrapAndThrow(e, result, keyStr); 768 } 769 } 770 } 771 772 /** 773 * Optimized method used when keys can be deserialized as plain old 774 * {@link java.lang.String}s, and there is no custom deserializer 775 * specified. 776 * 777 * @since 2.9 778 */ _readAndUpdateStringKeyMap(JsonParser p, DeserializationContext ctxt, Map<Object,Object> result)779 protected final void _readAndUpdateStringKeyMap(JsonParser p, DeserializationContext ctxt, 780 Map<Object,Object> result) throws IOException 781 { 782 final JsonDeserializer<Object> valueDes = _valueDeserializer; 783 final TypeDeserializer typeDeser = _valueTypeDeserializer; 784 785 // Note: assumption is that Object Id handling can't really work with merging 786 // and thereby we can (and should) just drop that part 787 788 String key; 789 if (p.isExpectedStartObjectToken()) { 790 key = p.nextFieldName(); 791 } else { 792 JsonToken t = p.currentToken(); 793 if (t == JsonToken.END_OBJECT) { 794 return; 795 } 796 if (t != JsonToken.FIELD_NAME) { 797 ctxt.reportWrongTokenException(this, JsonToken.FIELD_NAME, null); 798 } 799 key = p.currentName(); 800 } 801 802 for (; key != null; key = p.nextFieldName()) { 803 JsonToken t = p.nextToken(); 804 if ((_inclusionChecker != null) && _inclusionChecker.shouldIgnore(key)) { 805 p.skipChildren(); 806 continue; 807 } 808 try { 809 // Note: must handle null explicitly here, can't merge etc 810 if (t == JsonToken.VALUE_NULL) { 811 if (_skipNullValues) { 812 continue; 813 } 814 result.put(key, _nullProvider.getNullValue(ctxt)); 815 continue; 816 } 817 Object old = result.get(key); 818 Object value; 819 if (old != null) { 820 if (typeDeser == null) { 821 value = valueDes.deserialize(p, ctxt, old); 822 } else { 823 value = valueDes.deserializeWithType(p, ctxt, typeDeser, old); 824 } 825 } else if (typeDeser == null) { 826 value = valueDes.deserialize(p, ctxt); 827 } else { 828 value = valueDes.deserializeWithType(p, ctxt, typeDeser); 829 } 830 if (value != old) { 831 result.put(key, value); 832 } 833 } catch (Exception e) { 834 wrapAndThrow(e, result, key); 835 } 836 } 837 } 838 839 /* 840 /********************************************************** 841 /* Internal methods, other 842 /********************************************************** 843 */ 844 handleUnresolvedReference(DeserializationContext ctxt, MapReferringAccumulator accumulator, Object key, UnresolvedForwardReference reference)845 private void handleUnresolvedReference(DeserializationContext ctxt, 846 MapReferringAccumulator accumulator, 847 Object key, UnresolvedForwardReference reference) 848 throws JsonMappingException 849 { 850 if (accumulator == null) { 851 ctxt.reportInputMismatch(this, 852 "Unresolved forward reference but no identity info: "+reference); 853 } 854 Referring referring = accumulator.handleUnresolvedReference(reference, key); 855 reference.getRoid().appendReferring(referring); 856 } 857 858 private final static class MapReferringAccumulator { 859 private final Class<?> _valueType; 860 private Map<Object,Object> _result; 861 /** 862 * A list of {@link MapReferring} to maintain ordering. 863 */ 864 private List<MapReferring> _accumulator = new ArrayList<MapReferring>(); 865 MapReferringAccumulator(Class<?> valueType, Map<Object, Object> result)866 public MapReferringAccumulator(Class<?> valueType, Map<Object, Object> result) { 867 _valueType = valueType; 868 _result = result; 869 } 870 put(Object key, Object value)871 public void put(Object key, Object value) 872 { 873 if (_accumulator.isEmpty()) { 874 _result.put(key, value); 875 } else { 876 MapReferring ref = _accumulator.get(_accumulator.size() - 1); 877 ref.next.put(key, value); 878 } 879 } 880 handleUnresolvedReference(UnresolvedForwardReference reference, Object key)881 public Referring handleUnresolvedReference(UnresolvedForwardReference reference, Object key) 882 { 883 MapReferring id = new MapReferring(this, reference, _valueType, key); 884 _accumulator.add(id); 885 return id; 886 } 887 resolveForwardReference(Object id, Object value)888 public void resolveForwardReference(Object id, Object value) throws IOException 889 { 890 Iterator<MapReferring> iterator = _accumulator.iterator(); 891 // Resolve ordering after resolution of an id. This means either: 892 // 1- adding to the result map in case of the first unresolved id. 893 // 2- merge the content of the resolved id with its previous unresolved id. 894 Map<Object,Object> previous = _result; 895 while (iterator.hasNext()) { 896 MapReferring ref = iterator.next(); 897 if (ref.hasId(id)) { 898 iterator.remove(); 899 previous.put(ref.key, value); 900 previous.putAll(ref.next); 901 return; 902 } 903 previous = ref.next; 904 } 905 906 throw new IllegalArgumentException("Trying to resolve a forward reference with id [" + id 907 + "] that wasn't previously seen as unresolved."); 908 } 909 } 910 911 /** 912 * Helper class to maintain processing order of value. 913 * The resolved object associated with {@link #key} comes before the values in 914 * {@link #next}. 915 */ 916 static class MapReferring extends Referring { 917 private final MapReferringAccumulator _parent; 918 919 public final Map<Object, Object> next = new LinkedHashMap<Object, Object>(); 920 public final Object key; 921 MapReferring(MapReferringAccumulator parent, UnresolvedForwardReference ref, Class<?> valueType, Object key)922 MapReferring(MapReferringAccumulator parent, UnresolvedForwardReference ref, 923 Class<?> valueType, Object key) 924 { 925 super(ref, valueType); 926 _parent = parent; 927 this.key = key; 928 } 929 930 @Override handleResolvedForwardReference(Object id, Object value)931 public void handleResolvedForwardReference(Object id, Object value) throws IOException { 932 _parent.resolveForwardReference(id, value); 933 } 934 } 935 } 936