1 package com.fasterxml.jackson.databind.deser; 2 3 import java.io.Serializable; 4 import java.math.BigDecimal; 5 import java.math.BigInteger; 6 import java.util.*; 7 import java.util.concurrent.*; 8 import java.util.concurrent.atomic.AtomicReference; 9 10 import com.fasterxml.jackson.annotation.JacksonInject; 11 import com.fasterxml.jackson.annotation.JsonCreator; 12 import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 13 import com.fasterxml.jackson.annotation.JsonIncludeProperties; 14 import com.fasterxml.jackson.annotation.JsonSetter; 15 import com.fasterxml.jackson.annotation.Nulls; 16 import com.fasterxml.jackson.annotation.JsonCreator.Mode; 17 18 import com.fasterxml.jackson.core.JsonParser; 19 20 import com.fasterxml.jackson.databind.*; 21 import com.fasterxml.jackson.databind.cfg.ConfigOverride; 22 import com.fasterxml.jackson.databind.cfg.DeserializerFactoryConfig; 23 import com.fasterxml.jackson.databind.cfg.HandlerInstantiator; 24 import com.fasterxml.jackson.databind.deser.impl.CreatorCandidate; 25 import com.fasterxml.jackson.databind.deser.impl.CreatorCollector; 26 import com.fasterxml.jackson.databind.deser.impl.JDKValueInstantiators; 27 import com.fasterxml.jackson.databind.deser.impl.JavaUtilCollectionsDeserializers; 28 import com.fasterxml.jackson.databind.deser.std.*; 29 import com.fasterxml.jackson.databind.exc.InvalidDefinitionException; 30 import com.fasterxml.jackson.databind.ext.OptionalHandlerFactory; 31 import com.fasterxml.jackson.databind.introspect.*; 32 import com.fasterxml.jackson.databind.jsontype.NamedType; 33 import com.fasterxml.jackson.databind.jsontype.TypeDeserializer; 34 import com.fasterxml.jackson.databind.jsontype.TypeResolverBuilder; 35 import com.fasterxml.jackson.databind.type.*; 36 import com.fasterxml.jackson.databind.util.*; 37 38 /** 39 * Abstract factory base class that can provide deserializers for standard 40 * JDK classes, including collection classes and simple heuristics for 41 * "upcasting" common collection interface types 42 * (such as {@link java.util.Collection}). 43 *<p> 44 * Since all simple deserializers are eagerly instantiated, and there is 45 * no additional introspection or customizability of these types, 46 * this factory is stateless. 47 */ 48 @SuppressWarnings("serial") 49 public abstract class BasicDeserializerFactory 50 extends DeserializerFactory 51 implements java.io.Serializable 52 { 53 private final static Class<?> CLASS_OBJECT = Object.class; 54 private final static Class<?> CLASS_STRING = String.class; 55 private final static Class<?> CLASS_CHAR_SEQUENCE = CharSequence.class; 56 private final static Class<?> CLASS_ITERABLE = Iterable.class; 57 private final static Class<?> CLASS_MAP_ENTRY = Map.Entry.class; 58 private final static Class<?> CLASS_SERIALIZABLE = Serializable.class; 59 60 /** 61 * We need a placeholder for creator properties that don't have name 62 * but are marked with `@JsonWrapped` annotation. 63 */ 64 protected final static PropertyName UNWRAPPED_CREATOR_PARAM_NAME = new PropertyName("@JsonUnwrapped"); 65 66 /* 67 /********************************************************** 68 /* Config 69 /********************************************************** 70 */ 71 72 /** 73 * Configuration settings for this factory; immutable instance (just like this 74 * factory), new version created via copy-constructor (fluent-style) 75 */ 76 protected final DeserializerFactoryConfig _factoryConfig; 77 78 /* 79 /********************************************************** 80 /* Life cycle 81 /********************************************************** 82 */ 83 BasicDeserializerFactory(DeserializerFactoryConfig config)84 protected BasicDeserializerFactory(DeserializerFactoryConfig config) { 85 _factoryConfig = config; 86 } 87 88 /** 89 * Method for getting current {@link DeserializerFactoryConfig}. 90 *<p> 91 * Note that since instances are immutable, you can NOT change settings 92 * by accessing an instance and calling methods: this will simply create 93 * new instance of config object. 94 */ getFactoryConfig()95 public DeserializerFactoryConfig getFactoryConfig() { 96 return _factoryConfig; 97 } 98 withConfig(DeserializerFactoryConfig config)99 protected abstract DeserializerFactory withConfig(DeserializerFactoryConfig config); 100 101 /* 102 /******************************************************** 103 /* Configuration handling: fluent factories 104 /******************************************************** 105 */ 106 107 /** 108 * Convenience method for creating a new factory instance with additional deserializer 109 * provider. 110 */ 111 @Override withAdditionalDeserializers(Deserializers additional)112 public final DeserializerFactory withAdditionalDeserializers(Deserializers additional) { 113 return withConfig(_factoryConfig.withAdditionalDeserializers(additional)); 114 } 115 116 /** 117 * Convenience method for creating a new factory instance with additional 118 * {@link KeyDeserializers}. 119 */ 120 @Override withAdditionalKeyDeserializers(KeyDeserializers additional)121 public final DeserializerFactory withAdditionalKeyDeserializers(KeyDeserializers additional) { 122 return withConfig(_factoryConfig.withAdditionalKeyDeserializers(additional)); 123 } 124 125 /** 126 * Convenience method for creating a new factory instance with additional 127 * {@link BeanDeserializerModifier}. 128 */ 129 @Override withDeserializerModifier(BeanDeserializerModifier modifier)130 public final DeserializerFactory withDeserializerModifier(BeanDeserializerModifier modifier) { 131 return withConfig(_factoryConfig.withDeserializerModifier(modifier)); 132 } 133 134 /** 135 * Convenience method for creating a new factory instance with additional 136 * {@link AbstractTypeResolver}. 137 */ 138 @Override withAbstractTypeResolver(AbstractTypeResolver resolver)139 public final DeserializerFactory withAbstractTypeResolver(AbstractTypeResolver resolver) { 140 return withConfig(_factoryConfig.withAbstractTypeResolver(resolver)); 141 } 142 143 /** 144 * Convenience method for creating a new factory instance with additional 145 * {@link ValueInstantiators}. 146 */ 147 @Override withValueInstantiators(ValueInstantiators instantiators)148 public final DeserializerFactory withValueInstantiators(ValueInstantiators instantiators) { 149 return withConfig(_factoryConfig.withValueInstantiators(instantiators)); 150 } 151 152 /* 153 /********************************************************** 154 /* DeserializerFactory impl (partial): type mappings 155 /********************************************************** 156 */ 157 158 @Override mapAbstractType(DeserializationConfig config, JavaType type)159 public JavaType mapAbstractType(DeserializationConfig config, JavaType type) throws JsonMappingException 160 { 161 // first, general mappings 162 while (true) { 163 JavaType next = _mapAbstractType2(config, type); 164 if (next == null) { 165 return type; 166 } 167 // Should not have to worry about cycles; but better verify since they will invariably occur... :-) 168 // (also: guard against invalid resolution to a non-related type) 169 Class<?> prevCls = type.getRawClass(); 170 Class<?> nextCls = next.getRawClass(); 171 if ((prevCls == nextCls) || !prevCls.isAssignableFrom(nextCls)) { 172 throw new IllegalArgumentException("Invalid abstract type resolution from "+type+" to "+next+": latter is not a subtype of former"); 173 } 174 type = next; 175 } 176 } 177 178 /** 179 * Method that will find abstract type mapping for specified type, doing a single 180 * lookup through registered abstract type resolvers; will not do recursive lookups. 181 */ _mapAbstractType2(DeserializationConfig config, JavaType type)182 private JavaType _mapAbstractType2(DeserializationConfig config, JavaType type) 183 throws JsonMappingException 184 { 185 Class<?> currClass = type.getRawClass(); 186 if (_factoryConfig.hasAbstractTypeResolvers()) { 187 for (AbstractTypeResolver resolver : _factoryConfig.abstractTypeResolvers()) { 188 JavaType concrete = resolver.findTypeMapping(config, type); 189 if ((concrete != null) && !concrete.hasRawClass(currClass)) { 190 return concrete; 191 } 192 } 193 } 194 return null; 195 } 196 197 /* 198 /********************************************************** 199 /* DeserializerFactory impl (partial): ValueInstantiators 200 /********************************************************** 201 */ 202 203 /** 204 * Value instantiator is created both based on creator annotations, 205 * and on optional externally provided instantiators (registered through 206 * module interface). 207 */ 208 @Override findValueInstantiator(DeserializationContext ctxt, BeanDescription beanDesc)209 public ValueInstantiator findValueInstantiator(DeserializationContext ctxt, 210 BeanDescription beanDesc) 211 throws JsonMappingException 212 { 213 final DeserializationConfig config = ctxt.getConfig(); 214 215 ValueInstantiator instantiator = null; 216 // Check @JsonValueInstantiator before anything else 217 AnnotatedClass ac = beanDesc.getClassInfo(); 218 Object instDef = ctxt.getAnnotationIntrospector().findValueInstantiator(ac); 219 if (instDef != null) { 220 instantiator = _valueInstantiatorInstance(config, ac, instDef); 221 } 222 if (instantiator == null) { 223 // Second: see if some of standard Jackson/JDK types might provide value 224 // instantiators. 225 instantiator = JDKValueInstantiators.findStdValueInstantiator(config, beanDesc.getBeanClass()); 226 if (instantiator == null) { 227 instantiator = _constructDefaultValueInstantiator(ctxt, beanDesc); 228 } 229 } 230 231 // finally: anyone want to modify ValueInstantiator? 232 if (_factoryConfig.hasValueInstantiators()) { 233 for (ValueInstantiators insts : _factoryConfig.valueInstantiators()) { 234 instantiator = insts.findValueInstantiator(config, beanDesc, instantiator); 235 // let's do sanity check; easier to spot buggy handlers 236 if (instantiator == null) { 237 ctxt.reportBadTypeDefinition(beanDesc, 238 "Broken registered ValueInstantiators (of type %s): returned null ValueInstantiator", 239 insts.getClass().getName()); 240 } 241 } 242 } 243 if (instantiator != null) { 244 instantiator = instantiator.createContextual(ctxt, beanDesc); 245 } 246 247 return instantiator; 248 } 249 250 /** 251 * Method that will construct standard default {@link ValueInstantiator} 252 * using annotations (like @JsonCreator) and visibility rules 253 */ _constructDefaultValueInstantiator(DeserializationContext ctxt, BeanDescription beanDesc)254 protected ValueInstantiator _constructDefaultValueInstantiator(DeserializationContext ctxt, 255 BeanDescription beanDesc) 256 throws JsonMappingException 257 { 258 CreatorCollector creators = new CreatorCollector(beanDesc, ctxt.getConfig()); 259 AnnotationIntrospector intr = ctxt.getAnnotationIntrospector(); 260 261 // need to construct suitable visibility checker: 262 final DeserializationConfig config = ctxt.getConfig(); 263 VisibilityChecker<?> vchecker = config.getDefaultVisibilityChecker(beanDesc.getBeanClass(), 264 beanDesc.getClassInfo()); 265 266 /* 24-Sep-2014, tatu: Tricky part first; need to merge resolved property information 267 * (which has creator parameters sprinkled around) with actual creator 268 * declarations (which are needed to access creator annotation, amongst other things). 269 * Easiest to combine that info first, then pass it to remaining processing. 270 */ 271 /* 15-Mar-2015, tatu: Alas, this won't help with constructors that only have implicit 272 * names. Those will need to be resolved later on. 273 */ 274 Map<AnnotatedWithParams,BeanPropertyDefinition[]> creatorDefs = _findCreatorsFromProperties(ctxt, 275 beanDesc); 276 // Important: first add factory methods; then constructors, so 277 // latter can override former! 278 _addDeserializerFactoryMethods(ctxt, beanDesc, vchecker, intr, creators, creatorDefs); 279 // constructors only usable on concrete types: 280 if (beanDesc.getType().isConcrete()) { 281 _addDeserializerConstructors(ctxt, beanDesc, vchecker, intr, creators, creatorDefs); 282 } 283 return creators.constructValueInstantiator(ctxt); 284 } 285 _findCreatorsFromProperties(DeserializationContext ctxt, BeanDescription beanDesc)286 protected Map<AnnotatedWithParams,BeanPropertyDefinition[]> _findCreatorsFromProperties(DeserializationContext ctxt, 287 BeanDescription beanDesc) throws JsonMappingException 288 { 289 Map<AnnotatedWithParams,BeanPropertyDefinition[]> result = Collections.emptyMap(); 290 for (BeanPropertyDefinition propDef : beanDesc.findProperties()) { 291 Iterator<AnnotatedParameter> it = propDef.getConstructorParameters(); 292 while (it.hasNext()) { 293 AnnotatedParameter param = it.next(); 294 AnnotatedWithParams owner = param.getOwner(); 295 BeanPropertyDefinition[] defs = result.get(owner); 296 final int index = param.getIndex(); 297 298 if (defs == null) { 299 if (result.isEmpty()) { // since emptyMap is immutable need to create a 'real' one 300 result = new LinkedHashMap<AnnotatedWithParams,BeanPropertyDefinition[]>(); 301 } 302 defs = new BeanPropertyDefinition[owner.getParameterCount()]; 303 result.put(owner, defs); 304 } else { 305 if (defs[index] != null) { 306 ctxt.reportBadTypeDefinition(beanDesc, 307 "Conflict: parameter #%d of %s bound to more than one property; %s vs %s", 308 index, owner, defs[index], propDef); 309 } 310 } 311 defs[index] = propDef; 312 } 313 } 314 return result; 315 } 316 _valueInstantiatorInstance(DeserializationConfig config, Annotated annotated, Object instDef)317 public ValueInstantiator _valueInstantiatorInstance(DeserializationConfig config, 318 Annotated annotated, Object instDef) 319 throws JsonMappingException 320 { 321 if (instDef == null) { 322 return null; 323 } 324 325 ValueInstantiator inst; 326 327 if (instDef instanceof ValueInstantiator) { 328 return (ValueInstantiator) instDef; 329 } 330 if (!(instDef instanceof Class)) { 331 throw new IllegalStateException("AnnotationIntrospector returned key deserializer definition of type " 332 +instDef.getClass().getName() 333 +"; expected type KeyDeserializer or Class<KeyDeserializer> instead"); 334 } 335 Class<?> instClass = (Class<?>)instDef; 336 if (ClassUtil.isBogusClass(instClass)) { 337 return null; 338 } 339 if (!ValueInstantiator.class.isAssignableFrom(instClass)) { 340 throw new IllegalStateException("AnnotationIntrospector returned Class "+instClass.getName() 341 +"; expected Class<ValueInstantiator>"); 342 } 343 HandlerInstantiator hi = config.getHandlerInstantiator(); 344 if (hi != null) { 345 inst = hi.valueInstantiatorInstance(config, annotated, instClass); 346 if (inst != null) { 347 return inst; 348 } 349 } 350 return (ValueInstantiator) ClassUtil.createInstance(instClass, 351 config.canOverrideAccessModifiers()); 352 } 353 354 /* 355 /********************************************************** 356 /* Creator introspection 357 /********************************************************** 358 */ 359 _addDeserializerConstructors(DeserializationContext ctxt, BeanDescription beanDesc, VisibilityChecker<?> vchecker, AnnotationIntrospector intr, CreatorCollector creators, Map<AnnotatedWithParams,BeanPropertyDefinition[]> creatorParams)360 protected void _addDeserializerConstructors(DeserializationContext ctxt, 361 BeanDescription beanDesc, VisibilityChecker<?> vchecker, 362 AnnotationIntrospector intr, CreatorCollector creators, 363 Map<AnnotatedWithParams,BeanPropertyDefinition[]> creatorParams) 364 throws JsonMappingException 365 { 366 // 25-Jan-2017, tatu: As per [databind#1501], [databind#1502], [databind#1503], best 367 // for now to skip attempts at using anything but no-args constructor (see 368 // `InnerClassProperty` construction for that) 369 final boolean isNonStaticInnerClass = beanDesc.isNonStaticInnerClass(); 370 if (isNonStaticInnerClass) { 371 // TODO: look for `@JsonCreator` annotated ones, throw explicit exception? 372 return; 373 } 374 375 // First things first: the "default constructor" (zero-arg 376 // constructor; whether implicit or explicit) is NOT included 377 // in list of constructors, so needs to be handled separately. 378 AnnotatedConstructor defaultCtor = beanDesc.findDefaultConstructor(); 379 if (defaultCtor != null) { 380 if (!creators.hasDefaultCreator() || _hasCreatorAnnotation(ctxt, defaultCtor)) { 381 creators.setDefaultCreator(defaultCtor); 382 } 383 } 384 // 21-Sep-2017, tatu: First let's handle explicitly annotated ones 385 List<CreatorCandidate> nonAnnotated = new LinkedList<>(); 386 int explCount = 0; 387 for (AnnotatedConstructor ctor : beanDesc.getConstructors()) { 388 JsonCreator.Mode creatorMode = intr.findCreatorAnnotation(ctxt.getConfig(), ctor); 389 if (Mode.DISABLED == creatorMode) { 390 continue; 391 } 392 if (creatorMode == null) { 393 // let's check Visibility here, to avoid further processing for non-visible? 394 if (vchecker.isCreatorVisible(ctor)) { 395 nonAnnotated.add(CreatorCandidate.construct(intr, ctor, creatorParams.get(ctor))); 396 } 397 continue; 398 } 399 switch (creatorMode) { 400 case DELEGATING: 401 _addExplicitDelegatingCreator(ctxt, beanDesc, creators, 402 CreatorCandidate.construct(intr, ctor, null)); 403 break; 404 case PROPERTIES: 405 _addExplicitPropertyCreator(ctxt, beanDesc, creators, 406 CreatorCandidate.construct(intr, ctor, creatorParams.get(ctor))); 407 break; 408 default: 409 _addExplicitAnyCreator(ctxt, beanDesc, creators, 410 CreatorCandidate.construct(intr, ctor, creatorParams.get(ctor))); 411 break; 412 } 413 ++explCount; 414 } 415 // And only if and when those handled, consider potentially visible ones 416 if (explCount > 0) { // TODO: split method into two since we could have expl factories 417 return; 418 } 419 List<AnnotatedWithParams> implicitCtors = null; 420 for (CreatorCandidate candidate : nonAnnotated) { 421 final int argCount = candidate.paramCount(); 422 final AnnotatedWithParams ctor = candidate.creator(); 423 424 // some single-arg factory methods (String, number) are auto-detected 425 if (argCount == 1) { 426 BeanPropertyDefinition propDef = candidate.propertyDef(0); 427 boolean useProps = _checkIfCreatorPropertyBased(intr, ctor, propDef); 428 429 if (useProps) { 430 SettableBeanProperty[] properties = new SettableBeanProperty[1]; 431 PropertyName name = candidate.paramName(0); 432 properties[0] = constructCreatorProperty(ctxt, beanDesc, name, 0, 433 candidate.parameter(0), candidate.injection(0)); 434 creators.addPropertyCreator(ctor, false, properties); 435 } else { 436 /*boolean added = */ _handleSingleArgumentCreator(creators, 437 ctor, false, 438 vchecker.isCreatorVisible(ctor)); 439 // one more thing: sever link to creator property, to avoid possible later 440 // problems with "unresolved" constructor property 441 if (propDef != null) { 442 ((POJOPropertyBuilder) propDef).removeConstructors(); 443 } 444 } 445 // regardless, fully handled 446 continue; 447 } 448 449 // 2 or more args; all params must have names or be injectable 450 // 14-Mar-2015, tatu (2.6): Or, as per [#725], implicit names will also 451 // do, with some constraints. But that will require bit post processing... 452 453 int nonAnnotatedParamIndex = -1; 454 SettableBeanProperty[] properties = new SettableBeanProperty[argCount]; 455 int explicitNameCount = 0; 456 int implicitWithCreatorCount = 0; 457 int injectCount = 0; 458 459 for (int i = 0; i < argCount; ++i) { 460 final AnnotatedParameter param = ctor.getParameter(i); 461 BeanPropertyDefinition propDef = candidate.propertyDef(i); 462 JacksonInject.Value injectable = intr.findInjectableValue(param); 463 final PropertyName name = (propDef == null) ? null : propDef.getFullName(); 464 465 if (propDef != null && propDef.isExplicitlyNamed()) { 466 ++explicitNameCount; 467 properties[i] = constructCreatorProperty(ctxt, beanDesc, name, i, param, injectable); 468 continue; 469 } 470 if (injectable != null) { 471 ++injectCount; 472 properties[i] = constructCreatorProperty(ctxt, beanDesc, name, i, param, injectable); 473 continue; 474 } 475 NameTransformer unwrapper = intr.findUnwrappingNameTransformer(param); 476 if (unwrapper != null) { 477 _reportUnwrappedCreatorProperty(ctxt, beanDesc, param); 478 /* 479 properties[i] = constructCreatorProperty(ctxt, beanDesc, UNWRAPPED_CREATOR_PARAM_NAME, i, param, null); 480 ++explicitNameCount; 481 */ 482 continue; 483 } 484 // One more thing: implicit names are ok iff ctor has creator annotation 485 /* 486 if (isCreator && (name != null && !name.isEmpty())) { 487 ++implicitWithCreatorCount; 488 properties[i] = constructCreatorProperty(ctxt, beanDesc, name, i, param, injectId); 489 continue; 490 } 491 */ 492 if (nonAnnotatedParamIndex < 0) { 493 nonAnnotatedParamIndex = i; 494 } 495 } 496 497 final int namedCount = explicitNameCount + implicitWithCreatorCount; 498 // Ok: if named or injectable, we have more work to do 499 if ((explicitNameCount > 0) || (injectCount > 0)) { 500 // simple case; everything covered: 501 if ((namedCount + injectCount) == argCount) { 502 creators.addPropertyCreator(ctor, false, properties); 503 continue; 504 } 505 if ((explicitNameCount == 0) && ((injectCount + 1) == argCount)) { 506 // Secondary: all but one injectable, one un-annotated (un-named) 507 creators.addDelegatingCreator(ctor, false, properties, 0); 508 continue; 509 } 510 // otherwise, epic fail? 511 // 16-Mar-2015, tatu: due to [#725], need to be more permissive. For now let's 512 // only report problem if there's no implicit name 513 PropertyName impl = candidate.findImplicitParamName(nonAnnotatedParamIndex); 514 if (impl == null || impl.isEmpty()) { 515 // Let's consider non-static inner class as a special case... 516 // 25-Jan-2017, tatu: Non-static inner classes skipped altogether, now 517 /* 518 if ((nonAnnotatedParamIndex == 0) && isNonStaticInnerClass) { 519 throw new IllegalArgumentException("Non-static inner classes like " 520 +ctor.getDeclaringClass().getName()+" cannot use @JsonCreator for constructors"); 521 } 522 */ 523 ctxt.reportBadTypeDefinition(beanDesc, 524 "Argument #%d of constructor %s has no property name annotation; must have name when multiple-parameter constructor annotated as Creator", 525 nonAnnotatedParamIndex, ctor); 526 } 527 } 528 // [#725]: as a fallback, all-implicit names may work as well 529 if (!creators.hasDefaultCreator()) { 530 if (implicitCtors == null) { 531 implicitCtors = new LinkedList<>(); 532 } 533 implicitCtors.add(ctor); 534 } 535 } 536 // last option, as per [#725]: consider implicit-names-only, visible constructor, 537 // if just one found 538 if ((implicitCtors != null) && !creators.hasDelegatingCreator() 539 && !creators.hasPropertyBasedCreator()) { 540 _checkImplicitlyNamedConstructors(ctxt, beanDesc, vchecker, intr, 541 creators, implicitCtors); 542 } 543 } 544 545 /** 546 * Helper method called when there is the explicit "is-creator" with mode of "delegating" 547 * 548 * @since 2.9.2 549 */ _addExplicitDelegatingCreator(DeserializationContext ctxt, BeanDescription beanDesc, CreatorCollector creators, CreatorCandidate candidate)550 protected void _addExplicitDelegatingCreator(DeserializationContext ctxt, 551 BeanDescription beanDesc, CreatorCollector creators, 552 CreatorCandidate candidate) 553 throws JsonMappingException 554 { 555 // Somewhat simple: find injectable values, if any, ensure there is one 556 // and just one delegated argument; report violations if any 557 558 int ix = -1; 559 final int argCount = candidate.paramCount(); 560 SettableBeanProperty[] properties = new SettableBeanProperty[argCount]; 561 for (int i = 0; i < argCount; ++i) { 562 AnnotatedParameter param = candidate.parameter(i); 563 JacksonInject.Value injectId = candidate.injection(i); 564 if (injectId != null) { 565 properties[i] = constructCreatorProperty(ctxt, beanDesc, null, i, param, injectId); 566 continue; 567 } 568 if (ix < 0) { 569 ix = i; 570 continue; 571 } 572 // Illegal to have more than one value to delegate to 573 ctxt.reportBadTypeDefinition(beanDesc, 574 "More than one argument (#%d and #%d) left as delegating for Creator %s: only one allowed", 575 ix, i, candidate); 576 } 577 // Also, let's require that one Delegating argument does eixt 578 if (ix < 0) { 579 ctxt.reportBadTypeDefinition(beanDesc, 580 "No argument left as delegating for Creator %s: exactly one required", candidate); 581 } 582 // 17-Jan-2018, tatu: as per [databind#1853] need to ensure we will distinguish 583 // "well-known" single-arg variants (String, int/long, boolean) from "generic" delegating... 584 if (argCount == 1) { 585 _handleSingleArgumentCreator(creators, candidate.creator(), true, true); 586 // one more thing: sever link to creator property, to avoid possible later 587 // problems with "unresolved" constructor property 588 BeanPropertyDefinition paramDef = candidate.propertyDef(0); 589 if (paramDef != null) { 590 ((POJOPropertyBuilder) paramDef).removeConstructors(); 591 } 592 return; 593 } 594 creators.addDelegatingCreator(candidate.creator(), true, properties, ix); 595 } 596 597 /** 598 * Helper method called when there is the explicit "is-creator" with mode of "properties-based" 599 * 600 * @since 2.9.2 601 */ _addExplicitPropertyCreator(DeserializationContext ctxt, BeanDescription beanDesc, CreatorCollector creators, CreatorCandidate candidate)602 protected void _addExplicitPropertyCreator(DeserializationContext ctxt, 603 BeanDescription beanDesc, CreatorCollector creators, 604 CreatorCandidate candidate) 605 throws JsonMappingException 606 { 607 final int paramCount = candidate.paramCount(); 608 SettableBeanProperty[] properties = new SettableBeanProperty[paramCount]; 609 610 for (int i = 0; i < paramCount; ++i) { 611 JacksonInject.Value injectId = candidate.injection(i); 612 AnnotatedParameter param = candidate.parameter(i); 613 PropertyName name = candidate.paramName(i); 614 if (name == null) { 615 // 21-Sep-2017, tatu: Looks like we want to block accidental use of Unwrapped, 616 // as that will not work with Creators well at all 617 NameTransformer unwrapper = ctxt.getAnnotationIntrospector().findUnwrappingNameTransformer(param); 618 if (unwrapper != null) { 619 _reportUnwrappedCreatorProperty(ctxt, beanDesc, param); 620 /* 621 properties[i] = constructCreatorProperty(ctxt, beanDesc, UNWRAPPED_CREATOR_PARAM_NAME, i, param, null); 622 ++explicitNameCount; 623 */ 624 } 625 name = candidate.findImplicitParamName(i); 626 // Must be injectable or have name; without either won't work 627 if ((name == null) && (injectId == null)) { 628 ctxt.reportBadTypeDefinition(beanDesc, 629 "Argument #%d has no property name, is not Injectable: can not use as Creator %s", i, candidate); 630 } 631 } 632 properties[i] = constructCreatorProperty(ctxt, beanDesc, name, i, param, injectId); 633 } 634 creators.addPropertyCreator(candidate.creator(), true, properties); 635 } 636 637 /** 638 * Helper method called when there is explicit "is-creator" marker, but no mode declaration. 639 * 640 * @since 2.9.2 641 */ _addExplicitAnyCreator(DeserializationContext ctxt, BeanDescription beanDesc, CreatorCollector creators, CreatorCandidate candidate)642 protected void _addExplicitAnyCreator(DeserializationContext ctxt, 643 BeanDescription beanDesc, CreatorCollector creators, 644 CreatorCandidate candidate) 645 throws JsonMappingException 646 { 647 // Looks like there's bit of magic regarding 1-parameter creators; others simpler: 648 if (1 != candidate.paramCount()) { 649 // Ok: for delegates, we want one and exactly one parameter without 650 // injection AND without name 651 int oneNotInjected = candidate.findOnlyParamWithoutInjection(); 652 if (oneNotInjected >= 0) { 653 // getting close; but most not have name 654 if (candidate.paramName(oneNotInjected) == null) { 655 _addExplicitDelegatingCreator(ctxt, beanDesc, creators, candidate); 656 return; 657 } 658 } 659 _addExplicitPropertyCreator(ctxt, beanDesc, creators, candidate); 660 return; 661 } 662 AnnotatedParameter param = candidate.parameter(0); 663 JacksonInject.Value injectId = candidate.injection(0); 664 PropertyName paramName = candidate.explicitParamName(0); 665 BeanPropertyDefinition paramDef = candidate.propertyDef(0); 666 667 // If there's injection or explicit name, should be properties-based 668 boolean useProps = (paramName != null) || (injectId != null); 669 if (!useProps && (paramDef != null)) { 670 // One more thing: if implicit name matches property with a getter 671 // or field, we'll consider it property-based as well 672 673 // 25-May-2018, tatu: as per [databind#2051], looks like we have to get 674 // not implicit name, but name with possible strategy-based-rename 675 // paramName = candidate.findImplicitParamName(0); 676 paramName = candidate.paramName(0); 677 useProps = (paramName != null) && paramDef.couldSerialize(); 678 } 679 if (useProps) { 680 SettableBeanProperty[] properties = new SettableBeanProperty[] { 681 constructCreatorProperty(ctxt, beanDesc, paramName, 0, param, injectId) 682 }; 683 creators.addPropertyCreator(candidate.creator(), true, properties); 684 return; 685 } 686 _handleSingleArgumentCreator(creators, candidate.creator(), true, true); 687 688 // one more thing: sever link to creator property, to avoid possible later 689 // problems with "unresolved" constructor property 690 if (paramDef != null) { 691 ((POJOPropertyBuilder) paramDef).removeConstructors(); 692 } 693 } 694 _checkIfCreatorPropertyBased(AnnotationIntrospector intr, AnnotatedWithParams creator, BeanPropertyDefinition propDef)695 private boolean _checkIfCreatorPropertyBased(AnnotationIntrospector intr, 696 AnnotatedWithParams creator, BeanPropertyDefinition propDef) 697 { 698 // If explicit name, or inject id, property-based 699 if (((propDef != null) && propDef.isExplicitlyNamed()) 700 || (intr.findInjectableValue(creator.getParameter(0)) != null)) { 701 return true; 702 } 703 if (propDef != null) { 704 // One more thing: if implicit name matches property with a getter 705 // or field, we'll consider it property-based as well 706 String implName = propDef.getName(); 707 if (implName != null && !implName.isEmpty()) { 708 if (propDef.couldSerialize()) { 709 return true; 710 } 711 } 712 } 713 // in absence of everything else, default to delegating 714 return false; 715 } 716 _checkImplicitlyNamedConstructors(DeserializationContext ctxt, BeanDescription beanDesc, VisibilityChecker<?> vchecker, AnnotationIntrospector intr, CreatorCollector creators, List<AnnotatedWithParams> implicitCtors)717 private void _checkImplicitlyNamedConstructors(DeserializationContext ctxt, 718 BeanDescription beanDesc, VisibilityChecker<?> vchecker, 719 AnnotationIntrospector intr, CreatorCollector creators, 720 List<AnnotatedWithParams> implicitCtors) throws JsonMappingException 721 { 722 AnnotatedWithParams found = null; 723 SettableBeanProperty[] foundProps = null; 724 725 // Further checks: (a) must have names for all parameters, (b) only one visible 726 // Also, since earlier matching of properties and creators relied on existence of 727 // `@JsonCreator` (or equivalent) annotation, we need to do bit more re-inspection... 728 729 main_loop: 730 for (AnnotatedWithParams ctor : implicitCtors) { 731 if (!vchecker.isCreatorVisible(ctor)) { 732 continue; 733 } 734 // as per earlier notes, only end up here if no properties associated with creator 735 final int argCount = ctor.getParameterCount(); 736 SettableBeanProperty[] properties = new SettableBeanProperty[argCount]; 737 for (int i = 0; i < argCount; ++i) { 738 final AnnotatedParameter param = ctor.getParameter(i); 739 final PropertyName name = _findParamName(param, intr); 740 741 // must have name (implicit fine) 742 if (name == null || name.isEmpty()) { 743 continue main_loop; 744 } 745 properties[i] = constructCreatorProperty(ctxt, beanDesc, name, param.getIndex(), 746 param, /*injectId*/ null); 747 } 748 if (found != null) { // only one allowed; but multiple not an error 749 found = null; 750 break; 751 } 752 found = ctor; 753 foundProps = properties; 754 } 755 // found one and only one visible? Ship it! 756 if (found != null) { 757 creators.addPropertyCreator(found, /*isCreator*/ false, foundProps); 758 BasicBeanDescription bbd = (BasicBeanDescription) beanDesc; 759 // Also: add properties, to keep error messages complete wrt known properties... 760 for (SettableBeanProperty prop : foundProps) { 761 PropertyName pn = prop.getFullName(); 762 if (!bbd.hasProperty(pn)) { 763 BeanPropertyDefinition newDef = SimpleBeanPropertyDefinition.construct( 764 ctxt.getConfig(), prop.getMember(), pn); 765 bbd.addProperty(newDef); 766 } 767 } 768 } 769 } 770 _addDeserializerFactoryMethods(DeserializationContext ctxt, BeanDescription beanDesc, VisibilityChecker<?> vchecker, AnnotationIntrospector intr, CreatorCollector creators, Map<AnnotatedWithParams,BeanPropertyDefinition[]> creatorParams)771 protected void _addDeserializerFactoryMethods 772 (DeserializationContext ctxt, BeanDescription beanDesc, VisibilityChecker<?> vchecker, 773 AnnotationIntrospector intr, CreatorCollector creators, 774 Map<AnnotatedWithParams,BeanPropertyDefinition[]> creatorParams) 775 throws JsonMappingException 776 { 777 List<CreatorCandidate> nonAnnotated = new LinkedList<>(); 778 int explCount = 0; 779 780 // 21-Sep-2017, tatu: First let's handle explicitly annotated ones 781 for (AnnotatedMethod factory : beanDesc.getFactoryMethods()) { 782 JsonCreator.Mode creatorMode = intr.findCreatorAnnotation(ctxt.getConfig(), factory); 783 final int argCount = factory.getParameterCount(); 784 if (creatorMode == null) { 785 // Only potentially accept 1-argument factory methods 786 if ((argCount == 1) && vchecker.isCreatorVisible(factory)) { 787 nonAnnotated.add(CreatorCandidate.construct(intr, factory, null)); 788 } 789 continue; 790 } 791 if (creatorMode == Mode.DISABLED) { 792 continue; 793 } 794 795 // zero-arg method factory methods fine, as long as explicit 796 if (argCount == 0) { 797 creators.setDefaultCreator(factory); 798 continue; 799 } 800 801 switch (creatorMode) { 802 case DELEGATING: 803 _addExplicitDelegatingCreator(ctxt, beanDesc, creators, 804 CreatorCandidate.construct(intr, factory, null)); 805 break; 806 case PROPERTIES: 807 _addExplicitPropertyCreator(ctxt, beanDesc, creators, 808 CreatorCandidate.construct(intr, factory, creatorParams.get(factory))); 809 break; 810 case DEFAULT: 811 default: 812 _addExplicitAnyCreator(ctxt, beanDesc, creators, 813 CreatorCandidate.construct(intr, factory, creatorParams.get(factory))); 814 break; 815 } 816 ++explCount; 817 } 818 // And only if and when those handled, consider potentially visible ones 819 if (explCount > 0) { // TODO: split method into two since we could have expl factories 820 return; 821 } 822 // And then implicitly found 823 for (CreatorCandidate candidate : nonAnnotated) { 824 final int argCount = candidate.paramCount(); 825 AnnotatedWithParams factory = candidate.creator(); 826 final BeanPropertyDefinition[] propDefs = creatorParams.get(factory); 827 // some single-arg factory methods (String, number) are auto-detected 828 if (argCount != 1) { 829 continue; // 2 and more args? Must be explicit, handled earlier 830 } 831 BeanPropertyDefinition argDef = candidate.propertyDef(0); 832 boolean useProps = _checkIfCreatorPropertyBased(intr, factory, argDef); 833 if (!useProps) { // not property based but delegating 834 /*boolean added=*/ _handleSingleArgumentCreator(creators, 835 factory, false, vchecker.isCreatorVisible(factory)); 836 // 23-Sep-2016, tatu: [databind#1383]: Need to also sever link to avoid possible 837 // later problems with "unresolved" constructor property 838 if (argDef != null) { 839 ((POJOPropertyBuilder) argDef).removeConstructors(); 840 } 841 continue; 842 } 843 AnnotatedParameter nonAnnotatedParam = null; 844 SettableBeanProperty[] properties = new SettableBeanProperty[argCount]; 845 int implicitNameCount = 0; 846 int explicitNameCount = 0; 847 int injectCount = 0; 848 849 for (int i = 0; i < argCount; ++i) { 850 final AnnotatedParameter param = factory.getParameter(i); 851 BeanPropertyDefinition propDef = (propDefs == null) ? null : propDefs[i]; 852 JacksonInject.Value injectable = intr.findInjectableValue(param); 853 final PropertyName name = (propDef == null) ? null : propDef.getFullName(); 854 855 if (propDef != null && propDef.isExplicitlyNamed()) { 856 ++explicitNameCount; 857 properties[i] = constructCreatorProperty(ctxt, beanDesc, name, i, param, injectable); 858 continue; 859 } 860 if (injectable != null) { 861 ++injectCount; 862 properties[i] = constructCreatorProperty(ctxt, beanDesc, name, i, param, injectable); 863 continue; 864 } 865 NameTransformer unwrapper = intr.findUnwrappingNameTransformer(param); 866 if (unwrapper != null) { 867 _reportUnwrappedCreatorProperty(ctxt, beanDesc, param); 868 /* 869 properties[i] = constructCreatorProperty(ctxt, beanDesc, UNWRAPPED_CREATOR_PARAM_NAME, i, param, null); 870 ++implicitNameCount; 871 */ 872 continue; 873 } 874 // One more thing: implicit names are ok iff ctor has creator annotation 875 /* 876 if (isCreator) { 877 if (name != null && !name.isEmpty()) { 878 ++implicitNameCount; 879 properties[i] = constructCreatorProperty(ctxt, beanDesc, name, i, param, injectable); 880 continue; 881 } 882 } 883 */ 884 /* 25-Sep-2014, tatu: Actually, we may end up "losing" naming due to higher-priority constructor 885 * (see TestCreators#testConstructorCreator() test). And just to avoid running into that problem, 886 * let's add one more work around 887 */ 888 /* 889 PropertyName name2 = _findExplicitParamName(param, intr); 890 if (name2 != null && !name2.isEmpty()) { 891 // Hmmh. Ok, fine. So what are we to do with it... ? 892 // For now... skip. May need to revisit this, should this become problematic 893 continue main_loop; 894 } 895 */ 896 if (nonAnnotatedParam == null) { 897 nonAnnotatedParam = param; 898 } 899 } 900 final int namedCount = explicitNameCount + implicitNameCount; 901 902 // Ok: if named or injectable, we have more work to do 903 if (explicitNameCount > 0 || injectCount > 0) { 904 // simple case; everything covered: 905 if ((namedCount + injectCount) == argCount) { 906 creators.addPropertyCreator(factory, false, properties); 907 } else if ((explicitNameCount == 0) && ((injectCount + 1) == argCount)) { 908 // secondary: all but one injectable, one un-annotated (un-named) 909 creators.addDelegatingCreator(factory, false, properties, 0); 910 } else { // otherwise, epic fail 911 ctxt.reportBadTypeDefinition(beanDesc, 912 "Argument #%d of factory method %s has no property name annotation; must have name when multiple-parameter constructor annotated as Creator", 913 nonAnnotatedParam.getIndex(), factory); 914 } 915 } 916 } 917 } 918 _handleSingleArgumentCreator(CreatorCollector creators, AnnotatedWithParams ctor, boolean isCreator, boolean isVisible)919 protected boolean _handleSingleArgumentCreator(CreatorCollector creators, 920 AnnotatedWithParams ctor, boolean isCreator, boolean isVisible) 921 { 922 // otherwise either 'simple' number, String, or general delegate: 923 Class<?> type = ctor.getRawParameterType(0); 924 if (type == String.class || type == CLASS_CHAR_SEQUENCE) { 925 if (isCreator || isVisible) { 926 creators.addStringCreator(ctor, isCreator); 927 } 928 return true; 929 } 930 if (type == int.class || type == Integer.class) { 931 if (isCreator || isVisible) { 932 creators.addIntCreator(ctor, isCreator); 933 } 934 return true; 935 } 936 if (type == long.class || type == Long.class) { 937 if (isCreator || isVisible) { 938 creators.addLongCreator(ctor, isCreator); 939 } 940 return true; 941 } 942 if (type == double.class || type == Double.class) { 943 if (isCreator || isVisible) { 944 creators.addDoubleCreator(ctor, isCreator); 945 } 946 return true; 947 } 948 if (type == boolean.class || type == Boolean.class) { 949 if (isCreator || isVisible) { 950 creators.addBooleanCreator(ctor, isCreator); 951 } 952 return true; 953 } 954 if (type == BigInteger.class) { 955 if (isCreator || isVisible) { 956 creators.addBigIntegerCreator(ctor, isCreator); 957 } 958 } 959 if (type == BigDecimal.class) { 960 if (isCreator || isVisible) { 961 creators.addBigDecimalCreator(ctor, isCreator); 962 } 963 } 964 // Delegating Creator ok iff it has @JsonCreator (etc) 965 if (isCreator) { 966 creators.addDelegatingCreator(ctor, isCreator, null, 0); 967 return true; 968 } 969 return false; 970 } 971 972 // 01-Dec-2016, tatu: As per [databind#265] we cannot yet support passing 973 // of unwrapped values through creator properties, so fail fast _reportUnwrappedCreatorProperty(DeserializationContext ctxt, BeanDescription beanDesc, AnnotatedParameter param)974 protected void _reportUnwrappedCreatorProperty(DeserializationContext ctxt, 975 BeanDescription beanDesc, AnnotatedParameter param) 976 throws JsonMappingException 977 { 978 ctxt.reportBadDefinition(beanDesc.getType(), String.format( 979 "Cannot define Creator parameter %d as `@JsonUnwrapped`: combination not yet supported", 980 param.getIndex())); 981 } 982 983 /** 984 * Method that will construct a property object that represents 985 * a logical property passed via Creator (constructor or static 986 * factory method) 987 */ constructCreatorProperty(DeserializationContext ctxt, BeanDescription beanDesc, PropertyName name, int index, AnnotatedParameter param, JacksonInject.Value injectable)988 protected SettableBeanProperty constructCreatorProperty(DeserializationContext ctxt, 989 BeanDescription beanDesc, PropertyName name, int index, 990 AnnotatedParameter param, 991 JacksonInject.Value injectable) 992 throws JsonMappingException 993 { 994 final DeserializationConfig config = ctxt.getConfig(); 995 final AnnotationIntrospector intr = ctxt.getAnnotationIntrospector(); 996 PropertyMetadata metadata; 997 { 998 if (intr == null) { 999 metadata = PropertyMetadata.STD_REQUIRED_OR_OPTIONAL; 1000 } else { 1001 Boolean b = intr.hasRequiredMarker(param); 1002 String desc = intr.findPropertyDescription(param); 1003 Integer idx = intr.findPropertyIndex(param); 1004 String def = intr.findPropertyDefaultValue(param); 1005 metadata = PropertyMetadata.construct(b, desc, idx, def); 1006 } 1007 } 1008 JavaType type = resolveMemberAndTypeAnnotations(ctxt, param, param.getType()); 1009 BeanProperty.Std property = new BeanProperty.Std(name, type, 1010 intr.findWrapperName(param), param, metadata); 1011 // Type deserializer: either comes from property (and already resolved) 1012 TypeDeserializer typeDeser = (TypeDeserializer) type.getTypeHandler(); 1013 // or if not, based on type being referenced: 1014 if (typeDeser == null) { 1015 typeDeser = findTypeDeserializer(config, type); 1016 } 1017 1018 // 22-Sep-2019, tatu: for [databind#2458] need more work on getting metadata 1019 // about SetterInfo, mergeability 1020 metadata = _getSetterInfo(ctxt, property, metadata); 1021 1022 // Note: contextualization of typeDeser _should_ occur in constructor of CreatorProperty 1023 // so it is not called directly here 1024 SettableBeanProperty prop = CreatorProperty.construct(name, type, property.getWrapperName(), 1025 typeDeser, beanDesc.getClassAnnotations(), param, index, injectable, 1026 metadata); 1027 JsonDeserializer<?> deser = findDeserializerFromAnnotation(ctxt, param); 1028 if (deser == null) { 1029 deser = type.getValueHandler(); 1030 } 1031 if (deser != null) { 1032 // As per [databind#462] need to ensure we contextualize deserializer before passing it on 1033 deser = ctxt.handlePrimaryContextualization(deser, prop, type); 1034 prop = prop.withValueDeserializer(deser); 1035 } 1036 return prop; 1037 } 1038 _findParamName(AnnotatedParameter param, AnnotationIntrospector intr)1039 private PropertyName _findParamName(AnnotatedParameter param, AnnotationIntrospector intr) 1040 { 1041 if (param != null && intr != null) { 1042 PropertyName name = intr.findNameForDeserialization(param); 1043 if (name != null) { 1044 return name; 1045 } 1046 // 14-Apr-2014, tatu: Need to also consider possible implicit name 1047 // (for JDK8, or via paranamer) 1048 1049 String str = intr.findImplicitPropertyName(param); 1050 if (str != null && !str.isEmpty()) { 1051 return PropertyName.construct(str); 1052 } 1053 } 1054 return null; 1055 } 1056 1057 /** 1058 * Helper method copied from {@code POJOPropertyBuilder} since that won't be 1059 * applied to creator parameters 1060 * 1061 * @since 2.10 1062 */ _getSetterInfo(DeserializationContext ctxt, BeanProperty prop, PropertyMetadata metadata)1063 protected PropertyMetadata _getSetterInfo(DeserializationContext ctxt, 1064 BeanProperty prop, PropertyMetadata metadata) 1065 { 1066 final AnnotationIntrospector intr = ctxt.getAnnotationIntrospector(); 1067 final DeserializationConfig config = ctxt.getConfig(); 1068 1069 boolean needMerge = true; 1070 Nulls valueNulls = null; 1071 Nulls contentNulls = null; 1072 1073 // NOTE: compared to `POJOPropertyBuilder`, we only have access to creator 1074 // parameter, not other accessors, so code bit simpler 1075 AnnotatedMember prim = prop.getMember(); 1076 1077 if (prim != null) { 1078 // Ok, first: does property itself have something to say? 1079 if (intr != null) { 1080 JsonSetter.Value setterInfo = intr.findSetterInfo(prim); 1081 if (setterInfo != null) { 1082 valueNulls = setterInfo.nonDefaultValueNulls(); 1083 contentNulls = setterInfo.nonDefaultContentNulls(); 1084 } 1085 } 1086 // If not, config override? 1087 // 25-Oct-2016, tatu: Either this, or type of accessor... 1088 if (needMerge || (valueNulls == null) || (contentNulls == null)) { 1089 ConfigOverride co = config.getConfigOverride(prop.getType().getRawClass()); 1090 JsonSetter.Value setterInfo = co.getSetterInfo(); 1091 if (setterInfo != null) { 1092 if (valueNulls == null) { 1093 valueNulls = setterInfo.nonDefaultValueNulls(); 1094 } 1095 if (contentNulls == null) { 1096 contentNulls = setterInfo.nonDefaultContentNulls(); 1097 } 1098 } 1099 } 1100 } 1101 if (needMerge || (valueNulls == null) || (contentNulls == null)) { 1102 JsonSetter.Value setterInfo = config.getDefaultSetterInfo(); 1103 if (valueNulls == null) { 1104 valueNulls = setterInfo.nonDefaultValueNulls(); 1105 } 1106 if (contentNulls == null) { 1107 contentNulls = setterInfo.nonDefaultContentNulls(); 1108 } 1109 } 1110 if ((valueNulls != null) || (contentNulls != null)) { 1111 metadata = metadata.withNulls(valueNulls, contentNulls); 1112 } 1113 return metadata; 1114 } 1115 1116 /* 1117 /********************************************************** 1118 /* DeserializerFactory impl: array deserializers 1119 /********************************************************** 1120 */ 1121 1122 @Override createArrayDeserializer(DeserializationContext ctxt, ArrayType type, final BeanDescription beanDesc)1123 public JsonDeserializer<?> createArrayDeserializer(DeserializationContext ctxt, 1124 ArrayType type, final BeanDescription beanDesc) 1125 throws JsonMappingException 1126 { 1127 final DeserializationConfig config = ctxt.getConfig(); 1128 JavaType elemType = type.getContentType(); 1129 1130 // Very first thing: is deserializer hard-coded for elements? 1131 JsonDeserializer<Object> contentDeser = elemType.getValueHandler(); 1132 // Then optional type info: if type has been resolved, we may already know type deserializer: 1133 TypeDeserializer elemTypeDeser = elemType.getTypeHandler(); 1134 // but if not, may still be possible to find: 1135 if (elemTypeDeser == null) { 1136 elemTypeDeser = findTypeDeserializer(config, elemType); 1137 } 1138 // 23-Nov-2010, tatu: Custom array deserializer? 1139 JsonDeserializer<?> deser = _findCustomArrayDeserializer(type, 1140 config, beanDesc, elemTypeDeser, contentDeser); 1141 if (deser == null) { 1142 if (contentDeser == null) { 1143 Class<?> raw = elemType.getRawClass(); 1144 if (elemType.isPrimitive()) { 1145 return PrimitiveArrayDeserializers.forType(raw); 1146 } 1147 if (raw == String.class) { 1148 return StringArrayDeserializer.instance; 1149 } 1150 } 1151 deser = new ObjectArrayDeserializer(type, contentDeser, elemTypeDeser); 1152 } 1153 // and then new with 2.2: ability to post-process it too (databind#120) 1154 if (_factoryConfig.hasDeserializerModifiers()) { 1155 for (BeanDeserializerModifier mod : _factoryConfig.deserializerModifiers()) { 1156 deser = mod.modifyArrayDeserializer(config, type, beanDesc, deser); 1157 } 1158 } 1159 return deser; 1160 } 1161 1162 /* 1163 /********************************************************************** 1164 /* DeserializerFactory impl: Collection(-like) deserializers 1165 /********************************************************************** 1166 */ 1167 1168 @Override createCollectionDeserializer(DeserializationContext ctxt, CollectionType type, BeanDescription beanDesc)1169 public JsonDeserializer<?> createCollectionDeserializer(DeserializationContext ctxt, 1170 CollectionType type, BeanDescription beanDesc) 1171 throws JsonMappingException 1172 { 1173 JavaType contentType = type.getContentType(); 1174 // Very first thing: is deserializer hard-coded for elements? 1175 JsonDeserializer<Object> contentDeser = contentType.getValueHandler(); 1176 final DeserializationConfig config = ctxt.getConfig(); 1177 1178 // Then optional type info: if type has been resolved, we may already know type deserializer: 1179 TypeDeserializer contentTypeDeser = contentType.getTypeHandler(); 1180 // but if not, may still be possible to find: 1181 if (contentTypeDeser == null) { 1182 contentTypeDeser = findTypeDeserializer(config, contentType); 1183 } 1184 // 23-Nov-2010, tatu: Custom deserializer? 1185 JsonDeserializer<?> deser = _findCustomCollectionDeserializer(type, 1186 config, beanDesc, contentTypeDeser, contentDeser); 1187 if (deser == null) { 1188 Class<?> collectionClass = type.getRawClass(); 1189 if (contentDeser == null) { // not defined by annotation 1190 // One special type: EnumSet: 1191 if (EnumSet.class.isAssignableFrom(collectionClass)) { 1192 deser = new EnumSetDeserializer(contentType, null); 1193 } 1194 } 1195 } 1196 1197 /* One twist: if we are being asked to instantiate an interface or 1198 * abstract Collection, we need to either find something that implements 1199 * the thing, or give up. 1200 * 1201 * Note that we do NOT try to guess based on secondary interfaces 1202 * here; that would probably not work correctly since casts would 1203 * fail later on (as the primary type is not the interface we'd 1204 * be implementing) 1205 */ 1206 if (deser == null) { 1207 if (type.isInterface() || type.isAbstract()) { 1208 CollectionType implType = _mapAbstractCollectionType(type, config); 1209 if (implType == null) { 1210 // [databind#292]: Actually, may be fine, but only if polymorphich deser enabled 1211 if (type.getTypeHandler() == null) { 1212 throw new IllegalArgumentException("Cannot find a deserializer for non-concrete Collection type "+type); 1213 } 1214 deser = AbstractDeserializer.constructForNonPOJO(beanDesc); 1215 } else { 1216 type = implType; 1217 // But if so, also need to re-check creators... 1218 beanDesc = config.introspectForCreation(type); 1219 } 1220 } 1221 if (deser == null) { 1222 ValueInstantiator inst = findValueInstantiator(ctxt, beanDesc); 1223 if (!inst.canCreateUsingDefault()) { 1224 // [databind#161]: No default constructor for ArrayBlockingQueue... 1225 if (type.hasRawClass(ArrayBlockingQueue.class)) { 1226 return new ArrayBlockingQueueDeserializer(type, contentDeser, contentTypeDeser, inst); 1227 } 1228 // 10-Jan-2017, tatu: `java.util.Collections` types need help: 1229 deser = JavaUtilCollectionsDeserializers.findForCollection(ctxt, type); 1230 if (deser != null) { 1231 return deser; 1232 } 1233 } 1234 // Can use more optimal deserializer if content type is String, so: 1235 if (contentType.hasRawClass(String.class)) { 1236 // no value type deserializer because Strings are one of natural/native types: 1237 deser = new StringCollectionDeserializer(type, contentDeser, inst); 1238 } else { 1239 deser = new CollectionDeserializer(type, contentDeser, contentTypeDeser, inst); 1240 } 1241 } 1242 } 1243 // allow post-processing it too 1244 if (_factoryConfig.hasDeserializerModifiers()) { 1245 for (BeanDeserializerModifier mod : _factoryConfig.deserializerModifiers()) { 1246 deser = mod.modifyCollectionDeserializer(config, type, beanDesc, deser); 1247 } 1248 } 1249 return deser; 1250 } 1251 _mapAbstractCollectionType(JavaType type, DeserializationConfig config)1252 protected CollectionType _mapAbstractCollectionType(JavaType type, DeserializationConfig config) 1253 { 1254 final Class<?> collectionClass = ContainerDefaultMappings.findCollectionFallback(type); 1255 if (collectionClass != null) { 1256 return (CollectionType) config.getTypeFactory() 1257 .constructSpecializedType(type, collectionClass, true); 1258 } 1259 return null; 1260 } 1261 1262 // Copied almost verbatim from "createCollectionDeserializer" -- should try to share more code 1263 @Override createCollectionLikeDeserializer(DeserializationContext ctxt, CollectionLikeType type, final BeanDescription beanDesc)1264 public JsonDeserializer<?> createCollectionLikeDeserializer(DeserializationContext ctxt, 1265 CollectionLikeType type, final BeanDescription beanDesc) 1266 throws JsonMappingException 1267 { 1268 JavaType contentType = type.getContentType(); 1269 // Very first thing: is deserializer hard-coded for elements? 1270 JsonDeserializer<Object> contentDeser = contentType.getValueHandler(); 1271 final DeserializationConfig config = ctxt.getConfig(); 1272 1273 // Then optional type info (1.5): if type has been resolved, we may already know type deserializer: 1274 TypeDeserializer contentTypeDeser = contentType.getTypeHandler(); 1275 // but if not, may still be possible to find: 1276 if (contentTypeDeser == null) { 1277 contentTypeDeser = findTypeDeserializer(config, contentType); 1278 } 1279 JsonDeserializer<?> deser = _findCustomCollectionLikeDeserializer(type, config, beanDesc, 1280 contentTypeDeser, contentDeser); 1281 if (deser != null) { 1282 // and then new with 2.2: ability to post-process it too (Issue#120) 1283 if (_factoryConfig.hasDeserializerModifiers()) { 1284 for (BeanDeserializerModifier mod : _factoryConfig.deserializerModifiers()) { 1285 deser = mod.modifyCollectionLikeDeserializer(config, type, beanDesc, deser); 1286 } 1287 } 1288 } 1289 return deser; 1290 } 1291 1292 /* 1293 /********************************************************** 1294 /* DeserializerFactory impl: Map(-like) deserializers 1295 /********************************************************** 1296 */ 1297 1298 @Override createMapDeserializer(DeserializationContext ctxt, MapType type, BeanDescription beanDesc)1299 public JsonDeserializer<?> createMapDeserializer(DeserializationContext ctxt, 1300 MapType type, BeanDescription beanDesc) 1301 throws JsonMappingException 1302 { 1303 final DeserializationConfig config = ctxt.getConfig(); 1304 JavaType keyType = type.getKeyType(); 1305 JavaType contentType = type.getContentType(); 1306 1307 // First: is there annotation-specified deserializer for values? 1308 @SuppressWarnings("unchecked") 1309 JsonDeserializer<Object> contentDeser = (JsonDeserializer<Object>) contentType.getValueHandler(); 1310 1311 // Ok: need a key deserializer (null indicates 'default' here) 1312 KeyDeserializer keyDes = (KeyDeserializer) keyType.getValueHandler(); 1313 // Then optional type info; either attached to type, or resolved separately: 1314 TypeDeserializer contentTypeDeser = contentType.getTypeHandler(); 1315 // but if not, may still be possible to find: 1316 if (contentTypeDeser == null) { 1317 contentTypeDeser = findTypeDeserializer(config, contentType); 1318 } 1319 1320 // 23-Nov-2010, tatu: Custom deserializer? 1321 JsonDeserializer<?> deser = _findCustomMapDeserializer(type, config, beanDesc, 1322 keyDes, contentTypeDeser, contentDeser); 1323 1324 if (deser == null) { 1325 // Value handling is identical for all, but EnumMap requires special handling for keys 1326 Class<?> mapClass = type.getRawClass(); 1327 if (EnumMap.class.isAssignableFrom(mapClass)) { 1328 ValueInstantiator inst; 1329 1330 // 06-Mar-2017, tatu: Should only need to check ValueInstantiator for 1331 // custom sub-classes, see [databind#1544] 1332 if (mapClass == EnumMap.class) { 1333 inst = null; 1334 } else { 1335 inst = findValueInstantiator(ctxt, beanDesc); 1336 } 1337 if (!keyType.isEnumImplType()) { 1338 throw new IllegalArgumentException("Cannot construct EnumMap; generic (key) type not available"); 1339 } 1340 deser = new EnumMapDeserializer(type, inst, null, 1341 contentDeser, contentTypeDeser, null); 1342 } 1343 1344 // Otherwise, generic handler works ok. 1345 1346 /* But there is one more twist: if we are being asked to instantiate 1347 * an interface or abstract Map, we need to either find something 1348 * that implements the thing, or give up. 1349 * 1350 * Note that we do NOT try to guess based on secondary interfaces 1351 * here; that would probably not work correctly since casts would 1352 * fail later on (as the primary type is not the interface we'd 1353 * be implementing) 1354 */ 1355 if (deser == null) { 1356 if (type.isInterface() || type.isAbstract()) { 1357 MapType fallback = _mapAbstractMapType(type, config); 1358 if (fallback != null) { 1359 type = (MapType) fallback; 1360 mapClass = type.getRawClass(); 1361 // But if so, also need to re-check creators... 1362 beanDesc = config.introspectForCreation(type); 1363 } else { 1364 // [databind#292]: Actually, may be fine, but only if polymorphic deser enabled 1365 if (type.getTypeHandler() == null) { 1366 throw new IllegalArgumentException("Cannot find a deserializer for non-concrete Map type "+type); 1367 } 1368 deser = AbstractDeserializer.constructForNonPOJO(beanDesc); 1369 } 1370 } else { 1371 // 10-Jan-2017, tatu: `java.util.Collections` types need help: 1372 deser = JavaUtilCollectionsDeserializers.findForMap(ctxt, type); 1373 if (deser != null) { 1374 return deser; 1375 } 1376 } 1377 if (deser == null) { 1378 ValueInstantiator inst = findValueInstantiator(ctxt, beanDesc); 1379 // 01-May-2016, tatu: Which base type to use here gets tricky, since 1380 // most often it ought to be `Map` or `EnumMap`, but due to abstract 1381 // mapping it will more likely be concrete type like `HashMap`. 1382 // So, for time being, just pass `Map.class` 1383 MapDeserializer md = new MapDeserializer(type, inst, keyDes, contentDeser, contentTypeDeser); 1384 JsonIgnoreProperties.Value ignorals = config.getDefaultPropertyIgnorals(Map.class, 1385 beanDesc.getClassInfo()); 1386 Set<String> ignored = (ignorals == null) ? null 1387 : ignorals.findIgnoredForDeserialization(); 1388 md.setIgnorableProperties(ignored); 1389 JsonIncludeProperties.Value inclusions = config.getDefaultPropertyInclusions(Map.class, 1390 beanDesc.getClassInfo()); 1391 Set<String> included = inclusions == null ? null : inclusions.getIncluded(); 1392 md.setIncludableProperties(included); 1393 deser = md; 1394 } 1395 } 1396 } 1397 if (_factoryConfig.hasDeserializerModifiers()) { 1398 for (BeanDeserializerModifier mod : _factoryConfig.deserializerModifiers()) { 1399 deser = mod.modifyMapDeserializer(config, type, beanDesc, deser); 1400 } 1401 } 1402 return deser; 1403 } 1404 _mapAbstractMapType(JavaType type, DeserializationConfig config)1405 protected MapType _mapAbstractMapType(JavaType type, DeserializationConfig config) 1406 { 1407 final Class<?> mapClass = ContainerDefaultMappings.findMapFallback(type); 1408 if (mapClass != null) { 1409 return (MapType) config.getTypeFactory() 1410 .constructSpecializedType(type, mapClass, true); 1411 } 1412 return null; 1413 } 1414 1415 // Copied almost verbatim from "createMapDeserializer" -- should try to share more code 1416 @Override createMapLikeDeserializer(DeserializationContext ctxt, MapLikeType type, final BeanDescription beanDesc)1417 public JsonDeserializer<?> createMapLikeDeserializer(DeserializationContext ctxt, 1418 MapLikeType type, final BeanDescription beanDesc) 1419 throws JsonMappingException 1420 { 1421 JavaType keyType = type.getKeyType(); 1422 JavaType contentType = type.getContentType(); 1423 final DeserializationConfig config = ctxt.getConfig(); 1424 1425 // First: is there annotation-specified deserializer for values? 1426 @SuppressWarnings("unchecked") 1427 JsonDeserializer<Object> contentDeser = (JsonDeserializer<Object>) contentType.getValueHandler(); 1428 1429 // Ok: need a key deserializer (null indicates 'default' here) 1430 KeyDeserializer keyDes = (KeyDeserializer) keyType.getValueHandler(); 1431 /* !!! 24-Jan-2012, tatu: NOTE: impls MUST use resolve() to find key deserializer! 1432 if (keyDes == null) { 1433 keyDes = p.findKeyDeserializer(config, keyType, property); 1434 } 1435 */ 1436 // Then optional type info (1.5); either attached to type, or resolve separately: 1437 TypeDeserializer contentTypeDeser = contentType.getTypeHandler(); 1438 // but if not, may still be possible to find: 1439 if (contentTypeDeser == null) { 1440 contentTypeDeser = findTypeDeserializer(config, contentType); 1441 } 1442 JsonDeserializer<?> deser = _findCustomMapLikeDeserializer(type, config, 1443 beanDesc, keyDes, contentTypeDeser, contentDeser); 1444 if (deser != null) { 1445 // and then new with 2.2: ability to post-process it too (Issue#120) 1446 if (_factoryConfig.hasDeserializerModifiers()) { 1447 for (BeanDeserializerModifier mod : _factoryConfig.deserializerModifiers()) { 1448 deser = mod.modifyMapLikeDeserializer(config, type, beanDesc, deser); 1449 } 1450 } 1451 } 1452 return deser; 1453 } 1454 1455 /* 1456 /********************************************************** 1457 /* DeserializerFactory impl: other types 1458 /********************************************************** 1459 */ 1460 1461 /** 1462 * Factory method for constructing serializers of {@link Enum} types. 1463 */ 1464 @Override createEnumDeserializer(DeserializationContext ctxt, JavaType type, BeanDescription beanDesc)1465 public JsonDeserializer<?> createEnumDeserializer(DeserializationContext ctxt, 1466 JavaType type, BeanDescription beanDesc) 1467 throws JsonMappingException 1468 { 1469 final DeserializationConfig config = ctxt.getConfig(); 1470 final Class<?> enumClass = type.getRawClass(); 1471 // 23-Nov-2010, tatu: Custom deserializer? 1472 JsonDeserializer<?> deser = _findCustomEnumDeserializer(enumClass, config, beanDesc); 1473 1474 if (deser == null) { 1475 // 12-Feb-2020, tatu: while we can't really create real deserializer for `Enum.class`, 1476 // it is necessary to allow it in one specific case: see [databind#2605] for details 1477 // but basically it can be used as polymorphic base. 1478 // We could check `type.getTypeHandler()` to look for that case but seems like we 1479 // may as well simply create placeholder (AbstractDeserializer) regardless 1480 if (enumClass == Enum.class) { 1481 return AbstractDeserializer.constructForNonPOJO(beanDesc); 1482 } 1483 1484 ValueInstantiator valueInstantiator = _constructDefaultValueInstantiator(ctxt, beanDesc); 1485 SettableBeanProperty[] creatorProps = (valueInstantiator == null) ? null 1486 : valueInstantiator.getFromObjectArguments(ctxt.getConfig()); 1487 // May have @JsonCreator for static factory method: 1488 for (AnnotatedMethod factory : beanDesc.getFactoryMethods()) { 1489 if (_hasCreatorAnnotation(ctxt, factory)) { 1490 if (factory.getParameterCount() == 0) { // [databind#960] 1491 deser = EnumDeserializer.deserializerForNoArgsCreator(config, enumClass, factory); 1492 break; 1493 } 1494 Class<?> returnType = factory.getRawReturnType(); 1495 // usually should be class, but may be just plain Enum<?> (for Enum.valueOf()?) 1496 if (!returnType.isAssignableFrom(enumClass)) { 1497 ctxt.reportBadDefinition(type, String.format( 1498 "Invalid `@JsonCreator` annotated Enum factory method [%s]: needs to return compatible type", 1499 factory.toString())); 1500 } 1501 deser = EnumDeserializer.deserializerForCreator(config, enumClass, factory, valueInstantiator, creatorProps); 1502 break; 1503 } 1504 } 1505 1506 // Need to consider @JsonValue if one found 1507 if (deser == null) { 1508 deser = new EnumDeserializer(constructEnumResolver(enumClass, 1509 config, beanDesc.findJsonValueAccessor()), 1510 config.isEnabled(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS)); 1511 } 1512 } 1513 1514 // and then post-process it too 1515 if (_factoryConfig.hasDeserializerModifiers()) { 1516 for (BeanDeserializerModifier mod : _factoryConfig.deserializerModifiers()) { 1517 deser = mod.modifyEnumDeserializer(config, type, beanDesc, deser); 1518 } 1519 } 1520 return deser; 1521 } 1522 1523 @Override createTreeDeserializer(DeserializationConfig config, JavaType nodeType, BeanDescription beanDesc)1524 public JsonDeserializer<?> createTreeDeserializer(DeserializationConfig config, 1525 JavaType nodeType, BeanDescription beanDesc) 1526 throws JsonMappingException 1527 { 1528 @SuppressWarnings("unchecked") 1529 Class<? extends JsonNode> nodeClass = (Class<? extends JsonNode>) nodeType.getRawClass(); 1530 // 23-Nov-2010, tatu: Custom deserializer? 1531 JsonDeserializer<?> custom = _findCustomTreeNodeDeserializer(nodeClass, config, 1532 beanDesc); 1533 if (custom != null) { 1534 return custom; 1535 } 1536 return JsonNodeDeserializer.getDeserializer(nodeClass); 1537 } 1538 1539 @Override createReferenceDeserializer(DeserializationContext ctxt, ReferenceType type, BeanDescription beanDesc)1540 public JsonDeserializer<?> createReferenceDeserializer(DeserializationContext ctxt, 1541 ReferenceType type, BeanDescription beanDesc) 1542 throws JsonMappingException 1543 { 1544 JavaType contentType = type.getContentType(); 1545 // Very first thing: is deserializer hard-coded for elements? 1546 JsonDeserializer<Object> contentDeser = contentType.getValueHandler(); 1547 final DeserializationConfig config = ctxt.getConfig(); 1548 // Then optional type info: if type has been resolved, we may already know type deserializer: 1549 TypeDeserializer contentTypeDeser = contentType.getTypeHandler(); 1550 if (contentTypeDeser == null) { // or if not, may be able to find: 1551 contentTypeDeser = findTypeDeserializer(config, contentType); 1552 } 1553 JsonDeserializer<?> deser = _findCustomReferenceDeserializer(type, config, beanDesc, 1554 contentTypeDeser, contentDeser); 1555 1556 if (deser == null) { 1557 // Just one referential type as of JDK 1.7 / Java 7: AtomicReference (Java 8 adds Optional) 1558 if (type.isTypeOrSubTypeOf(AtomicReference.class)) { 1559 Class<?> rawType = type.getRawClass(); 1560 ValueInstantiator inst; 1561 if (rawType == AtomicReference.class) { 1562 inst = null; 1563 } else { 1564 /* 23-Oct-2016, tatu: Note that subtypes are probably not supportable 1565 * without either forcing merging (to avoid having to create instance) 1566 * or something else... 1567 */ 1568 inst = findValueInstantiator(ctxt, beanDesc); 1569 } 1570 return new AtomicReferenceDeserializer(type, inst, contentTypeDeser, contentDeser); 1571 } 1572 } 1573 if (deser != null) { 1574 // and then post-process 1575 if (_factoryConfig.hasDeserializerModifiers()) { 1576 for (BeanDeserializerModifier mod : _factoryConfig.deserializerModifiers()) { 1577 deser = mod.modifyReferenceDeserializer(config, type, beanDesc, deser); 1578 } 1579 } 1580 } 1581 return deser; 1582 } 1583 1584 /* 1585 /********************************************************** 1586 /* DeserializerFactory impl (partial): type deserializers 1587 /********************************************************** 1588 */ 1589 1590 @Override findTypeDeserializer(DeserializationConfig config, JavaType baseType)1591 public TypeDeserializer findTypeDeserializer(DeserializationConfig config, 1592 JavaType baseType) 1593 throws JsonMappingException 1594 { 1595 BeanDescription bean = config.introspectClassAnnotations(baseType.getRawClass()); 1596 AnnotatedClass ac = bean.getClassInfo(); 1597 AnnotationIntrospector ai = config.getAnnotationIntrospector(); 1598 TypeResolverBuilder<?> b = ai.findTypeResolver(config, ac, baseType); 1599 1600 // Ok: if there is no explicit type info handler, we may want to 1601 // use a default. If so, config object knows what to use. 1602 Collection<NamedType> subtypes = null; 1603 if (b == null) { 1604 b = config.getDefaultTyper(baseType); 1605 if (b == null) { 1606 return null; 1607 } 1608 } else { 1609 subtypes = config.getSubtypeResolver().collectAndResolveSubtypesByTypeId(config, ac); 1610 } 1611 // May need to figure out default implementation, if none found yet 1612 // (note: check for abstract type is not 100% mandatory, more of an optimization) 1613 if ((b.getDefaultImpl() == null) && baseType.isAbstract()) { 1614 JavaType defaultType = mapAbstractType(config, baseType); 1615 if ((defaultType != null) && !defaultType.hasRawClass(baseType.getRawClass())) { 1616 b = b.defaultImpl(defaultType.getRawClass()); 1617 } 1618 } 1619 // 05-Apt-2018, tatu: Since we get non-mapping exception due to various limitations, 1620 // map to better type here 1621 try { 1622 return b.buildTypeDeserializer(config, baseType, subtypes); 1623 } catch (IllegalArgumentException e0) { 1624 InvalidDefinitionException e = InvalidDefinitionException.from((JsonParser) null, 1625 ClassUtil.exceptionMessage(e0), baseType); 1626 e.initCause(e0); 1627 throw e; 1628 } 1629 } 1630 1631 /** 1632 * Overridable method called after checking all other types. 1633 * 1634 * @since 2.2 1635 */ findOptionalStdDeserializer(DeserializationContext ctxt, JavaType type, BeanDescription beanDesc)1636 protected JsonDeserializer<?> findOptionalStdDeserializer(DeserializationContext ctxt, 1637 JavaType type, BeanDescription beanDesc) 1638 throws JsonMappingException 1639 { 1640 return OptionalHandlerFactory.instance.findDeserializer(type, ctxt.getConfig(), beanDesc); 1641 } 1642 1643 /* 1644 /********************************************************** 1645 /* DeserializerFactory impl (partial): key deserializers 1646 /********************************************************** 1647 */ 1648 1649 @Override createKeyDeserializer(DeserializationContext ctxt, JavaType type)1650 public KeyDeserializer createKeyDeserializer(DeserializationContext ctxt, 1651 JavaType type) 1652 throws JsonMappingException 1653 { 1654 final DeserializationConfig config = ctxt.getConfig(); 1655 BeanDescription beanDesc = null; 1656 KeyDeserializer deser = null; 1657 if (_factoryConfig.hasKeyDeserializers()) { 1658 beanDesc = config.introspectClassAnnotations(type); 1659 for (KeyDeserializers d : _factoryConfig.keyDeserializers()) { 1660 deser = d.findKeyDeserializer(type, config, beanDesc); 1661 if (deser != null) { 1662 break; 1663 } 1664 } 1665 } 1666 1667 // the only non-standard thing is this: 1668 if (deser == null) { 1669 // [databind#2452]: Support `@JsonDeserialize(keyUsing = ...)` 1670 if (beanDesc == null) { 1671 beanDesc = config.introspectClassAnnotations(type.getRawClass()); 1672 } 1673 deser = findKeyDeserializerFromAnnotation(ctxt, beanDesc.getClassInfo()); 1674 if (deser == null) { 1675 if (type.isEnumType()) { 1676 deser = _createEnumKeyDeserializer(ctxt, type); 1677 } else { 1678 deser = StdKeyDeserializers.findStringBasedKeyDeserializer(config, type); 1679 } 1680 } 1681 } 1682 // and then post-processing 1683 if (deser != null) { 1684 if (_factoryConfig.hasDeserializerModifiers()) { 1685 for (BeanDeserializerModifier mod : _factoryConfig.deserializerModifiers()) { 1686 deser = mod.modifyKeyDeserializer(config, type, deser); 1687 } 1688 } 1689 } 1690 return deser; 1691 } 1692 _createEnumKeyDeserializer(DeserializationContext ctxt, JavaType type)1693 private KeyDeserializer _createEnumKeyDeserializer(DeserializationContext ctxt, 1694 JavaType type) 1695 throws JsonMappingException 1696 { 1697 final DeserializationConfig config = ctxt.getConfig(); 1698 Class<?> enumClass = type.getRawClass(); 1699 1700 BeanDescription beanDesc = config.introspect(type); 1701 // 24-Sep-2015, bim: a key deserializer is the preferred thing. 1702 KeyDeserializer des = findKeyDeserializerFromAnnotation(ctxt, beanDesc.getClassInfo()); 1703 if (des != null) { 1704 return des; 1705 } else { 1706 // 24-Sep-2015, bim: if no key deser, look for enum deserializer first, then a plain deser. 1707 JsonDeserializer<?> custom = _findCustomEnumDeserializer(enumClass, config, beanDesc); 1708 if (custom != null) { 1709 return StdKeyDeserializers.constructDelegatingKeyDeserializer(config, type, custom); 1710 } 1711 JsonDeserializer<?> valueDesForKey = findDeserializerFromAnnotation(ctxt, beanDesc.getClassInfo()); 1712 if (valueDesForKey != null) { 1713 return StdKeyDeserializers.constructDelegatingKeyDeserializer(config, type, valueDesForKey); 1714 } 1715 } 1716 EnumResolver enumRes = constructEnumResolver(enumClass, config, beanDesc.findJsonValueAccessor()); 1717 1718 // May have @JsonCreator for static factory method 1719 for (AnnotatedMethod factory : beanDesc.getFactoryMethods()) { 1720 if (_hasCreatorAnnotation(ctxt, factory)) { 1721 int argCount = factory.getParameterCount(); 1722 if (argCount == 1) { 1723 Class<?> returnType = factory.getRawReturnType(); 1724 // usually should be class, but may be just plain Enum<?> (for Enum.valueOf()?) 1725 if (returnType.isAssignableFrom(enumClass)) { 1726 // note: mostly copied from 'EnumDeserializer.deserializerForCreator(...)' 1727 if (factory.getRawParameterType(0) != String.class) { 1728 // [databind#2725]: Should not error out because (1) there may be good creator 1729 // method and (2) this method may be valid for "regular" enum value deserialization 1730 // (leaving aside potential for multiple conflicting creators) 1731 // throw new IllegalArgumentException("Parameter #0 type for factory method ("+factory+") not suitable, must be java.lang.String"); 1732 continue; 1733 } 1734 if (config.canOverrideAccessModifiers()) { 1735 ClassUtil.checkAndFixAccess(factory.getMember(), 1736 ctxt.isEnabled(MapperFeature.OVERRIDE_PUBLIC_ACCESS_MODIFIERS)); 1737 } 1738 return StdKeyDeserializers.constructEnumKeyDeserializer(enumRes, factory); 1739 } 1740 } 1741 throw new IllegalArgumentException("Unsuitable method ("+factory+") decorated with @JsonCreator (for Enum type " 1742 +enumClass.getName()+")"); 1743 } 1744 } 1745 // Also, need to consider @JsonValue, if one found 1746 return StdKeyDeserializers.constructEnumKeyDeserializer(enumRes); 1747 } 1748 1749 /* 1750 /********************************************************** 1751 /* DeserializerFactory impl: checking explicitly registered desers 1752 /********************************************************** 1753 */ 1754 1755 @Override hasExplicitDeserializerFor(DeserializationConfig config, Class<?> valueType)1756 public boolean hasExplicitDeserializerFor(DeserializationConfig config, 1757 Class<?> valueType) 1758 { 1759 // First things first: unpeel Array types as the element type is 1760 // what we are interested in -- this because we will always support array 1761 // types via composition, and since array types are JDK provided (and hence 1762 // can not be custom or customized). 1763 while (valueType.isArray()) { 1764 valueType = valueType.getComponentType(); 1765 } 1766 1767 // Yes, we handle all Enum types 1768 if (Enum.class.isAssignableFrom(valueType)) { 1769 return true; 1770 } 1771 // Numbers? 1772 final String clsName = valueType.getName(); 1773 if (clsName.startsWith("java.")) { 1774 if (Collection.class.isAssignableFrom(valueType)) { 1775 return true; 1776 } 1777 if (Map.class.isAssignableFrom(valueType)) { 1778 return true; 1779 } 1780 if (Number.class.isAssignableFrom(valueType)) { 1781 return NumberDeserializers.find(valueType, clsName) != null; 1782 } 1783 if (JdkDeserializers.hasDeserializerFor(valueType) 1784 || (valueType == CLASS_STRING) 1785 || (valueType == Boolean.class) 1786 || (valueType == EnumMap.class) 1787 || (valueType == AtomicReference.class) 1788 ) { 1789 return true; 1790 } 1791 if (DateDeserializers.hasDeserializerFor(valueType)) { 1792 return true; 1793 } 1794 } else if (clsName.startsWith("com.fasterxml.")) { 1795 return JsonNode.class.isAssignableFrom(valueType) 1796 || (valueType == TokenBuffer.class); 1797 } else { 1798 return OptionalHandlerFactory.instance.hasDeserializerFor(valueType); 1799 } 1800 return false; 1801 } 1802 1803 /* 1804 /********************************************************** 1805 /* Extended API 1806 /********************************************************** 1807 */ 1808 1809 /** 1810 * Method called to create a type information deserializer for values of 1811 * given non-container property, if one is needed. 1812 * If not needed (no polymorphic handling configured for property), should return null. 1813 *<p> 1814 * Note that this method is only called for non-container bean properties, 1815 * and not for values in container types or root values (or container properties) 1816 * 1817 * @param baseType Declared base type of the value to deserializer (actual 1818 * deserializer type will be this type or its subtype) 1819 * 1820 * @return Type deserializer to use for given base type, if one is needed; null if not. 1821 */ findPropertyTypeDeserializer(DeserializationConfig config, JavaType baseType, AnnotatedMember annotated)1822 public TypeDeserializer findPropertyTypeDeserializer(DeserializationConfig config, 1823 JavaType baseType, AnnotatedMember annotated) 1824 throws JsonMappingException 1825 { 1826 AnnotationIntrospector ai = config.getAnnotationIntrospector(); 1827 TypeResolverBuilder<?> b = ai.findPropertyTypeResolver(config, annotated, baseType); 1828 // Defaulting: if no annotations on member, check value class 1829 if (b == null) { 1830 return findTypeDeserializer(config, baseType); 1831 } 1832 // but if annotations found, may need to resolve subtypes: 1833 Collection<NamedType> subtypes = config.getSubtypeResolver().collectAndResolveSubtypesByTypeId( 1834 config, annotated, baseType); 1835 try { 1836 return b.buildTypeDeserializer(config, baseType, subtypes); 1837 } catch (IllegalArgumentException e0) { 1838 InvalidDefinitionException e = InvalidDefinitionException.from((JsonParser) null, 1839 ClassUtil.exceptionMessage(e0), baseType); 1840 e.initCause(e0); 1841 throw e; 1842 } 1843 } 1844 1845 /** 1846 * Method called to find and create a type information deserializer for values of 1847 * given container (list, array, map) property, if one is needed. 1848 * If not needed (no polymorphic handling configured for property), should return null. 1849 *<p> 1850 * Note that this method is only called for container bean properties, 1851 * and not for values in container types or root values (or non-container properties) 1852 * 1853 * @param containerType Type of property; must be a container type 1854 * @param propertyEntity Field or method that contains container property 1855 */ findPropertyContentTypeDeserializer(DeserializationConfig config, JavaType containerType, AnnotatedMember propertyEntity)1856 public TypeDeserializer findPropertyContentTypeDeserializer(DeserializationConfig config, 1857 JavaType containerType, AnnotatedMember propertyEntity) 1858 throws JsonMappingException 1859 { 1860 AnnotationIntrospector ai = config.getAnnotationIntrospector(); 1861 TypeResolverBuilder<?> b = ai.findPropertyContentTypeResolver(config, propertyEntity, containerType); 1862 JavaType contentType = containerType.getContentType(); 1863 // Defaulting: if no annotations on member, check class 1864 if (b == null) { 1865 return findTypeDeserializer(config, contentType); 1866 } 1867 // but if annotations found, may need to resolve subtypes: 1868 Collection<NamedType> subtypes = config.getSubtypeResolver().collectAndResolveSubtypesByTypeId( 1869 config, propertyEntity, contentType); 1870 return b.buildTypeDeserializer(config, contentType, subtypes); 1871 } 1872 1873 /** 1874 * Helper method called to find one of default serializers for "well-known" 1875 * platform types: JDK-provided types, and small number of public Jackson 1876 * API types. 1877 * 1878 * @since 2.2 1879 */ findDefaultDeserializer(DeserializationContext ctxt, JavaType type, BeanDescription beanDesc)1880 public JsonDeserializer<?> findDefaultDeserializer(DeserializationContext ctxt, 1881 JavaType type, BeanDescription beanDesc) 1882 throws JsonMappingException 1883 { 1884 Class<?> rawType = type.getRawClass(); 1885 // Object ("untyped"), and as of 2.10 (see [databind#2115]), `java.io.Serializable` 1886 if ((rawType == CLASS_OBJECT) || (rawType == CLASS_SERIALIZABLE)) { 1887 // 11-Feb-2015, tatu: As per [databind#700] need to be careful wrt non-default Map, List. 1888 DeserializationConfig config = ctxt.getConfig(); 1889 JavaType lt, mt; 1890 1891 if (_factoryConfig.hasAbstractTypeResolvers()) { 1892 lt = _findRemappedType(config, List.class); 1893 mt = _findRemappedType(config, Map.class); 1894 } else { 1895 lt = mt = null; 1896 } 1897 return new UntypedObjectDeserializer(lt, mt); 1898 } 1899 // String and equivalents 1900 if (rawType == CLASS_STRING || rawType == CLASS_CHAR_SEQUENCE) { 1901 return StringDeserializer.instance; 1902 } 1903 if (rawType == CLASS_ITERABLE) { 1904 // [databind#199]: Can and should 'upgrade' to a Collection type: 1905 TypeFactory tf = ctxt.getTypeFactory(); 1906 JavaType[] tps = tf.findTypeParameters(type, CLASS_ITERABLE); 1907 JavaType elemType = (tps == null || tps.length != 1) ? TypeFactory.unknownType() : tps[0]; 1908 CollectionType ct = tf.constructCollectionType(Collection.class, elemType); 1909 // Should we re-introspect beanDesc? For now let's not... 1910 return createCollectionDeserializer(ctxt, ct, beanDesc); 1911 } 1912 if (rawType == CLASS_MAP_ENTRY) { 1913 // 28-Apr-2015, tatu: TypeFactory does it all for us already so 1914 JavaType kt = type.containedTypeOrUnknown(0); 1915 JavaType vt = type.containedTypeOrUnknown(1); 1916 TypeDeserializer vts = (TypeDeserializer) vt.getTypeHandler(); 1917 if (vts == null) { 1918 vts = findTypeDeserializer(ctxt.getConfig(), vt); 1919 } 1920 JsonDeserializer<Object> valueDeser = vt.getValueHandler(); 1921 KeyDeserializer keyDes = (KeyDeserializer) kt.getValueHandler(); 1922 return new MapEntryDeserializer(type, keyDes, valueDeser, vts); 1923 } 1924 String clsName = rawType.getName(); 1925 if (rawType.isPrimitive() || clsName.startsWith("java.")) { 1926 // Primitives/wrappers, other Numbers: 1927 JsonDeserializer<?> deser = NumberDeserializers.find(rawType, clsName); 1928 if (deser == null) { 1929 deser = DateDeserializers.find(rawType, clsName); 1930 } 1931 if (deser != null) { 1932 return deser; 1933 } 1934 } 1935 // and a few Jackson types as well: 1936 if (rawType == TokenBuffer.class) { 1937 return new TokenBufferDeserializer(); 1938 } 1939 JsonDeserializer<?> deser = findOptionalStdDeserializer(ctxt, type, beanDesc); 1940 if (deser != null) { 1941 return deser; 1942 } 1943 return JdkDeserializers.find(rawType, clsName); 1944 } 1945 _findRemappedType(DeserializationConfig config, Class<?> rawType)1946 protected JavaType _findRemappedType(DeserializationConfig config, Class<?> rawType) throws JsonMappingException { 1947 JavaType type = mapAbstractType(config, config.constructType(rawType)); 1948 return (type == null || type.hasRawClass(rawType)) ? null : type; 1949 } 1950 1951 /* 1952 /********************************************************** 1953 /* Helper methods, finding custom deserializers 1954 /********************************************************** 1955 */ 1956 _findCustomTreeNodeDeserializer(Class<? extends JsonNode> type, DeserializationConfig config, BeanDescription beanDesc)1957 protected JsonDeserializer<?> _findCustomTreeNodeDeserializer(Class<? extends JsonNode> type, 1958 DeserializationConfig config, BeanDescription beanDesc) 1959 throws JsonMappingException 1960 { 1961 for (Deserializers d : _factoryConfig.deserializers()) { 1962 JsonDeserializer<?> deser = d.findTreeNodeDeserializer(type, config, beanDesc); 1963 if (deser != null) { 1964 return deser; 1965 } 1966 } 1967 return null; 1968 } 1969 _findCustomReferenceDeserializer(ReferenceType type, DeserializationConfig config, BeanDescription beanDesc, TypeDeserializer contentTypeDeserializer, JsonDeserializer<?> contentDeserializer)1970 protected JsonDeserializer<?> _findCustomReferenceDeserializer(ReferenceType type, 1971 DeserializationConfig config, BeanDescription beanDesc, 1972 TypeDeserializer contentTypeDeserializer, JsonDeserializer<?> contentDeserializer) 1973 throws JsonMappingException 1974 { 1975 for (Deserializers d : _factoryConfig.deserializers()) { 1976 JsonDeserializer<?> deser = d.findReferenceDeserializer(type, config, beanDesc, 1977 contentTypeDeserializer, contentDeserializer); 1978 if (deser != null) { 1979 return deser; 1980 } 1981 } 1982 return null; 1983 } 1984 1985 @SuppressWarnings("unchecked") _findCustomBeanDeserializer(JavaType type, DeserializationConfig config, BeanDescription beanDesc)1986 protected JsonDeserializer<Object> _findCustomBeanDeserializer(JavaType type, 1987 DeserializationConfig config, BeanDescription beanDesc) 1988 throws JsonMappingException 1989 { 1990 for (Deserializers d : _factoryConfig.deserializers()) { 1991 JsonDeserializer<?> deser = d.findBeanDeserializer(type, config, beanDesc); 1992 if (deser != null) { 1993 return (JsonDeserializer<Object>) deser; 1994 } 1995 } 1996 return null; 1997 } 1998 _findCustomArrayDeserializer(ArrayType type, DeserializationConfig config, BeanDescription beanDesc, TypeDeserializer elementTypeDeserializer, JsonDeserializer<?> elementDeserializer)1999 protected JsonDeserializer<?> _findCustomArrayDeserializer(ArrayType type, 2000 DeserializationConfig config, BeanDescription beanDesc, 2001 TypeDeserializer elementTypeDeserializer, JsonDeserializer<?> elementDeserializer) 2002 throws JsonMappingException 2003 { 2004 for (Deserializers d : _factoryConfig.deserializers()) { 2005 JsonDeserializer<?> deser = d.findArrayDeserializer(type, config, 2006 beanDesc, elementTypeDeserializer, elementDeserializer); 2007 if (deser != null) { 2008 return deser; 2009 } 2010 } 2011 return null; 2012 } 2013 _findCustomCollectionDeserializer(CollectionType type, DeserializationConfig config, BeanDescription beanDesc, TypeDeserializer elementTypeDeserializer, JsonDeserializer<?> elementDeserializer)2014 protected JsonDeserializer<?> _findCustomCollectionDeserializer(CollectionType type, 2015 DeserializationConfig config, BeanDescription beanDesc, 2016 TypeDeserializer elementTypeDeserializer, JsonDeserializer<?> elementDeserializer) 2017 throws JsonMappingException 2018 { 2019 for (Deserializers d : _factoryConfig.deserializers()) { 2020 JsonDeserializer<?> deser = d.findCollectionDeserializer(type, config, beanDesc, 2021 elementTypeDeserializer, elementDeserializer); 2022 if (deser != null) { 2023 return deser; 2024 } 2025 } 2026 return null; 2027 } 2028 _findCustomCollectionLikeDeserializer(CollectionLikeType type, DeserializationConfig config, BeanDescription beanDesc, TypeDeserializer elementTypeDeserializer, JsonDeserializer<?> elementDeserializer)2029 protected JsonDeserializer<?> _findCustomCollectionLikeDeserializer(CollectionLikeType type, 2030 DeserializationConfig config, BeanDescription beanDesc, 2031 TypeDeserializer elementTypeDeserializer, JsonDeserializer<?> elementDeserializer) 2032 throws JsonMappingException 2033 { 2034 for (Deserializers d : _factoryConfig.deserializers()) { 2035 JsonDeserializer<?> deser = d.findCollectionLikeDeserializer(type, config, beanDesc, 2036 elementTypeDeserializer, elementDeserializer); 2037 if (deser != null) { 2038 return deser; 2039 } 2040 } 2041 return null; 2042 } 2043 _findCustomEnumDeserializer(Class<?> type, DeserializationConfig config, BeanDescription beanDesc)2044 protected JsonDeserializer<?> _findCustomEnumDeserializer(Class<?> type, 2045 DeserializationConfig config, BeanDescription beanDesc) 2046 throws JsonMappingException 2047 { 2048 for (Deserializers d : _factoryConfig.deserializers()) { 2049 JsonDeserializer<?> deser = d.findEnumDeserializer(type, config, beanDesc); 2050 if (deser != null) { 2051 return deser; 2052 } 2053 } 2054 return null; 2055 } 2056 _findCustomMapDeserializer(MapType type, DeserializationConfig config, BeanDescription beanDesc, KeyDeserializer keyDeserializer, TypeDeserializer elementTypeDeserializer, JsonDeserializer<?> elementDeserializer)2057 protected JsonDeserializer<?> _findCustomMapDeserializer(MapType type, 2058 DeserializationConfig config, BeanDescription beanDesc, 2059 KeyDeserializer keyDeserializer, 2060 TypeDeserializer elementTypeDeserializer, JsonDeserializer<?> elementDeserializer) 2061 throws JsonMappingException 2062 { 2063 for (Deserializers d : _factoryConfig.deserializers()) { 2064 JsonDeserializer<?> deser = d.findMapDeserializer(type, config, beanDesc, 2065 keyDeserializer, elementTypeDeserializer, elementDeserializer); 2066 if (deser != null) { 2067 return deser; 2068 } 2069 } 2070 return null; 2071 } 2072 _findCustomMapLikeDeserializer(MapLikeType type, DeserializationConfig config, BeanDescription beanDesc, KeyDeserializer keyDeserializer, TypeDeserializer elementTypeDeserializer, JsonDeserializer<?> elementDeserializer)2073 protected JsonDeserializer<?> _findCustomMapLikeDeserializer(MapLikeType type, 2074 DeserializationConfig config, BeanDescription beanDesc, 2075 KeyDeserializer keyDeserializer, 2076 TypeDeserializer elementTypeDeserializer, JsonDeserializer<?> elementDeserializer) 2077 throws JsonMappingException 2078 { 2079 for (Deserializers d : _factoryConfig.deserializers()) { 2080 JsonDeserializer<?> deser = d.findMapLikeDeserializer(type, config, beanDesc, 2081 keyDeserializer, elementTypeDeserializer, elementDeserializer); 2082 if (deser != null) { 2083 return deser; 2084 } 2085 } 2086 return null; 2087 } 2088 2089 /* 2090 /********************************************************** 2091 /* Helper methods, value/content/key type introspection 2092 /********************************************************** 2093 */ 2094 2095 /** 2096 * Helper method called to check if a class or method 2097 * has annotation that tells which class to use for deserialization; and if 2098 * so, to instantiate, that deserializer to use. 2099 * Note that deserializer will NOT yet be contextualized so caller needs to 2100 * take care to call contextualization appropriately. 2101 * Returns null if no such annotation found. 2102 */ findDeserializerFromAnnotation(DeserializationContext ctxt, Annotated ann)2103 protected JsonDeserializer<Object> findDeserializerFromAnnotation(DeserializationContext ctxt, 2104 Annotated ann) 2105 throws JsonMappingException 2106 { 2107 AnnotationIntrospector intr = ctxt.getAnnotationIntrospector(); 2108 if (intr != null) { 2109 Object deserDef = intr.findDeserializer(ann); 2110 if (deserDef != null) { 2111 return ctxt.deserializerInstance(ann, deserDef); 2112 } 2113 } 2114 return null; 2115 } 2116 2117 /** 2118 * Helper method called to check if a class or method 2119 * has annotation that tells which class to use for deserialization of {@link java.util.Map} keys. 2120 * Returns null if no such annotation found. 2121 */ findKeyDeserializerFromAnnotation(DeserializationContext ctxt, Annotated ann)2122 protected KeyDeserializer findKeyDeserializerFromAnnotation(DeserializationContext ctxt, 2123 Annotated ann) 2124 throws JsonMappingException 2125 { 2126 AnnotationIntrospector intr = ctxt.getAnnotationIntrospector(); 2127 if (intr != null) { 2128 Object deserDef = intr.findKeyDeserializer(ann); 2129 if (deserDef != null) { 2130 return ctxt.keyDeserializerInstance(ann, deserDef); 2131 } 2132 } 2133 return null; 2134 } 2135 2136 /** 2137 * @since 2.9 2138 */ findContentDeserializerFromAnnotation(DeserializationContext ctxt, Annotated ann)2139 protected JsonDeserializer<Object> findContentDeserializerFromAnnotation(DeserializationContext ctxt, 2140 Annotated ann) 2141 throws JsonMappingException 2142 { 2143 AnnotationIntrospector intr = ctxt.getAnnotationIntrospector(); 2144 if (intr != null) { 2145 Object deserDef = intr.findContentDeserializer(ann); 2146 if (deserDef != null) { 2147 return ctxt.deserializerInstance(ann, deserDef); 2148 } 2149 } 2150 return null; 2151 } 2152 2153 /** 2154 * Helper method used to resolve additional type-related annotation information 2155 * like type overrides, or handler (serializer, deserializer) overrides, 2156 * so that from declared field, property or constructor parameter type 2157 * is used as the base and modified based on annotations, if any. 2158 * 2159 * @since 2.8 Combines functionality of <code>modifyTypeByAnnotation</code> 2160 * and <code>resolveType</code> 2161 */ resolveMemberAndTypeAnnotations(DeserializationContext ctxt, AnnotatedMember member, JavaType type)2162 protected JavaType resolveMemberAndTypeAnnotations(DeserializationContext ctxt, 2163 AnnotatedMember member, JavaType type) 2164 throws JsonMappingException 2165 { 2166 AnnotationIntrospector intr = ctxt.getAnnotationIntrospector(); 2167 if (intr == null) { 2168 return type; 2169 } 2170 2171 // First things first: see if we can find annotations on declared 2172 // type 2173 2174 if (type.isMapLikeType()) { 2175 JavaType keyType = type.getKeyType(); 2176 if (keyType != null) { 2177 Object kdDef = intr.findKeyDeserializer(member); 2178 KeyDeserializer kd = ctxt.keyDeserializerInstance(member, kdDef); 2179 if (kd != null) { 2180 type = ((MapLikeType) type).withKeyValueHandler(kd); 2181 keyType = type.getKeyType(); // just in case it's used below 2182 } 2183 } 2184 } 2185 2186 if (type.hasContentType()) { // that is, is either container- or reference-type 2187 Object cdDef = intr.findContentDeserializer(member); 2188 JsonDeserializer<?> cd = ctxt.deserializerInstance(member, cdDef); 2189 if (cd != null) { 2190 type = type.withContentValueHandler(cd); 2191 } 2192 TypeDeserializer contentTypeDeser = findPropertyContentTypeDeserializer( 2193 ctxt.getConfig(), type, (AnnotatedMember) member); 2194 if (contentTypeDeser != null) { 2195 type = type.withContentTypeHandler(contentTypeDeser); 2196 } 2197 } 2198 TypeDeserializer valueTypeDeser = findPropertyTypeDeserializer(ctxt.getConfig(), 2199 type, (AnnotatedMember) member); 2200 if (valueTypeDeser != null) { 2201 type = type.withTypeHandler(valueTypeDeser); 2202 } 2203 2204 // Second part: find actual type-override annotations on member, if any 2205 2206 // 18-Jun-2016, tatu: Should we re-do checks for annotations on refined 2207 // subtypes as well? Code pre-2.8 did not do this, but if we get bug 2208 // reports may need to consider 2209 type = intr.refineDeserializationType(ctxt.getConfig(), member, type); 2210 return type; 2211 } 2212 constructEnumResolver(Class<?> enumClass, DeserializationConfig config, AnnotatedMember jsonValueAccessor)2213 protected EnumResolver constructEnumResolver(Class<?> enumClass, 2214 DeserializationConfig config, AnnotatedMember jsonValueAccessor) 2215 { 2216 if (jsonValueAccessor != null) { 2217 if (config.canOverrideAccessModifiers()) { 2218 ClassUtil.checkAndFixAccess(jsonValueAccessor.getMember(), 2219 config.isEnabled(MapperFeature.OVERRIDE_PUBLIC_ACCESS_MODIFIERS)); 2220 } 2221 return EnumResolver.constructUnsafeUsingMethod(enumClass, 2222 jsonValueAccessor, config.getAnnotationIntrospector()); 2223 } 2224 // 14-Mar-2016, tatu: We used to check `DeserializationFeature.READ_ENUMS_USING_TO_STRING` 2225 // here, but that won't do: it must be dynamically changeable... 2226 return EnumResolver.constructUnsafe(enumClass, config.getAnnotationIntrospector()); 2227 } 2228 2229 /** 2230 * @since 2.9 2231 */ _hasCreatorAnnotation(DeserializationContext ctxt, Annotated ann)2232 protected boolean _hasCreatorAnnotation(DeserializationContext ctxt, 2233 Annotated ann) { 2234 AnnotationIntrospector intr = ctxt.getAnnotationIntrospector(); 2235 if (intr != null) { 2236 JsonCreator.Mode mode = intr.findCreatorAnnotation(ctxt.getConfig(), ann); 2237 return (mode != null) && (mode != JsonCreator.Mode.DISABLED); 2238 } 2239 return false; 2240 } 2241 2242 /* 2243 /********************************************************** 2244 /* Deprecated helper methods 2245 /********************************************************** 2246 */ 2247 2248 /** 2249 * Method called to see if given method has annotations that indicate 2250 * a more specific type than what the argument specifies. 2251 * 2252 * @deprecated Since 2.8; call {@link #resolveMemberAndTypeAnnotations} instead 2253 */ 2254 @Deprecated modifyTypeByAnnotation(DeserializationContext ctxt, Annotated a, JavaType type)2255 protected JavaType modifyTypeByAnnotation(DeserializationContext ctxt, 2256 Annotated a, JavaType type) 2257 throws JsonMappingException 2258 { 2259 AnnotationIntrospector intr = ctxt.getAnnotationIntrospector(); 2260 if (intr == null) { 2261 return type; 2262 } 2263 return intr.refineDeserializationType(ctxt.getConfig(), a, type); 2264 } 2265 2266 /** 2267 * @deprecated since 2.8 call {@link #resolveMemberAndTypeAnnotations} instead. 2268 */ 2269 @Deprecated // since 2.8 resolveType(DeserializationContext ctxt, BeanDescription beanDesc, JavaType type, AnnotatedMember member)2270 protected JavaType resolveType(DeserializationContext ctxt, 2271 BeanDescription beanDesc, JavaType type, AnnotatedMember member) 2272 throws JsonMappingException 2273 { 2274 return resolveMemberAndTypeAnnotations(ctxt, member, type); 2275 } 2276 2277 /** 2278 * @deprecated since 2.8 call <code>findJsonValueMethod</code> on {@link BeanDescription} instead 2279 */ 2280 @Deprecated // not used, possibly remove as early as 2.9 _findJsonValueFor(DeserializationConfig config, JavaType enumType)2281 protected AnnotatedMethod _findJsonValueFor(DeserializationConfig config, JavaType enumType) 2282 { 2283 if (enumType == null) { 2284 return null; 2285 } 2286 BeanDescription beanDesc = config.introspect(enumType); 2287 return beanDesc.findJsonValueMethod(); 2288 } 2289 2290 /** 2291 * Helper class to contain default mappings for abstract JDK {@link java.util.Collection} 2292 * and {@link java.util.Map} types. Separated out here to defer cost of creating lookups 2293 * until mappings are actually needed. 2294 * 2295 * @since 2.10 2296 */ 2297 @SuppressWarnings("rawtypes") 2298 protected static class ContainerDefaultMappings { 2299 // We do some defaulting for abstract Collection classes and 2300 // interfaces, to avoid having to use exact types or annotations in 2301 // cases where the most common concrete Collection will do. 2302 final static HashMap<String, Class<? extends Collection>> _collectionFallbacks; 2303 static { 2304 HashMap<String, Class<? extends Collection>> fallbacks = new HashMap<>(); 2305 2306 final Class<? extends Collection> DEFAULT_LIST = ArrayList.class; 2307 final Class<? extends Collection> DEFAULT_SET = HashSet.class; 2308 Collection.class.getName()2309 fallbacks.put(Collection.class.getName(), DEFAULT_LIST); List.class.getName()2310 fallbacks.put(List.class.getName(), DEFAULT_LIST); Set.class.getName()2311 fallbacks.put(Set.class.getName(), DEFAULT_SET); SortedSet.class.getName()2312 fallbacks.put(SortedSet.class.getName(), TreeSet.class); Queue.class.getName()2313 fallbacks.put(Queue.class.getName(), LinkedList.class); 2314 2315 // 09-Feb-2019, tatu: How did we miss these? Related in [databind#2251] problem AbstractList.class.getName()2316 fallbacks.put(AbstractList.class.getName(), DEFAULT_LIST); AbstractSet.class.getName()2317 fallbacks.put(AbstractSet.class.getName(), DEFAULT_SET); 2318 2319 // 09-Feb-2019, tatu: And more esoteric types added in JDK6 Deque.class.getName()2320 fallbacks.put(Deque.class.getName(), LinkedList.class); NavigableSet.class.getName()2321 fallbacks.put(NavigableSet.class.getName(), TreeSet.class); 2322 2323 _collectionFallbacks = fallbacks; 2324 } 2325 2326 // We do some defaulting for abstract Map classes and 2327 // interfaces, to avoid having to use exact types or annotations in 2328 // cases where the most common concrete Maps will do. 2329 final static HashMap<String, Class<? extends Map>> _mapFallbacks; 2330 static { 2331 HashMap<String, Class<? extends Map>> fallbacks = new HashMap<>(); 2332 2333 final Class<? extends Map> DEFAULT_MAP = LinkedHashMap.class; Map.class.getName()2334 fallbacks.put(Map.class.getName(), DEFAULT_MAP); AbstractMap.class.getName()2335 fallbacks.put(AbstractMap.class.getName(), DEFAULT_MAP); ConcurrentMap.class.getName()2336 fallbacks.put(ConcurrentMap.class.getName(), ConcurrentHashMap.class); SortedMap.class.getName()2337 fallbacks.put(SortedMap.class.getName(), TreeMap.class); 2338 java.util.NavigableMap.class.getName()2339 fallbacks.put(java.util.NavigableMap.class.getName(), TreeMap.class); java.util.concurrent.ConcurrentNavigableMap.class.getName()2340 fallbacks.put(java.util.concurrent.ConcurrentNavigableMap.class.getName(), 2341 java.util.concurrent.ConcurrentSkipListMap.class); 2342 2343 _mapFallbacks = fallbacks; 2344 } 2345 findCollectionFallback(JavaType type)2346 public static Class<?> findCollectionFallback(JavaType type) { 2347 return _collectionFallbacks.get(type.getRawClass().getName()); 2348 } 2349 findMapFallback(JavaType type)2350 public static Class<?> findMapFallback(JavaType type) { 2351 return _mapFallbacks.get(type.getRawClass().getName()); 2352 } 2353 } 2354 } 2355