/**
   * 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;
  }
  private static List<MediaType> resolveProducedTypes(
      final AnnotatedMethod am, final List<MediaType> defaultProducedTypes) {
    // Override default types if the annotation is present on the method
    if (am.isAnnotationPresent(Produces.class)) {
      return extractMediaTypes(am.getAnnotation(Produces.class));
    }

    return defaultProducedTypes;
  }
  /**
   * Method for resolving member method information: aggregating all non-static methods and
   * combining annotations (to implement method-annotation inheritance)
   *
   * @param collectIgnored Whether to collect list of ignored methods for later retrieval
   */
  public void resolveMemberMethods(MethodFilter methodFilter, boolean collectIgnored) {
    _memberMethods = new AnnotatedMethodMap();
    AnnotatedMethodMap mixins = new AnnotatedMethodMap();
    // first: methods from the class itself
    _addMemberMethods(_class, methodFilter, _memberMethods, _primaryMixIn, mixins);

    // and then augment these with annotations from super-types:
    for (Class<?> cls : _superTypes) {
      Class<?> mixin = (_mixInResolver == null) ? null : _mixInResolver.findMixInClassFor(cls);
      _addMemberMethods(cls, methodFilter, _memberMethods, mixin, mixins);
    }
    // Special case: mix-ins for Object.class? (to apply to ALL classes)
    if (_mixInResolver != null) {
      Class<?> mixin = _mixInResolver.findMixInClassFor(Object.class);
      if (mixin != null) {
        _addMethodMixIns(methodFilter, _memberMethods, mixin, mixins);
      }
    }

    /* Any unmatched mix-ins? Most likely error cases (not matching
     * any method); but there is one possible real use case:
     * exposing Object#hashCode (alas, Object#getClass can NOT be
     * exposed, see [JACKSON-140])
     */
    if (!mixins.isEmpty()) {
      Iterator<AnnotatedMethod> it = mixins.iterator();
      while (it.hasNext()) {
        AnnotatedMethod mixIn = it.next();
        try {
          Method m = Object.class.getDeclaredMethod(mixIn.getName(), mixIn.getParameterClasses());
          if (m != null) {
            AnnotatedMethod am = _constructMethod(m);
            _addMixOvers(mixIn.getAnnotated(), am, false);
            _memberMethods.add(am);
          }
        } catch (Exception e) {
        }
      }
    }

    /* And last but not least: let's remove all methods that are
     * deemed to be ignorable after all annotations have been
     * properly collapsed.
     */
    Iterator<AnnotatedMethod> it = _memberMethods.iterator();
    while (it.hasNext()) {
      AnnotatedMethod am = it.next();
      if (_annotationIntrospector.isIgnorableMethod(am)) {
        it.remove();
        if (collectIgnored) {
          _ignoredMethods = ArrayBuilders.addToList(_ignoredMethods, am);
        }
      }
    }
  }
  private void addSubResourceMethods(
      final Resource.Builder resourceBuilder,
      final MethodList methodList,
      final boolean encodedParameters,
      final List<MediaType> defaultConsumedTypes,
      final List<MediaType> defaultProducedTypes,
      final Collection<Class<? extends Annotation>> defaultNameBindings,
      final boolean extended) {

    for (AnnotatedMethod am :
        methodList.withMetaAnnotation(HttpMethod.class).withAnnotation(Path.class)) {
      Resource.Builder childResourceBuilder =
          resourceBuilder.addChildResource(am.getAnnotation(Path.class).value());

      ResourceMethod.Builder methodBuilder =
          childResourceBuilder
              .addMethod(am.getMetaMethodAnnotations(HttpMethod.class).get(0).value())
              .consumes(resolveConsumedTypes(am, defaultConsumedTypes))
              .produces(resolveProducedTypes(am, defaultProducedTypes))
              .encodedParameters(encodedParameters || am.isAnnotationPresent(Encoded.class))
              .nameBindings(defaultNameBindings)
              .nameBindings(am.getAnnotations())
              .handledBy(handlerClass, am.getMethod())
              .handlingMethod(am.getDeclaredMethod())
              .extended(extended || am.isAnnotationPresent(ExtendedResource.class));

      introspectAsyncFeatures(am, methodBuilder);
    }
  }
 /** @param addParamAnnotations Whether parameter annotations are to be added as well */
 protected void _addMixOvers(Method mixin, AnnotatedMethod target, boolean addParamAnnotations) {
   for (Annotation a : mixin.getDeclaredAnnotations()) {
     if (_annotationIntrospector.isHandled(a)) {
       target.addOrOverride(a);
     }
   }
   if (addParamAnnotations) {
     Annotation[][] pa = mixin.getParameterAnnotations();
     for (int i = 0, len = pa.length; i < len; ++i) {
       for (Annotation a : pa[i]) {
         target.addOrOverrideParam(i, a);
       }
     }
   }
 }
  private static void introspectAsyncFeatures(
      AnnotatedMethod am, ResourceMethod.Builder resourceMethodBuilder) {
    if (am.isAnnotationPresent(ManagedAsync.class)) {
      resourceMethodBuilder.managedAsync();
    }

    for (Annotation[] annotations : am.getParameterAnnotations()) {
      for (Annotation annotation : annotations) {
        if (annotation.annotationType() == Suspended.class) {
          resourceMethodBuilder.suspended(AsyncResponse.NO_TIMEOUT, TimeUnit.MILLISECONDS);
          return;
        }
      }
    }
  }
 /**
  * Method that can be called to find if introspected class declares a static "valueOf" factory
  * method that returns an instance of introspected type, given one of acceptable types.
  *
  * @param expArgTypes Types that the matching single argument factory method can take: will also
  *     accept super types of these types (ie. arg just has to be assignable from expArgType)
  */
 public Method findFactoryMethod(Class<?>... expArgTypes) {
   // So, of all single-arg static methods:
   for (AnnotatedMethod am : _classInfo.getStaticMethods()) {
     if (isFactoryMethod(am)) {
       // And must take one of expected arg types (or supertype)
       Class<?> actualArgType = am.getParameterClass(0);
       for (Class<?> expArgType : expArgTypes) {
         // And one that matches what we would pass in
         if (actualArgType.isAssignableFrom(expArgType)) {
           return am.getAnnotated();
         }
       }
     }
   }
   return null;
 }
 /**
  * Method used to locate the method of introspected class that implements {@link
  * sh.calaba.org.codehaus.jackson.annotate.JsonAnyGetter}. If no such method exists null is
  * returned. If more than one are found, an exception is thrown.
  *
  * @since 1.6
  */
 @Override
 public AnnotatedMethod findAnyGetter() throws IllegalArgumentException {
   if (_anyGetterMethod != null) {
     /* For now let's require a Map; in future can add support for other
      * types like perhaps Iterable<Map.Entry>?
      */
     Class<?> type = _anyGetterMethod.getRawType();
     if (!Map.class.isAssignableFrom(type)) {
       throw new IllegalArgumentException(
           "Invalid 'any-getter' annotation on method "
               + _anyGetterMethod.getName()
               + "(): return type is not instance of java.util.Map");
     }
   }
   return _anyGetterMethod;
 }
 /**
  * Method that will add annotations from specified source method to target method, but only if
  * target does not yet have them.
  */
 protected void _addMixUnders(Method src, AnnotatedMethod target) {
   for (Annotation a : src.getDeclaredAnnotations()) {
     if (_annotationIntrospector.isHandled(a)) {
       target.addIfNotPresent(a);
     }
   }
 }
  protected void _addMemberMethods(
      Class<?> cls,
      MethodFilter methodFilter,
      AnnotatedMethodMap methods,
      Class<?> mixInCls,
      AnnotatedMethodMap mixIns) {
    // first, mixIns, since they have higher priority then class methods
    if (mixInCls != null) {
      _addMethodMixIns(methodFilter, methods, mixInCls, mixIns);
    }

    if (cls == null) { // just so caller need not check when passing super-class
      return;
    }
    // then methods from the class itself
    for (Method m : cls.getDeclaredMethods()) {
      if (!_isIncludableMethod(m, methodFilter)) {
        continue;
      }
      AnnotatedMethod old = methods.find(m);
      if (old == null) {
        AnnotatedMethod newM = _constructMethod(m);
        methods.add(newM);
        // Ok, but is there a mix-in to connect now?
        old = mixIns.remove(m);
        if (old != null) {
          _addMixOvers(old.getAnnotated(), newM, false);
        }
      } else {
        /* If sub-class already has the method, we only want to augment
         * annotations with entries that are not masked by sub-class.
         */
        _addMixUnders(m, old);

        /* 06-Jan-2010, tatu: [JACKSON-450] Except that if method we saw first is
         *   from an interface, and we now find a non-interface definition, we should
         *   use this method, but with combination of annotations.
         *   This helps (or rather, is essential) with JAXB annotations and
         *   may also result in faster method calls (interface calls are slightly
         *   costlier than regular method calls)
         */
        if (old.getDeclaringClass().isInterface() && !m.getDeclaringClass().isInterface()) {
          methods.add(old.withMethod(m));
        }
      }
    }
  }
 private void checkResourceClassSetters(final MethodList methodList, final boolean encodedFlag) {
   for (AnnotatedMethod method :
       methodList
           .withoutMetaAnnotation(HttpMethod.class)
           .withoutAnnotation(Path.class)
           .hasNumParams(1)
           .hasReturnType(void.class)
           .nameStartsWith("set")) {
     Parameter p =
         Parameter.create(
             handlerClass,
             method.getMethod().getDeclaringClass(),
             encodedFlag || method.isAnnotationPresent(Encoded.class),
             method.getParameterTypes()[0],
             method.getGenericParameterTypes()[0],
             method.getAnnotations());
     if (null != p) {
       ResourceMethodValidator.validateParameter(
           p,
           method.getMethod(),
           method.getMethod().toGenericString(),
           "1",
           InvocableValidator.isSingleton(handlerClass));
     }
   }
 }
  /**
   * 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;
  }
        @Override
        public int compare(AnnotatedMethod m1, AnnotatedMethod m2) {

          int o1 = m1.getApplicablTestMethodsAndOrder().getOrder();
          int o2 = m2.getApplicablTestMethodsAndOrder().getOrder();

          if (o1 > 0) {
            if (o2 > 0) {
              return o1 - o2;
            } else {
              // explicitly ordered stuff always precedes the unordered
              return -1;
            }
          } else {
            // explicitly ordered stuff always precedes the unordered
            return o2 > 0 ? 1 : 0;
          }
        }
  private List<Method> filterAndOrderMethods(
      String targetTestMethodName, Method[] beforeDiscoveryMethods) {
    List<AnnotatedMethod> ordered =
        new ArrayList<AbstractAroundDiscoveryExecutor.AnnotatedMethod>(
            beforeDiscoveryMethods.length);

    for (int i = 0; i < beforeDiscoveryMethods.length; ++i) {
      T annotation = beforeDiscoveryMethods[i].getAnnotation(annotationClass);
      ApplicableTestMethodsAndOrder o = getApplicableTestMethodsAndOrder(annotation);

      AnnotatedMethod m = new AnnotatedMethod(beforeDiscoveryMethods[i], o);

      ordered.add(m);
    }

    Iterator<AnnotatedMethod> it = ordered.iterator();

    // filter
    while (it.hasNext()) {
      AnnotatedMethod m = it.next();

      String[] applicableTestMethodNames =
          m.getApplicablTestMethodsAndOrder().getApplicableTestMethodNames();

      if (applicableTestMethodNames.length > 0
          && !Arrays.asList(applicableTestMethodNames).contains(targetTestMethodName)) {

        it.remove();
      }
    }

    // order
    Collections.sort(ordered, ORDERING);

    // convert to List<Method>

    List<Method> ret = new ArrayList<Method>(ordered.size());

    for (AnnotatedMethod m : ordered) {
      ret.add(m.getTestMethod());
    }

    return ret;
  }
  private void checkForNonPublicMethodIssues() {
    final MethodList allDeclaredMethods = new MethodList(getAllDeclaredMethods(handlerClass));

    // non-public resource methods
    for (AnnotatedMethod m :
        allDeclaredMethods
            .withMetaAnnotation(HttpMethod.class)
            .withoutAnnotation(Path.class)
            .isNotPublic()) {
      Errors.warning(
          handlerClass, LocalizationMessages.NON_PUB_RES_METHOD(m.getMethod().toGenericString()));
    }
    // non-public subres methods
    for (AnnotatedMethod m :
        allDeclaredMethods
            .withMetaAnnotation(HttpMethod.class)
            .withAnnotation(Path.class)
            .isNotPublic()) {
      Errors.warning(
          handlerClass,
          LocalizationMessages.NON_PUB_SUB_RES_METHOD(m.getMethod().toGenericString()));
    }
    // non-public subres locators
    for (AnnotatedMethod m :
        allDeclaredMethods
            .withoutMetaAnnotation(HttpMethod.class)
            .withAnnotation(Path.class)
            .isNotPublic()) {
      Errors.warning(
          handlerClass, LocalizationMessages.NON_PUB_SUB_RES_LOC(m.getMethod().toGenericString()));
    }
  }
  protected boolean isFactoryMethod(AnnotatedMethod am) {
    /* First: return type must be compatible with the introspected class
     * (i.e. allowed to be sub-class, although usually is the same
     * class)
     */
    Class<?> rt = am.getRawType();
    if (!getBeanClass().isAssignableFrom(rt)) {
      return false;
    }

    /* Also: must be a recognized factory method, meaning:
     * (a) marked with @JsonCreator annotation, or
     * (a) "valueOf" (at this point, need not be public)
     */
    if (_annotationIntrospector.hasCreatorAnnotation(am)) {
      return true;
    }
    if ("valueOf".equals(am.getName())) {
      return true;
    }
    return false;
  }
 /**
  * Method used to locate the method of introspected class that implements {@link
  * sh.calaba.org.codehaus.jackson.annotate.JsonAnySetter}. If no such method exists null is
  * returned. If more than one are found, an exception is thrown. Additional checks are also made
  * to see that method signature is acceptable: needs to take 2 arguments, first one String or
  * Object; second any can be any type.
  */
 @Override
 public AnnotatedMethod findAnySetter() throws IllegalArgumentException {
   if (_anySetterMethod != null) {
     /* Also, let's be somewhat strict on how field name is to be
      * passed; String, Object make sense, others not
      * so much.
      */
     /* !!! 18-May-2009, tatu: how about enums? Can add support if
      *  requested; easy enough for devs to add support within
      *  method.
      */
     Class<?> type = _anySetterMethod.getParameterClass(0);
     if (type != String.class && type != Object.class) {
       throw new IllegalArgumentException(
           "Invalid 'any-setter' annotation on method "
               + _anySetterMethod.getName()
               + "(): first argument not of type String or Object, but "
               + type.getName());
     }
   }
   return _anySetterMethod;
 }
 @Override
 public Object findInjectableValueId(AnnotatedMember m) {
   JacksonInject ann = _findAnnotation(m, JacksonInject.class);
   if (ann == null) {
     return null;
   }
   /* Empty String means that we should use name of declared
    * value class.
    */
   String id = ann.value();
   if (id.length() == 0) {
     // slight complication; for setters, type
     if (!(m instanceof AnnotatedMethod)) {
       return m.getRawType().getName();
     }
     AnnotatedMethod am = (AnnotatedMethod) m;
     if (am.getParameterCount() == 0) {
       return m.getRawType().getName();
     }
     return am.getRawParameterType(0).getName();
   }
   return id;
 }
  private void addSubResourceLocators(
      Resource.Builder resourceBuilder,
      MethodList methodList,
      boolean encodedParameters,
      final boolean extended) {

    for (AnnotatedMethod am :
        methodList.withoutMetaAnnotation(HttpMethod.class).withAnnotation(Path.class)) {
      final String path = am.getAnnotation(Path.class).value();
      Resource.Builder builder = resourceBuilder;
      if (path != null && !path.isEmpty() && !path.equals("/")) {
        builder = resourceBuilder.addChildResource(path);
      }

      builder
          .addMethod()
          .encodedParameters(encodedParameters || am.isAnnotationPresent(Encoded.class))
          .handledBy(handlerClass, am.getMethod())
          .handlingMethod(am.getDeclaredMethod())
          .extended(extended || am.isAnnotationPresent(ExtendedResource.class));
    }
  }
  @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;
  }
  /**
   * 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);
      }
    }
  }