/**
   * 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;
  }
  /**
   * Method that does the heavy lifting of checking for per-type annotations, find out full type,
   * and figure out which actual factory method to call.
   */
  @SuppressWarnings("unchecked")
  protected JsonDeserializer<Object> _createDeserializer(
      DeserializationContext ctxt, DeserializerFactory factory, JavaType type)
      throws JsonMappingException {
    final DeserializationConfig config = ctxt.getConfig();

    // First things first: do we need to use abstract type mapping?
    if (type.isAbstract() || type.isMapLikeType() || type.isCollectionLikeType()) {
      type = factory.mapAbstractType(config, type);
    }
    BeanDescription beanDesc = config.introspect(type);
    // Then: does type define explicit deserializer to use, with annotation(s)?
    JsonDeserializer<Object> deser = findDeserializerFromAnnotation(ctxt, beanDesc.getClassInfo());
    if (deser != null) {
      return deser;
    }

    // If not, may have further type-modification annotations to check:
    JavaType newType = modifyTypeByAnnotation(ctxt, beanDesc.getClassInfo(), type);
    if (newType != type) {
      type = newType;
      beanDesc = config.introspect(newType);
    }

    // We may also have a Builder type to consider...
    Class<?> builder = beanDesc.findPOJOBuilder();
    if (builder != null) {
      return (JsonDeserializer<Object>)
          factory.createBuilderBasedDeserializer(ctxt, type, beanDesc, builder);
    }

    // Or perhaps a Converter?
    Converter<Object, Object> conv = beanDesc.findDeserializationConverter();
    if (conv == null) { // nope, just construct in normal way
      return (JsonDeserializer<Object>) _createDeserializer2(ctxt, factory, type, beanDesc);
    }
    // otherwise need to do bit of introspection
    JavaType delegateType = conv.getInputType(ctxt.getTypeFactory());
    return new StdDelegatingDeserializer<Object>(
        conv, delegateType, _createDeserializer2(ctxt, factory, delegateType, beanDesc));
  }