/**
   * 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));
  }
 protected JsonDeserializer<?> _createDeserializer2(
     DeserializationContext ctxt,
     DeserializerFactory factory,
     JavaType type,
     BeanDescription beanDesc)
     throws JsonMappingException {
   final DeserializationConfig config = ctxt.getConfig();
   // If not, let's see which factory method to use:
   if (type.isEnumType()) {
     return factory.createEnumDeserializer(ctxt, type, beanDesc);
   }
   if (type.isContainerType()) {
     if (type.isArrayType()) {
       return factory.createArrayDeserializer(ctxt, (ArrayType) type, beanDesc);
     }
     if (type.isMapLikeType()) {
       MapLikeType mlt = (MapLikeType) type;
       if (mlt.isTrueMapType()) {
         return factory.createMapDeserializer(ctxt, (MapType) mlt, beanDesc);
       }
       return factory.createMapLikeDeserializer(ctxt, mlt, beanDesc);
     }
     if (type.isCollectionLikeType()) {
       /* 03-Aug-2012, tatu: As per [Issue#40], one exception is if shape
        *   is to be Shape.OBJECT. Ideally we'd determine it bit later on
        *   (to allow custom handler checks), but that won't work for other
        *   reasons. So do it here.
        */
       JsonFormat.Value format = beanDesc.findExpectedFormat(null);
       if (format == null || format.getShape() != JsonFormat.Shape.OBJECT) {
         CollectionLikeType clt = (CollectionLikeType) type;
         if (clt.isTrueCollectionType()) {
           return factory.createCollectionDeserializer(ctxt, (CollectionType) clt, beanDesc);
         }
         return factory.createCollectionLikeDeserializer(ctxt, clt, beanDesc);
       }
     }
   }
   if (JsonNode.class.isAssignableFrom(type.getRawClass())) {
     return factory.createTreeDeserializer(config, type, beanDesc);
   }
   return factory.createBeanDeserializer(ctxt, type, beanDesc);
 }