/**
   * Method that handles actual construction (via factory) and caching (both intermediate and
   * eventual)
   */
  protected JsonDeserializer<Object> _createAndCache2(
      DeserializationContext ctxt, DeserializerFactory factory, JavaType type)
      throws JsonMappingException {
    JsonDeserializer<Object> deser;
    try {
      deser = _createDeserializer(ctxt, factory, type);
    } catch (IllegalArgumentException iae) {
      /* We better only expose checked exceptions, since those
       * are what caller is expected to handle
       */
      throw new JsonMappingException(iae.getMessage(), null, iae);
    }
    if (deser == null) {
      return null;
    }
    /* cache resulting deserializer? always true for "plain" BeanDeserializer
     * (but can be re-defined for sub-classes by using @JsonCachable!)
     */
    // 08-Jun-2010, tatu: Related to [JACKSON-296], need to avoid caching MapSerializers... so:
    boolean isResolvable = (deser instanceof ResolvableDeserializer);
    boolean addToCache = deser.isCachable();

    /* we will temporarily hold on to all created deserializers (to
     * handle cyclic references, and possibly reuse non-cached
     * deserializers (list, map))
     */
    /* 07-Jun-2010, tatu: Danger: [JACKSON-296] was caused by accidental
     *   resolution of a reference -- couple of ways to prevent this;
     *   either not add Lists or Maps, or clear references eagerly.
     *   Let's actually do both; since both seem reasonable.
     */
    /* Need to resolve? Mostly done for bean deserializers; required for
     * resolving cyclic references.
     */
    if (isResolvable) {
      _incompleteDeserializers.put(type, deser);
      ((ResolvableDeserializer) deser).resolve(ctxt);
      _incompleteDeserializers.remove(type);
    }
    if (addToCache) {
      _cachedDeserializers.put(type, deser);
    }
    return deser;
  }
  /**
   * Method called to see if given method has annotations that indicate a more specific type than
   * what the argument specifies. If annotations are present, they must specify compatible Class;
   * instance of which can be assigned using the method. This means that the Class has to be raw
   * class of type, or its sub-class (or, implementing class if original Class instance is an
   * interface).
   *
   * @param a Method or field that the type is associated with
   * @param type Type derived from the setter argument
   * @return Original type if no annotations are present; or a more specific type derived from it if
   *     type annotation(s) was found
   * @throws JsonMappingException if invalid annotation is found
   */
  private JavaType modifyTypeByAnnotation(DeserializationContext ctxt, Annotated a, JavaType type)
      throws JsonMappingException {
    // first: let's check class for the instance itself:
    AnnotationIntrospector intr = ctxt.getAnnotationIntrospector();
    Class<?> subclass = intr.findDeserializationType(a, type);
    if (subclass != null) {
      try {
        type = type.narrowBy(subclass);
      } catch (IllegalArgumentException iae) {
        throw new JsonMappingException(
            "Failed to narrow type "
                + type
                + " with concrete-type annotation (value "
                + subclass.getName()
                + "), method '"
                + a.getName()
                + "': "
                + iae.getMessage(),
            null,
            iae);
      }
    }

    // then key class
    if (type.isContainerType()) {
      Class<?> keyClass = intr.findDeserializationKeyType(a, type.getKeyType());
      if (keyClass != null) {
        // illegal to use on non-Maps
        if (!(type instanceof MapLikeType)) {
          throw new JsonMappingException(
              "Illegal key-type annotation: type " + type + " is not a Map(-like) type");
        }
        try {
          type = ((MapLikeType) type).narrowKey(keyClass);
        } catch (IllegalArgumentException iae) {
          throw new JsonMappingException(
              "Failed to narrow key type "
                  + type
                  + " with key-type annotation ("
                  + keyClass.getName()
                  + "): "
                  + iae.getMessage(),
              null,
              iae);
        }
      }
      JavaType keyType = type.getKeyType();
      /* 21-Mar-2011, tatu: ... and associated deserializer too (unless already assigned)
       *   (not 100% why or how, but this does seem to get called more than once, which
       *   is not good: for now, let's just avoid errors)
       */
      if (keyType != null && keyType.getValueHandler() == null) {
        Object kdDef = intr.findKeyDeserializer(a);
        if (kdDef != null) {
          KeyDeserializer kd = ctxt.keyDeserializerInstance(a, kdDef);
          if (kd != null) {
            type = ((MapLikeType) type).withKeyValueHandler(kd);
            keyType = type.getKeyType(); // just in case it's used below
          }
        }
      }

      // and finally content class; only applicable to structured types
      Class<?> cc = intr.findDeserializationContentType(a, type.getContentType());
      if (cc != null) {
        try {
          type = type.narrowContentsBy(cc);
        } catch (IllegalArgumentException iae) {
          throw new JsonMappingException(
              "Failed to narrow content type "
                  + type
                  + " with content-type annotation ("
                  + cc.getName()
                  + "): "
                  + iae.getMessage(),
              null,
              iae);
        }
      }
      // ... as well as deserializer for contents:
      JavaType contentType = type.getContentType();
      if (contentType.getValueHandler()
          == null) { // as with above, avoid resetting (which would trigger exception)
        Object cdDef = intr.findContentDeserializer(a);
        if (cdDef != null) {
          JsonDeserializer<?> cd = null;
          if (cdDef instanceof JsonDeserializer<?>) {
            cdDef = (JsonDeserializer<?>) cdDef;
          } else {
            Class<?> cdClass =
                _verifyAsClass(cdDef, "findContentDeserializer", JsonDeserializer.None.class);
            if (cdClass != null) {
              cd = ctxt.deserializerInstance(a, cdClass);
            }
          }
          if (cd != null) {
            type = type.withContentValueHandler(cd);
          }
        }
      }
    }
    return type;
  }