Exemplo n.º 1
0
 @Override
 public DateMidnight deserialize(JsonParser jp, DeserializationContext ctxt)
     throws IOException, JsonProcessingException {
   // We'll accept either long (timestamp) or array:
   if (jp.isExpectedStartArrayToken()) {
     jp.nextToken(); // VALUE_NUMBER_INT
     int year = jp.getIntValue();
     jp.nextToken(); // VALUE_NUMBER_INT
     int month = jp.getIntValue();
     jp.nextToken(); // VALUE_NUMBER_INT
     int day = jp.getIntValue();
     if (jp.nextToken() != JsonToken.END_ARRAY) {
       throw ctxt.wrongTokenException(jp, JsonToken.END_ARRAY, "after DateMidnight ints");
     }
     return new DateMidnight(year, month, day);
   }
   switch (jp.getCurrentToken()) {
     case VALUE_NUMBER_INT:
       return new DateMidnight(jp.getLongValue());
     case VALUE_STRING:
       DateTime local = parseLocal(jp);
       if (local == null) {
         return null;
       }
       return local.toDateMidnight();
   }
   throw ctxt.wrongTokenException(
       jp, JsonToken.START_ARRAY, "expected JSON Array, Number or String");
 }
 @Override
 public JsonDeserializer<Object> createBuilderBasedDeserializer(
     DeserializationContext ctxt,
     JavaType valueType,
     BeanDescription beanDesc,
     Class<?> builderClass)
     throws JsonMappingException {
   // First: need a BeanDescription for builder class
   JavaType builderType = ctxt.constructType(builderClass);
   BeanDescription builderDesc = ctxt.getConfig().introspectForBuilder(builderType);
   return buildBuilderBasedDeserializer(ctxt, valueType, builderDesc);
 }
  @Override
  public EnumMap<?, ?> deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException {
    // Ok: must point to START_OBJECT
    if (jp.getCurrentToken() != JsonToken.START_OBJECT) {
      return _deserializeFromEmpty(jp, ctxt);
    }
    EnumMap result = constructMap();
    final JsonDeserializer<Object> valueDes = _valueDeserializer;
    final TypeDeserializer typeDeser = _valueTypeDeserializer;

    while ((jp.nextToken()) == JsonToken.FIELD_NAME) {
      String keyName = jp.getCurrentName(); // just for error message
      // but we need to let key deserializer handle it separately, nonetheless
      Enum<?> key = (Enum<?>) _keyDeserializer.deserializeKey(keyName, ctxt);
      if (key == null) {
        if (!ctxt.isEnabled(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL)) {
          throw ctxt.weirdStringException(
              keyName,
              _enumClass,
              "value not one of declared Enum instance names for " + _mapType.getKeyType());
        }
        /* 24-Mar-2012, tatu: Null won't work as a key anyway, so let's
         *  just skip the entry then. But we must skip the value as well, if so.
         */
        jp.nextToken();
        jp.skipChildren();
        continue;
      }
      // And then the value...
      JsonToken t = jp.nextToken();
      /* note: MUST check for nulls separately: deserializers will
       * not handle them (and maybe fail or return bogus data)
       */
      Object value;

      try {
        if (t == JsonToken.VALUE_NULL) {
          value = valueDes.getNullValue(ctxt);
        } else if (typeDeser == null) {
          value = valueDes.deserialize(jp, ctxt);
        } else {
          value = valueDes.deserializeWithType(jp, ctxt, typeDeser);
        }
      } catch (Exception e) {
        wrapAndThrow(e, result, keyName);
        return null;
      }
      result.put(key, value);
    }
    return result;
  }
  /**
   * 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. */
  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;
  }
Exemplo n.º 6
0
    @Override
    public LocalDateTime deserialize(JsonParser jp, DeserializationContext ctxt)
        throws IOException, JsonProcessingException {
      // We'll accept either long (timestamp) or array:
      if (jp.isExpectedStartArrayToken()) {
        jp.nextToken(); // VALUE_NUMBER_INT
        int year = jp.getIntValue();
        jp.nextToken(); // VALUE_NUMBER_INT
        int month = jp.getIntValue();
        jp.nextToken(); // VALUE_NUMBER_INT
        int day = jp.getIntValue();
        jp.nextToken(); // VALUE_NUMBER_INT
        int hour = jp.getIntValue();
        jp.nextToken(); // VALUE_NUMBER_INT
        int minute = jp.getIntValue();
        jp.nextToken(); // VALUE_NUMBER_INT
        int second = jp.getIntValue();
        // let's leave milliseconds optional?
        int millisecond = 0;
        if (jp.nextToken() != JsonToken.END_ARRAY) { // VALUE_NUMBER_INT
          millisecond = jp.getIntValue();
          jp.nextToken(); // END_ARRAY?
        }
        if (jp.getCurrentToken() != JsonToken.END_ARRAY) {
          throw ctxt.wrongTokenException(jp, JsonToken.END_ARRAY, "after LocalDateTime ints");
        }
        return new LocalDateTime(year, month, day, hour, minute, second, millisecond);
      }

      switch (jp.getCurrentToken()) {
        case VALUE_NUMBER_INT:
          return new LocalDateTime(jp.getLongValue());
        case VALUE_STRING:
          DateTime local = parseLocal(jp);
          if (local == null) {
            return null;
          }
          return local.toLocalDateTime();
      }
      throw ctxt.wrongTokenException(jp, JsonToken.START_ARRAY, "expected JSON Array or Number");
    }
 @Override
 public Map<Object, Object> deserialize(
     JsonParser jp, DeserializationContext ctxt, Map<Object, Object> result)
     throws IOException, JsonProcessingException {
   // Ok: must point to START_OBJECT or FIELD_NAME
   JsonToken t = jp.getCurrentToken();
   if (t != JsonToken.START_OBJECT && t != JsonToken.FIELD_NAME) {
     throw ctxt.mappingException(getMapClass());
   }
   _readAndBind(jp, ctxt, result);
   return result;
 }
Exemplo n.º 8
0
 @Override
 public ReadablePeriod deserialize(JsonParser jp, DeserializationContext ctxt)
     throws IOException, JsonProcessingException {
   // TODO: perhaps support array of numbers...
   // if (jp.isExpectedStartArrayToken()) { ]
   switch (jp.getCurrentToken()) {
     case VALUE_NUMBER_INT: // assume it's millisecond count
       return new Period(jp.getLongValue());
     case VALUE_STRING:
       return new Period(jp.getText());
   }
   throw ctxt.wrongTokenException(jp, JsonToken.START_ARRAY, "expected JSON Number or String");
 }
  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));
  }
 /**
  * Method called to finalize setup of this deserializer, when it is known for which property
  * deserializer is needed for.
  */
 @Override
 public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property)
     throws JsonMappingException {
   // note: instead of finding key deserializer, with enums we actually
   // work with regular deserializers (less code duplication; but not
   // quite as clean as it ought to be)
   KeyDeserializer kd = _keyDeserializer;
   if (kd == null) {
     kd = ctxt.findKeyDeserializer(_mapType.getKeyType(), property);
   }
   JsonDeserializer<?> vd = _valueDeserializer;
   final JavaType vt = _mapType.getContentType();
   if (vd == null) {
     vd = ctxt.findContextualValueDeserializer(vt, property);
   } else { // if directly assigned, probably not yet contextual, so:
     vd = ctxt.handleSecondaryContextualization(vd, property, vt);
   }
   TypeDeserializer vtd = _valueTypeDeserializer;
   if (vtd != null) {
     vtd = vtd.forProperty(property);
   }
   return withResolved(kd, vd, vtd);
 }
 @Override
 public Map<Object, Object> deserialize(JsonParser jp, DeserializationContext ctxt)
     throws IOException, JsonProcessingException {
   // Ok: must point to START_OBJECT, or FIELD_NAME
   JsonToken t = jp.getCurrentToken();
   if (t != JsonToken.START_OBJECT && t != JsonToken.FIELD_NAME) {
     throw ctxt.mappingException(getMapClass());
   }
   if (_propertyBasedCreator != null) {
     return _deserializeUsingCreator(jp, ctxt);
   }
   Map<Object, Object> result;
   if (_defaultCtor == null) {
     throw ctxt.instantiationException(getMapClass(), "No default constructor found");
   }
   try {
     result = _defaultCtor.newInstance();
   } catch (Exception e) {
     throw ctxt.instantiationException(getMapClass(), e);
   }
   _readAndBind(jp, ctxt, result);
   return result;
 }
  /**
   * 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;
  }
Exemplo n.º 13
0
 @SuppressWarnings("unchecked")
 @Override
 public T deserialize(JsonParser jp, DeserializationContext ctxt)
     throws IOException, JsonProcessingException {
   JsonToken t = jp.getCurrentToken();
   if (t == JsonToken.VALUE_NUMBER_INT) {
     return (T) new DateTime(jp.getLongValue(), DateTimeZone.UTC);
   }
   if (t == JsonToken.VALUE_STRING) {
     String str = jp.getText().trim();
     if (str.length() == 0) { // [JACKSON-360]
       return null;
     }
     return (T) new DateTime(str, DateTimeZone.UTC);
   }
   throw ctxt.mappingException(getValueClass());
 }
  /**
   * 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 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 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 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());
     }
   }
 }
  /**
   * Helper method called to filter out explicit ignored properties, as well as properties that have
   * "ignorable types". Note that this will not remove properties that have no setters.
   */
  protected List<BeanPropertyDefinition> filterBeanProps(
      DeserializationContext ctxt,
      BeanDescription beanDesc,
      BeanDeserializerBuilder builder,
      List<BeanPropertyDefinition> propDefsIn,
      Set<String> ignored)
      throws JsonMappingException {
    ArrayList<BeanPropertyDefinition> result =
        new ArrayList<BeanPropertyDefinition>(Math.max(4, propDefsIn.size()));
    HashMap<Class<?>, Boolean> ignoredTypes = new HashMap<Class<?>, Boolean>();
    // These are all valid setters, but we do need to introspect bit more
    for (BeanPropertyDefinition property : propDefsIn) {
      String name = property.getName();
      if (ignored.contains(
          name)) { // explicit ignoral using @JsonIgnoreProperties needs to block entries
        continue;
      }
      if (!property.hasConstructorParameter()) { // never skip constructor params
        Class<?> rawPropertyType = null;
        if (property.hasSetter()) {
          rawPropertyType = property.getSetter().getRawParameterType(0);
        } else if (property.hasField()) {
          rawPropertyType = property.getField().getRawType();
        }

        // [JACKSON-429] Some types are declared as ignorable as well
        if ((rawPropertyType != null)
            && (isIgnorableType(ctxt.getConfig(), beanDesc, rawPropertyType, ignoredTypes))) {
          // important: make ignorable, to avoid errors if value is actually seen
          builder.addIgnorable(name);
          continue;
        }
      }
      result.add(property);
    }
    return result;
  }
  @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;
  }
 /**
  * Overridable method that constructs a {@link BeanDeserializerBuilder} which is used to
  * accumulate information needed to create deserializer instance.
  */
 protected BeanDeserializerBuilder constructBeanDeserializerBuilder(
     DeserializationContext ctxt, BeanDescription beanDesc) {
   return new BeanDeserializerBuilder(beanDesc, ctxt.getConfig());
 }
  /**
   * 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);
      }
    }
  }