/**
  * @param ignoredProperties (optional) names of properties to ignore; any fields that would be
  *     recognized as one of these properties is ignored.
  * @param forSerialization If true, will collect serializable property fields; if false,
  *     deserializable
  * @return Ordered Map with logical property name as key, and matching field as value.
  */
 public LinkedHashMap<String, AnnotatedField> _findPropertyFields(
     Collection<String> ignoredProperties, boolean forSerialization) {
   LinkedHashMap<String, AnnotatedField> results = new LinkedHashMap<String, AnnotatedField>();
   for (BeanPropertyDefinition property : _properties) {
     AnnotatedField f = property.getField();
     if (f != null) {
       String name = property.getName();
       if (ignoredProperties != null) {
         if (ignoredProperties.contains(name)) {
           continue;
         }
       }
       results.put(name, f);
     }
   }
   return results;
 }
  /**
   * 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;
  }
  /**
   * 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);
      }
    }
  }