/**
   * Method called by {@link BeanDeserializerFactory} to see if there might be a standard
   * deserializer registered for given type.
   */
  @SuppressWarnings("unchecked")
  protected JsonDeserializer<Object> findStdDeserializer(
      DeserializationConfig config, JavaType type) throws JsonMappingException {
    Class<?> cls = type.getRawClass();
    // note: we do NOT check for custom deserializers here; that's for sub-class to do
    JsonDeserializer<Object> deser = _simpleDeserializers.get(new ClassKey(cls));
    if (deser != null) {
      return deser;
    }

    // [JACKSON-283]: AtomicReference is a rather special type...
    if (AtomicReference.class.isAssignableFrom(cls)) {
      // Must find parameterization
      TypeFactory tf = config.getTypeFactory();
      JavaType[] params = tf.findTypeParameters(type, AtomicReference.class);
      JavaType referencedType;
      if (params == null || params.length < 1) { // untyped (raw)
        referencedType = TypeFactory.unknownType();
      } else {
        referencedType = params[0];
      }

      JsonDeserializer<?> d2 = new JdkDeserializers.AtomicReferenceDeserializer(referencedType);
      return (JsonDeserializer<Object>) d2;
    }
    // [JACKSON-386]: External/optional type handlers are handled somewhat differently
    JsonDeserializer<?> d = optionalHandlers.findDeserializer(type, config);
    if (d != null) {
      return (JsonDeserializer<Object>) d;
    }
    return null;
  }
  /** Method that will construct a regular bean property setter using the given setter method. */
  protected SettableBeanProperty constructSetterlessProperty(
      DeserializationContext ctxt, BeanDescription beanDesc, BeanPropertyDefinition propDef)
      throws JsonMappingException {
    final AnnotatedMethod getter = propDef.getGetter();
    // need to ensure it is callable now:
    if (ctxt.canOverrideAccessModifiers()) {
      getter.fixAccess();
    }

    /* 26-Jan-2012, tatu: Alas, this complication is still needed to handle
     *   (or at least work around) local type declarations...
     */
    JavaType type = getter.getType(beanDesc.bindingsForBeanType());
    /* First: does the Method specify the deserializer to use?
     * If so, let's use it.
     */
    JsonDeserializer<Object> propDeser = findDeserializerFromAnnotation(ctxt, getter);
    type = modifyTypeByAnnotation(ctxt, getter, type);
    TypeDeserializer typeDeser = type.getTypeHandler();
    SettableBeanProperty prop =
        new SetterlessProperty(propDef, type, typeDeser, beanDesc.getClassAnnotations(), getter);
    if (propDeser != null) {
      prop = prop.withValueDeserializer(propDeser);
    }
    return prop;
  }
  public ValueInstantiator constructValueInstantiator(DeserializationConfig config) {
    JavaType delegateType;
    boolean maybeVanilla = !_hasNonDefaultCreator;

    if (maybeVanilla || (_creators[C_DELEGATE] == null)) {
      delegateType = null;
    } else {
      // need to find type...
      int ix = 0;
      if (_delegateArgs != null) {
        for (int i = 0, len = _delegateArgs.length; i < len; ++i) {
          if (_delegateArgs[i] == null) { // marker for delegate itself
            ix = i;
            break;
          }
        }
      }
      delegateType = _creators[C_DELEGATE].getParameterType(ix);
    }

    final JavaType type = _beanDesc.getType();

    // Any non-standard creator will prevent; with one exception: int-valued constructor
    // that standard containers have can be ignored
    maybeVanilla &= !_hasNonDefaultCreator;

    if (maybeVanilla) {
      /* 10-May-2014, tatu: If we have nothing special, and we are dealing with one
       *   of "well-known" types, can create a non-reflection-based instantiator.
       */
      final Class<?> rawType = type.getRawClass();
      if (rawType == Collection.class || rawType == List.class || rawType == ArrayList.class) {
        return new Vanilla(Vanilla.TYPE_COLLECTION);
      }
      if (rawType == Map.class || rawType == LinkedHashMap.class) {
        return new Vanilla(Vanilla.TYPE_MAP);
      }
      if (rawType == HashMap.class) {
        return new Vanilla(Vanilla.TYPE_HASH_MAP);
      }
    }

    StdValueInstantiator inst = new StdValueInstantiator(config, type);
    inst.configureFromObjectSettings(
        _creators[C_DEFAULT],
        _creators[C_DELEGATE],
        delegateType,
        _delegateArgs,
        _creators[C_PROPS],
        _propertyBasedArgs);
    inst.configureFromStringCreator(_creators[C_STRING]);
    inst.configureFromIntCreator(_creators[C_INT]);
    inst.configureFromLongCreator(_creators[C_LONG]);
    inst.configureFromDoubleCreator(_creators[C_DOUBLE]);
    inst.configureFromBooleanCreator(_creators[C_BOOLEAN]);
    inst.configureIncompleteParameter(_incompleteParameter);
    return inst;
  }
  /**
   * Method that will construct a regular bean property setter using the given setter method.
   *
   * @return Property constructed, if any; or null to indicate that there should be no property
   *     based on given definitions.
   */
  protected SettableBeanProperty constructSettableProperty(
      DeserializationContext ctxt,
      BeanDescription beanDesc,
      BeanPropertyDefinition propDef,
      Type jdkType)
      throws JsonMappingException {
    // need to ensure method is callable (for non-public)
    AnnotatedMember mutator = propDef.getMutator();
    if (ctxt.canOverrideAccessModifiers()) {
      mutator.fixAccess();
    }
    // note: this works since we know there's exactly one argument for methods
    JavaType t0 = beanDesc.resolveType(jdkType);

    BeanProperty.Std property =
        new BeanProperty.Std(propDef.getName(), t0, beanDesc.getClassAnnotations(), mutator);
    JavaType type = resolveType(ctxt, beanDesc, t0, mutator);
    // did type change?
    if (type != t0) {
      property = property.withType(type);
    }

    /* First: does the Method specify the deserializer to use?
     * If so, let's use it.
     */
    JsonDeserializer<Object> propDeser = findDeserializerFromAnnotation(ctxt, mutator);
    type = modifyTypeByAnnotation(ctxt, mutator, type);
    TypeDeserializer typeDeser = type.getTypeHandler();
    SettableBeanProperty prop;
    if (mutator instanceof AnnotatedMethod) {
      prop =
          new MethodProperty(
              propDef, type, typeDeser, beanDesc.getClassAnnotations(), (AnnotatedMethod) mutator);
    } else {
      prop =
          new FieldProperty(
              propDef, type, typeDeser, beanDesc.getClassAnnotations(), (AnnotatedField) mutator);
    }
    if (propDeser != null) {
      prop = prop.withValueDeserializer(propDeser);
    }
    // [JACKSON-235]: need to retain name of managed forward references:
    AnnotationIntrospector.ReferenceProperty ref = propDef.findReferenceType();
    if (ref != null && ref.isManagedReference()) {
      prop.setManagedReferenceName(ref.getName());
    }
    return prop;
  }
  /**
   * Method that {@link DeserializerCache}s call to create a new deserializer for types other than
   * Collections, Maps, arrays and enums.
   */
  @Override
  public JsonDeserializer<Object> createBeanDeserializer(
      DeserializationContext ctxt, JavaType type, BeanDescription beanDesc)
      throws JsonMappingException {
    final DeserializationConfig config = ctxt.getConfig();
    // We may also have custom overrides:
    JsonDeserializer<Object> custom = _findCustomBeanDeserializer(type, config, beanDesc);
    if (custom != null) {
      return custom;
    }
    /* One more thing to check: do we have an exception type
     * (Throwable or its sub-classes)? If so, need slightly
     * different handling.
     */
    if (type.isThrowable()) {
      return buildThrowableDeserializer(ctxt, type, beanDesc);
    }
    /* Or, for abstract types, may have alternate means for resolution
     * (defaulting, materialization)
     */
    if (type.isAbstract()) {
      // [JACKSON-41] (v1.6): Let's make it possible to materialize abstract types.
      JavaType concreteType = materializeAbstractType(config, beanDesc);
      if (concreteType != null) {
        /* important: introspect actual implementation (abstract class or
         * interface doesn't have constructors, for one)
         */
        beanDesc = config.introspect(concreteType);
        return buildBeanDeserializer(ctxt, concreteType, beanDesc);
      }
    }

    // Otherwise, may want to check handlers for standard types, from superclass:
    JsonDeserializer<Object> deser = findStdDeserializer(config, type);
    if (deser != null) {
      return deser;
    }

    // Otherwise: could the class be a Bean class? If not, bail out
    if (!isPotentialBeanType(type.getRawClass())) {
      return null;
    }
    // Use generic bean introspection to build deserializer
    return buildBeanDeserializer(ctxt, type, beanDesc);
  }
  /**
   * Method that is to actually build a bean deserializer instance. All basic sanity checks have
   * been done to know that what we have may be a valid bean type, and that there are no default
   * simple deserializers.
   */
  @SuppressWarnings("unchecked")
  public JsonDeserializer<Object> buildBeanDeserializer(
      DeserializationContext ctxt, JavaType type, BeanDescription beanDesc)
      throws JsonMappingException {
    // First: check what creators we can use, if any
    ValueInstantiator valueInstantiator = findValueInstantiator(ctxt, beanDesc);
    BeanDeserializerBuilder builder = constructBeanDeserializerBuilder(ctxt, beanDesc);
    builder.setValueInstantiator(valueInstantiator);
    // And then setters for deserializing from JSON Object
    addBeanProps(ctxt, beanDesc, builder);
    addObjectIdReader(ctxt, beanDesc, builder);

    // managed/back reference fields/setters need special handling... first part
    addReferenceProperties(ctxt, beanDesc, builder);
    addInjectables(ctxt, beanDesc, builder);

    final DeserializationConfig config = ctxt.getConfig();
    // [JACKSON-440]: update builder now that all information is in?
    if (_factoryConfig.hasDeserializerModifiers()) {
      for (BeanDeserializerModifier mod : _factoryConfig.deserializerModifiers()) {
        builder = mod.updateBuilder(config, beanDesc, builder);
      }
    }
    JsonDeserializer<?> deserializer;

    /* 19-Mar-2012, tatu: This check used to be done earlier; but we have to defer
     *   it a bit to collect information on ObjectIdReader, for example.
     */
    if (type.isAbstract() && !valueInstantiator.canInstantiate()) {
      deserializer = builder.buildAbstract();
    } else {
      deserializer = builder.build();
    }

    // [JACKSON-440]: may have modifier(s) that wants to modify or replace serializer we just built:
    if (_factoryConfig.hasDeserializerModifiers()) {
      for (BeanDeserializerModifier mod : _factoryConfig.deserializerModifiers()) {
        deserializer = mod.modifyDeserializer(config, beanDesc, deserializer);
      }
    }
    return (JsonDeserializer<Object>) deserializer;
  }