public void testJackson744() throws Exception {
   BeanDescription beanDesc =
       mapper.getDeserializationConfig().introspect(mapper.constructType(Issue744Bean.class));
   assertNotNull(beanDesc);
   AnnotatedMethod setter = beanDesc.findAnySetter();
   assertNotNull(setter);
 }
  /** 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;
  }
  /**
   * Method called to construct fallback {@link SettableAnyProperty} for handling unknown bean
   * properties, given a method that has been designated as such setter.
   */
  protected SettableAnyProperty constructAnySetter(
      DeserializationContext ctxt, BeanDescription beanDesc, AnnotatedMethod setter)
      throws JsonMappingException {
    if (ctxt.canOverrideAccessModifiers()) {
      setter.fixAccess(); // to ensure we can call it
    }
    // we know it's a 2-arg method, second arg is the value
    JavaType type = beanDesc.bindingsForBeanType().resolveType(setter.getGenericParameterType(1));
    BeanProperty.Std property =
        new BeanProperty.Std(setter.getName(), type, beanDesc.getClassAnnotations(), setter);
    type = resolveType(ctxt, beanDesc, type, setter);

    /* AnySetter can be annotated with @JsonClass (etc) just like a
     * regular setter... so let's see if those are used.
     * Returns null if no annotations, in which case binding will
     * be done at a later point.
     */
    JsonDeserializer<Object> deser = findDeserializerFromAnnotation(ctxt, setter);
    if (deser != null) {
      return new SettableAnyProperty(property, setter, type, deser);
    }
    /* Otherwise, method may specify more specific (sub-)class for
     * value (no need to check if explicit deser was specified):
     */
    type = modifyTypeByAnnotation(ctxt, setter, type);
    return new SettableAnyProperty(property, setter, type, null);
  }
  /**
   * 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;
  }
 /**
  * Helper method that will check whether given raw type is marked as always ignorable (for purpose
  * of ignoring properties with type)
  */
 protected boolean isIgnorableType(
     DeserializationConfig config,
     BeanDescription beanDesc,
     Class<?> type,
     Map<Class<?>, Boolean> ignoredTypes) {
   Boolean status = ignoredTypes.get(type);
   if (status == null) {
     BeanDescription desc = config.introspectClassAnnotations(type);
     status = config.getAnnotationIntrospector().isIgnorableType(desc.getClassInfo());
     // We default to 'false', ie. not ignorable
     if (status == null) {
       status = Boolean.FALSE;
     }
   }
   return status;
 }
  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 for constructing a bean deserializer that uses specified intermediate Builder for
   * binding data, and construction of the value instance. Note that implementation is mostly copied
   * from the regular BeanDeserializer build method.
   */
  @SuppressWarnings("unchecked")
  protected JsonDeserializer<Object> buildBuilderBasedDeserializer(
      DeserializationContext ctxt, JavaType valueType, BeanDescription builderDesc)
      throws JsonMappingException {
    // Creators, anyone? (to create builder itself)
    ValueInstantiator valueInstantiator = findValueInstantiator(ctxt, builderDesc);
    final DeserializationConfig config = ctxt.getConfig();
    BeanDeserializerBuilder builder = constructBeanDeserializerBuilder(ctxt, builderDesc);
    builder.setValueInstantiator(valueInstantiator);
    // And then "with methods" for deserializing from JSON Object
    addBeanProps(ctxt, builderDesc, builder);
    addObjectIdReader(ctxt, builderDesc, builder);

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

    JsonPOJOBuilder.Value builderConfig = builderDesc.findPOJOBuilderConfig();
    final String buildMethodName =
        (builderConfig == null) ? "build" : builderConfig.buildMethodName;

    // and lastly, find build method to use:
    AnnotatedMethod buildMethod = builderDesc.findMethod(buildMethodName, null);
    if (buildMethod != null) { // note: can't yet throw error; may be given build method
      if (config.canOverrideAccessModifiers()) {
        ClassUtil.checkAndFixAccess(buildMethod.getMember());
      }
    }
    builder.setPOJOBuilder(buildMethod, builderConfig);
    // this may give us more information...
    if (_factoryConfig.hasDeserializerModifiers()) {
      for (BeanDeserializerModifier mod : _factoryConfig.deserializerModifiers()) {
        builder = mod.updateBuilder(config, builderDesc, builder);
      }
    }
    JsonDeserializer<?> deserializer = builder.buildBuilderBased(valueType, buildMethodName);

    // [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, builderDesc, deserializer);
      }
    }
    return (JsonDeserializer<Object>) deserializer;
  }
 /**
  * Method called locate all members used for value injection (if any), constructor {@link
  * com.fasterxml.jackson.databind.deser.impl.ValueInjector} instances, and add them to builder.
  */
 protected void addInjectables(
     DeserializationContext ctxt, BeanDescription beanDesc, BeanDeserializerBuilder builder)
     throws JsonMappingException {
   Map<Object, AnnotatedMember> raw = beanDesc.findInjectables();
   if (raw != null) {
     boolean fixAccess = ctxt.canOverrideAccessModifiers();
     for (Map.Entry<Object, AnnotatedMember> entry : raw.entrySet()) {
       AnnotatedMember m = entry.getValue();
       if (fixAccess) {
         m.fixAccess(); // to ensure we can call it
       }
       builder.addInjectable(
           m.getName(),
           beanDesc.resolveType(m.getGenericType()),
           beanDesc.getClassAnnotations(),
           m,
           entry.getKey());
     }
   }
 }
  /**
   * 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 void addObjectIdReader(
      DeserializationContext ctxt, BeanDescription beanDesc, BeanDeserializerBuilder builder)
      throws JsonMappingException {
    ObjectIdInfo objectIdInfo = beanDesc.getObjectIdInfo();
    if (objectIdInfo == null) {
      return;
    }
    Class<?> implClass = objectIdInfo.getGeneratorType();
    JavaType idType;
    SettableBeanProperty idProp;
    ObjectIdGenerator<?> gen;

    // Just one special case: Property-based generator is trickier
    if (implClass
        == ObjectIdGenerators.PropertyGenerator.class) { // most special one, needs extra work
      String propName = objectIdInfo.getPropertyName();
      idProp = builder.findProperty(propName);
      if (idProp == null) {
        throw new IllegalArgumentException(
            "Invalid Object Id definition for "
                + beanDesc.getBeanClass().getName()
                + ": can not find property with name '"
                + propName
                + "'");
      }
      idType = idProp.getType();
      gen = new PropertyBasedObjectIdGenerator(objectIdInfo.getScope());
    } else {
      JavaType type = ctxt.constructType(implClass);
      idType = ctxt.getTypeFactory().findTypeParameters(type, ObjectIdGenerator.class)[0];
      idProp = null;
      gen = ctxt.objectIdGeneratorInstance(beanDesc.getClassInfo(), objectIdInfo);
    }
    // also: unlike with value deserializers, let's just resolve one we need here
    JsonDeserializer<?> deser = ctxt.findRootValueDeserializer(idType);
    builder.setObjectIdReader(
        ObjectIdReader.construct(idType, objectIdInfo.getPropertyName(), gen, deser, idProp));
  }
  protected JavaType materializeAbstractType(DeserializationConfig config, BeanDescription beanDesc)
      throws JsonMappingException {
    final JavaType abstractType = beanDesc.getType();

    /* [JACKSON-502] (1.8): Now it is possible to have multiple resolvers too,
     *   as they are registered via module interface.
     */
    for (AbstractTypeResolver r : _factoryConfig.abstractTypeResolvers()) {
      JavaType concrete = r.resolveAbstractType(config, abstractType);
      if (concrete != null) {
        return concrete;
      }
    }
    return null;
  }
 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);
 }
 /**
  * Method that will find if bean has any managed- or back-reference properties, and if so add them
  * to bean, to be linked during resolution phase.
  */
 protected void addReferenceProperties(
     DeserializationContext ctxt, BeanDescription beanDesc, BeanDeserializerBuilder builder)
     throws JsonMappingException {
   // and then back references, not necessarily found as regular properties
   Map<String, AnnotatedMember> refs = beanDesc.findBackReferenceProperties();
   if (refs != null) {
     for (Map.Entry<String, AnnotatedMember> en : refs.entrySet()) {
       String name = en.getKey();
       AnnotatedMember m = en.getValue();
       Type genericType;
       if (m instanceof AnnotatedMethod) {
         genericType = ((AnnotatedMethod) m).getGenericParameterType(0);
       } else {
         genericType = m.getRawType();
       }
       SimpleBeanPropertyDefinition propDef = new SimpleBeanPropertyDefinition(m);
       builder.addBackReferenceProperty(
           name, constructSettableProperty(ctxt, beanDesc, propDef, genericType));
     }
   }
 }
  /**
   * Method called to figure out settable properties for the bean deserializer to use.
   *
   * <p>Note: designed to be overridable, and effort is made to keep interface similar between
   * versions.
   */
  protected void addBeanProps(
      DeserializationContext ctxt, BeanDescription beanDesc, BeanDeserializerBuilder builder)
      throws JsonMappingException {
    final SettableBeanProperty[] creatorProps =
        builder.getValueInstantiator().getFromObjectArguments(ctxt.getConfig());

    // Things specified as "ok to ignore"? [JACKSON-77]
    AnnotationIntrospector intr = ctxt.getAnnotationIntrospector();
    boolean ignoreAny = false;
    {
      Boolean B = intr.findIgnoreUnknownProperties(beanDesc.getClassInfo());
      if (B != null) {
        ignoreAny = B.booleanValue();
        builder.setIgnoreUnknownProperties(ignoreAny);
      }
    }
    // Or explicit/implicit definitions?
    Set<String> ignored =
        ArrayBuilders.arrayToSet(intr.findPropertiesToIgnore(beanDesc.getClassInfo()));
    for (String propName : ignored) {
      builder.addIgnorable(propName);
    }
    // Also, do we have a fallback "any" setter?
    AnnotatedMethod anySetter = beanDesc.findAnySetter();
    if (anySetter != null) {
      builder.setAnySetter(constructAnySetter(ctxt, beanDesc, anySetter));
    }
    // NOTE: we do NOT add @JsonIgnore'd properties into blocked ones if there's any setter
    // Implicit ones via @JsonIgnore and equivalent?
    if (anySetter == null) {
      Collection<String> ignored2 = beanDesc.getIgnoredPropertyNames();
      if (ignored2 != null) {
        for (String propName : ignored2) {
          // allow ignoral of similarly named JSON property, but do not force;
          // latter means NOT adding this to 'ignored':
          builder.addIgnorable(propName);
        }
      }
    }
    final boolean useGettersAsSetters =
        (ctxt.isEnabled(MapperFeature.USE_GETTERS_AS_SETTERS)
            && ctxt.isEnabled(MapperFeature.AUTO_DETECT_GETTERS));

    // Ok: let's then filter out property definitions
    List<BeanPropertyDefinition> propDefs =
        filterBeanProps(ctxt, beanDesc, builder, beanDesc.findProperties(), ignored);

    // After which we can let custom code change the set
    if (_factoryConfig.hasDeserializerModifiers()) {
      for (BeanDeserializerModifier mod : _factoryConfig.deserializerModifiers()) {
        propDefs = mod.updateProperties(ctxt.getConfig(), beanDesc, propDefs);
      }
    }

    // At which point we still have all kinds of properties; not all with mutators:
    for (BeanPropertyDefinition propDef : propDefs) {
      SettableBeanProperty prop = null;
      if (propDef.hasConstructorParameter()) {
        /* [JACKSON-700] If property is passed via constructor parameter, we must
         *   handle things in special way. Not sure what is the most optimal way...
         *   for now, let's just call a (new) method in builder, which does nothing.
         */
        // but let's call a method just to allow custom builders to be aware...
        final String name = propDef.getName();
        for (SettableBeanProperty cp : creatorProps) {
          if (name.equals(cp.getName())) {
            prop = cp;
            break;
          }
        }
        if (prop == null) {
          throw ctxt.mappingException("Could not find creator property with name '" + name + "'");
        }
        builder.addCreatorProperty(prop);
        continue;
      }
      if (propDef.hasSetter()) {
        Type propertyType = propDef.getSetter().getGenericParameterType(0);
        prop = constructSettableProperty(ctxt, beanDesc, propDef, propertyType);
      } else if (propDef.hasField()) {
        Type propertyType = propDef.getField().getGenericType();
        prop = constructSettableProperty(ctxt, beanDesc, propDef, propertyType);
      } else if (useGettersAsSetters && propDef.hasGetter()) {
        /* As per [JACKSON-88], may also need to consider getters
         * for Map/Collection properties; but with lowest precedence
         */
        AnnotatedMethod getter = propDef.getGetter();
        // should only consider Collections and Maps, for now?
        Class<?> rawPropertyType = getter.getRawType();
        if (Collection.class.isAssignableFrom(rawPropertyType)
            || Map.class.isAssignableFrom(rawPropertyType)) {
          prop = constructSetterlessProperty(ctxt, beanDesc, propDef);
        }
      }
      if (prop != null) {
        Class<?>[] views = propDef.findViews();
        if (views == null) {
          // one more twist: if default inclusion disabled, need to force empty set of views
          if (!ctxt.isEnabled(MapperFeature.DEFAULT_VIEW_INCLUSION)) {
            views = NO_VIEWS;
          }
        }
        // one more thing before adding to builder: copy any metadata
        prop.setViews(views);
        builder.addProperty(prop);
      }
    }
  }
  @SuppressWarnings("unchecked")
  public JsonDeserializer<Object> buildThrowableDeserializer(
      DeserializationContext ctxt, JavaType type, BeanDescription beanDesc)
      throws JsonMappingException {
    final DeserializationConfig config = ctxt.getConfig();
    // first: construct like a regular bean deserializer...
    BeanDeserializerBuilder builder = constructBeanDeserializerBuilder(ctxt, beanDesc);
    builder.setValueInstantiator(findValueInstantiator(ctxt, beanDesc));

    addBeanProps(ctxt, beanDesc, builder);
    // (and assume there won't be any back references)

    // But then let's decorate things a bit
    /* To resolve [JACKSON-95], need to add "initCause" as setter
     * for exceptions (sub-classes of Throwable).
     */
    AnnotatedMethod am = beanDesc.findMethod("initCause", INIT_CAUSE_PARAMS);
    if (am != null) { // should never be null
      SimpleBeanPropertyDefinition propDef = new SimpleBeanPropertyDefinition(am, "cause");
      SettableBeanProperty prop =
          constructSettableProperty(ctxt, beanDesc, propDef, am.getGenericParameterType(0));
      if (prop != null) {
        /* 21-Aug-2011, tatus: We may actually have found 'cause' property
         *   to set (with new 1.9 code)... but let's replace it just in case,
         *   otherwise can end up with odd errors.
         */
        builder.addOrReplaceProperty(prop, true);
      }
    }

    // And also need to ignore "localizedMessage"
    builder.addIgnorable("localizedMessage");
    // [JACKSON-794]: JDK 7 also added "getSuppressed", skip if we have such data:
    builder.addIgnorable("suppressed");
    /* As well as "message": it will be passed via constructor,
     * as there's no 'setMessage()' method
     */
    builder.addIgnorable("message");

    // [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 = builder.build();

    /* At this point it ought to be a BeanDeserializer; if not, must assume
     * it's some other thing that can handle deserialization ok...
     */
    if (deserializer instanceof BeanDeserializer) {
      deserializer = new ThrowableDeserializer((BeanDeserializer) deserializer);
    }

    // [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;
  }
 private void _verifyProperty(BeanDescription beanDesc, boolean verifyDesc, boolean verifyIndex) {
   assertNotNull(beanDesc);
   List<BeanPropertyDefinition> props = beanDesc.findProperties();
   assertEquals(2, props.size());
   for (BeanPropertyDefinition prop : props) {
     String name = prop.getName();
     final PropertyMetadata md = prop.getMetadata();
     if ("a".equals(name)) {
       assertFalse(md.isRequired());
       assertNull(md.getRequired());
       if (verifyDesc) {
         assertEquals(PropDescBean.A_DESC, md.getDescription());
       }
       if (verifyIndex) {
         assertNull(md.getIndex());
       }
     } else if ("b".equals(name)) {
       assertTrue(md.isRequired());
       assertEquals(Boolean.TRUE, md.getRequired());
       if (verifyDesc) {
         assertNull(md.getDescription());
       }
       if (verifyIndex) {
         assertEquals(Integer.valueOf(PropDescBean.B_INDEX), md.getIndex());
       }
     } else {
       fail("Unrecognized property '" + name + "'");
     }
   }
 }