in xbean-reflect/src/main/java/org/apache/xbean/recipe/ReflectionUtil.java [583:691]
public static ConstructorFactory findConstructor(Class typeClass, List<String> parameterNames, List<? extends Class<?>> parameterTypes, Set<String> availableProperties, Set<Option> options) {
if (typeClass == null) throw new NullPointerException("typeClass is null");
if (availableProperties == null) availableProperties = 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());
}
if (Modifier.isAbstract(typeClass.getModifiers())) {
throw new ConstructionException("Class is abstract: " + 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<Constructor> constructors = new ArrayList<Constructor>(Arrays.asList(typeClass.getConstructors()));
constructors.addAll(Arrays.asList(typeClass.getDeclaredConstructors()));
Collections.sort(constructors, new Comparator<Constructor>() {
public int compare(Constructor constructor1, Constructor constructor2) {
return constructor2.getParameterTypes().length - constructor1.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_CONSTRUCTOR);
for (Constructor constructor : constructors) {
// if an explicit constructor is specified (via parameter types), look a constructor that matches
if (parameterTypes != null) {
if (constructor.getParameterTypes().length != parameterTypes.size()) {
if (matchLevel < 1) {
matchLevel = 1;
missException = new MissingFactoryMethodException("Constructor has " + constructor.getParameterTypes().length + " arugments " +
"but expected " + parameterTypes.size() + " arguments: " + constructor);
}
continue;
}
if (!isAssignableFrom(parameterTypes, Arrays.<Class<?>>asList(constructor.getParameterTypes()))) {
if (matchLevel < 2) {
matchLevel = 2;
missException = new MissingFactoryMethodException("Constructor has signature " +
"public static " + typeClass.getName() + toParameterList(constructor.getParameterTypes()) +
" but expected signature " +
"public static " + typeClass.getName() + 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(constructor);
if (parameterNames == null || !availableProperties.containsAll(parameterNames)) {
continue;
}
}
if (Modifier.isAbstract(constructor.getModifiers())) {
if (matchLevel < 4) {
matchLevel = 4;
missException = new MissingFactoryMethodException("Constructor is abstract: " + constructor);
}
continue;
}
if (!allowPrivate && !Modifier.isPublic(constructor.getModifiers())) {
if (matchLevel < 5) {
matchLevel = 5;
missException = new MissingFactoryMethodException("Constructor is not public: " + constructor);
}
continue;
}
if (allowPrivate && !Modifier.isPublic(constructor.getModifiers())) {
setAccessible(constructor);
}
return new ConstructorFactory(constructor, parameterNames);
}
if (missException != null) {
throw missException;
} else {
StringBuffer buffer = new StringBuffer("Unable to find a valid constructor: ");
buffer.append("public void ").append(typeClass.getName()).append(toParameterList(parameterTypes));
throw new ConstructionException(buffer.toString());
}
}