public static List findAllSetters()

in xbean-reflect/src/main/java/org/apache/xbean/recipe/ReflectionUtil.java [254:405]


    public static List<Method> findAllSetters(Class typeClass, String propertyName, Object propertyValue, Set<Option> options,
                                              PropertyEditorRegistry registry) {
        if (typeClass == null) throw new NullPointerException("typeClass is null");
        if (propertyName == null) throw new NullPointerException("name is null");
        if (propertyName.length() == 0) throw new IllegalArgumentException("name is an empty string");
        if (options == null) options = EnumSet.noneOf(Option.class);

        if (propertyName.contains("/")){
            String[] strings = propertyName.split("/");
            if (strings == null || strings.length != 2) throw new IllegalArgumentException("badly formed <class>/<attribute> property name: " + propertyName);

            String className = strings[0];
            propertyName = strings[1];

            boolean found = false;
            while(!typeClass.equals(Object.class) && !found){
                if (typeClass.getName().equals(className)){
                    found = true;
                    break;
                } else {
                    typeClass = typeClass.getSuperclass();
                }
            }

            if (!found) throw new MissingAccessorException("Type not assignable to class: " + className, -1);
        }

        String setterName = "set" + Character.toUpperCase(propertyName.charAt(0));
        if (propertyName.length() > 0) {
            setterName += propertyName.substring(1);
        }


        int matchLevel = 0;
        MissingAccessorException missException = null;

        boolean allowPrivate = options.contains(Option.PRIVATE_PROPERTIES);
        boolean allowStatic = options.contains(Option.STATIC_PROPERTIES);
        boolean caseInsesnitive = options.contains(Option.CASE_INSENSITIVE_PROPERTIES);


        LinkedList<Method> validSetters = new LinkedList<Method>();

        List<Method> methods = new ArrayList<Method>(Arrays.asList(typeClass.getMethods()));
        methods.addAll(Arrays.asList(typeClass.getDeclaredMethods()));
        for (Method method : methods) {
            if (method.getName().equals(setterName) || (caseInsesnitive && method.getName().equalsIgnoreCase(setterName))) {
                if (method.getParameterTypes().length == 0) {
                    if (matchLevel < 1) {
                        matchLevel = 1;
                        missException = new MissingAccessorException("Setter takes no parameters: " + method, matchLevel);
                    }
                    continue;
                }

                if (method.getParameterTypes().length > 1) {
                    if (matchLevel < 1) {
                        matchLevel = 1;
                        missException = new MissingAccessorException("Setter takes more then one parameter: " + method, matchLevel);
                    }
                    continue;
                }

                if (method.getReturnType() != Void.TYPE) {
                    if (matchLevel < 2) {
                        matchLevel = 2;
                        missException = new MissingAccessorException("Setter returns a value: " + method, matchLevel);
                    }
                    continue;
                }

                if (Modifier.isAbstract(method.getModifiers())) {
                    if (matchLevel < 3) {
                        matchLevel = 3;
                        missException = new MissingAccessorException("Setter is abstract: " + method, matchLevel);
                    }
                    continue;
                }

                if (!allowPrivate && !Modifier.isPublic(method.getModifiers())) {
                    if (matchLevel < 4) {
                        matchLevel = 4;
                        missException = new MissingAccessorException("Setter is not public: " + method, matchLevel);
                    }
                    continue;
                }

                if (!allowStatic && Modifier.isStatic(method.getModifiers())) {
                    if (matchLevel < 4) {
                        matchLevel = 4;
                        missException = new MissingAccessorException("Setter is static: " + method, matchLevel);
                    }
                    continue;
                }

                Class methodParameterType = method.getParameterTypes()[0];
                if (methodParameterType.isPrimitive() && propertyValue == null) {
                    if (matchLevel < 6) {
                        matchLevel = 6;
                        missException = new MissingAccessorException("Null can not be assigned to " +
                                methodParameterType.getName() + ": " + method, matchLevel);
                    }
                    continue;
                }


                if (!RecipeHelper.isInstance(methodParameterType, propertyValue) && !RecipeHelper.isConvertable(methodParameterType, propertyValue, registry)) {
                    if (matchLevel < 5) {
                        matchLevel = 5;
                        missException = new MissingAccessorException((propertyValue == null ? "null" : propertyValue.getClass().getName()) + " can not be assigned or converted to " +
                                methodParameterType.getName() + ": " + method, matchLevel);
                    }
                    continue;
                }

                if (allowPrivate && !Modifier.isPublic(method.getModifiers())) {
                    setAccessible(method);
                }

                if (RecipeHelper.isInstance(methodParameterType, propertyValue)) {
                    // This setter requires no conversion, which means there can not be a conversion error.
                    // Therefore this setter is perferred and put a the head of the list
                    validSetters.addFirst(method);
                } else {
                    validSetters.add(method);
                }
            }

        }

        if (!validSetters.isEmpty()) {
            // remove duplicate methods (can happen with inheritance)
            return new ArrayList<Method>(new LinkedHashSet<Method>(validSetters));
        }
        
        if (missException != null) {
            throw missException;
        } else {
            StringBuffer buffer = new StringBuffer("Unable to find a valid setter method: ");
            buffer.append("public void ").append(typeClass.getName()).append(".");
            buffer.append(setterName).append("(");
            if (propertyValue == null) {
                buffer.append("null");
            } else if (propertyValue instanceof String || propertyValue instanceof Recipe) {
                buffer.append("...");
            } else {
                buffer.append(propertyValue.getClass().getName());
            }
            buffer.append(")");
            throw new MissingAccessorException(buffer.toString(), -1);
        }
    }