public static StaticFactory findStaticFactory()

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


    public static StaticFactory findStaticFactory(Class typeClass, String factoryMethod, List<String> parameterNames, List<? extends Class<?>> parameterTypes, Set<String> allProperties, Set<Option> options) {
        if (typeClass == null) throw new NullPointerException("typeClass is null");
        if (factoryMethod == null) throw new NullPointerException("name is null");
        if (factoryMethod.length() == 0) throw new IllegalArgumentException("name is an empty string");
        if (allProperties == null) allProperties = Collections.emptySet();
        if (options == null) options = EnumSet.noneOf(Option.class);

        //
        // verify that it is a class we can construct
        if (!Modifier.isPublic(typeClass.getModifiers())) {
            throw new ConstructionException("Class is not public: " + typeClass.getName());
        }
        if (Modifier.isInterface(typeClass.getModifiers())) {
            throw new ConstructionException("Class is an interface: " + typeClass.getName());
        }

        // verify parameter names and types are the same length
        if (parameterNames != null) {
            if (parameterTypes == null) parameterTypes = Collections.nCopies(parameterNames.size(), null);
            if (parameterNames.size() != parameterTypes.size()) {
                throw new ConstructionException("Invalid ObjectRecipe: recipe has " + parameterNames.size() +
                        " parameter names and " + parameterTypes.size() + " parameter types");
            }
        } else if (!options.contains(Option.NAMED_PARAMETERS)) {
            // Named parameters are not supported and no explicit parameters were given,
            // so we will only use the no-arg constructor
            parameterNames = Collections.emptyList();
            parameterTypes = Collections.emptyList();
        }

        // get all methods sorted so that the methods with the most constructor args are first
        List<Method> methods = new ArrayList<Method>(Arrays.asList(typeClass.getMethods()));
        methods.addAll(Arrays.asList(typeClass.getDeclaredMethods()));
        Collections.sort(methods, new Comparator<Method>() {
            public int compare(Method method2, Method method1) {
                return method1.getParameterTypes().length - method2.getParameterTypes().length;
            }
        });


        // as we check each constructor, we remember the closest invalid match so we can throw a nice exception to the user
        int matchLevel = 0;
        MissingFactoryMethodException missException = null;

        boolean allowPrivate = options.contains(Option.PRIVATE_FACTORY);
        boolean caseInsesnitive = options.contains(Option.CASE_INSENSITIVE_FACTORY);
        for (Method method : methods) {
            // Only consider methods where the name matches
            if (!method.getName().equals(factoryMethod) && (!caseInsesnitive || !method.getName().equalsIgnoreCase(method.getName()))) {
                continue;
            }

            // if an explicit constructor is specified (via parameter types), look a constructor that matches
            if (parameterTypes != null) {
                if (method.getParameterTypes().length != parameterTypes.size()) {
                    if (matchLevel < 1) {
                        matchLevel = 1;
                        missException = new MissingFactoryMethodException("Static factory method has " + method.getParameterTypes().length + " arugments " +
                                "but expected " + parameterTypes.size() + " arguments: " + method);
                    }
                    continue;
                }

                if (!isAssignableFrom(parameterTypes, Arrays.asList(method.getParameterTypes()))) {
                    if (matchLevel < 2) {
                        matchLevel = 2;
                        missException = new MissingFactoryMethodException("Static factory method has signature " +
                                "public static " + typeClass.getName() + "." + factoryMethod + toParameterList(method.getParameterTypes()) +
                                " but expected signature " +
                                "public static " + typeClass.getName() + "." + factoryMethod + toParameterList(parameterTypes));
                    }
                    continue;
                }
            } else {
                // Implicit constructor selection based on named constructor args
                //
                // Only consider methods where we can supply a value for all of the parameters
                parameterNames = getParameterNames(method);
                if (parameterNames == null || !allProperties.containsAll(parameterNames)) {
                    continue;
                }
            }

            if (method.getReturnType() == Void.TYPE) {
                if (matchLevel < 3) {
                    matchLevel = 3;
                    missException = new MissingFactoryMethodException("Static factory method does not return a value: " + method);
                }
                continue;
            }

            if (Modifier.isAbstract(method.getModifiers())) {
                if (matchLevel < 4) {
                    matchLevel = 4;
                    missException = new MissingFactoryMethodException("Static factory method is abstract: " + method);
                }
                continue;
            }

            if (!allowPrivate && !Modifier.isPublic(method.getModifiers())) {
                if (matchLevel < 5) {
                    matchLevel = 5;
                    missException = new MissingFactoryMethodException("Static factory method is not public: " + method);
                }
                continue;
            }

            if (!Modifier.isStatic(method.getModifiers())) {
                if (matchLevel < 6) {
                    matchLevel = 6;
                    missException = new MissingFactoryMethodException("Static factory method is not static: " + method);
                }
                continue;
            }

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

            return new StaticFactory(method, parameterNames);
        }

        if (missException != null) {
            throw missException;
        } else {
            StringBuffer buffer = new StringBuffer("Unable to find a valid factory method: ");
            buffer.append("public void ").append(typeClass.getName()).append(".");
            buffer.append(factoryMethod).append(toParameterList(parameterTypes));
            throw new MissingFactoryMethodException(buffer.toString());
        }
    }