Fixed getTypeDifferenceWeight algorithm in ReflectionHelper, and deprecated ArgsMatchKind enum (for removal in 4.0)
Issue: SPR-11306
This commit is contained in:
parent
62fd12c527
commit
f18debb5a3
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2012 the original author or authors.
|
* Copyright 2002-2013 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -42,9 +42,9 @@ import org.springframework.util.MethodInvoker;
|
||||||
public class ReflectionHelper {
|
public class ReflectionHelper {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compare argument arrays and return information about whether they match. A supplied type converter
|
* Compare argument arrays and return information about whether they match. A supplied
|
||||||
* and conversionAllowed flag allow for matches to take into account that a type may be transformed
|
* type converter and conversionAllowed flag allow for matches to take into account
|
||||||
* into a different type by the converter.
|
* that a type may be transformed into a different type by the converter.
|
||||||
* @param expectedArgTypes the array of types the method/constructor is expecting
|
* @param expectedArgTypes the array of types the method/constructor is expecting
|
||||||
* @param suppliedArgTypes the array of types that are being supplied at the point of invocation
|
* @param suppliedArgTypes the array of types that are being supplied at the point of invocation
|
||||||
* @param typeConverter a registered type converter
|
* @param typeConverter a registered type converter
|
||||||
|
|
@ -109,25 +109,25 @@ public class ReflectionHelper {
|
||||||
*/
|
*/
|
||||||
public static int getTypeDifferenceWeight(List<TypeDescriptor> paramTypes, List<TypeDescriptor> argTypes) {
|
public static int getTypeDifferenceWeight(List<TypeDescriptor> paramTypes, List<TypeDescriptor> argTypes) {
|
||||||
int result = 0;
|
int result = 0;
|
||||||
for (int i = 0,max=paramTypes.size(); i < max; i++) {
|
for (int i = 0; i < paramTypes.size(); i++) {
|
||||||
TypeDescriptor argType = argTypes.get(i);
|
|
||||||
TypeDescriptor paramType = paramTypes.get(i);
|
TypeDescriptor paramType = paramTypes.get(i);
|
||||||
|
TypeDescriptor argType = argTypes.get(i);
|
||||||
if (argType == null) {
|
if (argType == null) {
|
||||||
if (paramType.isPrimitive()) {
|
if (paramType.isPrimitive()) {
|
||||||
return Integer.MAX_VALUE;
|
return Integer.MAX_VALUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!ClassUtils.isAssignable(paramType.getClass(), argType.getClass())) {
|
else {
|
||||||
return Integer.MAX_VALUE;
|
Class<?> paramTypeClazz = paramType.getType();
|
||||||
}
|
if (!ClassUtils.isAssignable(paramTypeClazz, argType.getType())) {
|
||||||
if (argType != null) {
|
return Integer.MAX_VALUE;
|
||||||
Class paramTypeClazz = paramType.getType();
|
}
|
||||||
if (paramTypeClazz.isPrimitive()) {
|
if (paramTypeClazz.isPrimitive()) {
|
||||||
paramTypeClazz = Object.class;
|
paramTypeClazz = Object.class;
|
||||||
}
|
}
|
||||||
Class superClass = argType.getClass().getSuperclass();
|
Class<?> superClass = argType.getType().getSuperclass();
|
||||||
while (superClass != null) {
|
while (superClass != null) {
|
||||||
if (paramType.equals(superClass)) {
|
if (paramTypeClazz.equals(superClass)) {
|
||||||
result = result + 2;
|
result = result + 2;
|
||||||
superClass = null;
|
superClass = null;
|
||||||
}
|
}
|
||||||
|
|
@ -199,6 +199,7 @@ public class ReflectionHelper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If already confirmed it cannot be a match, then return
|
// If already confirmed it cannot be a match, then return
|
||||||
if (match == null) {
|
if (match == null) {
|
||||||
return null;
|
return null;
|
||||||
|
|
@ -211,25 +212,26 @@ public class ReflectionHelper {
|
||||||
// expected argument - that is a match, the caller has already built the array. Proceed with it.
|
// expected argument - that is a match, the caller has already built the array. Proceed with it.
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Now... we have the final argument in the method we are checking as a match and we have 0 or more other
|
// Now... we have the final argument in the method we are checking as a match and we have 0
|
||||||
// arguments left to pass to it.
|
// or more other arguments left to pass to it.
|
||||||
Class varargsParameterType = expectedArgTypes.get(expectedArgTypes.size() - 1).getElementTypeDescriptor().getType();
|
Class<?> varargsParamType = expectedArgTypes.get(expectedArgTypes.size() - 1).getElementTypeDescriptor().getType();
|
||||||
|
|
||||||
// All remaining parameters must be of this type or convertable to this type
|
// All remaining parameters must be of this type or convertable to this type
|
||||||
for (int i = expectedArgTypes.size() - 1; i < suppliedArgTypes.size(); i++) {
|
for (int i = expectedArgTypes.size() - 1; i < suppliedArgTypes.size(); i++) {
|
||||||
TypeDescriptor suppliedArg = suppliedArgTypes.get(i);
|
TypeDescriptor suppliedArg = suppliedArgTypes.get(i);
|
||||||
if (suppliedArg == null) {
|
if (suppliedArg == null) {
|
||||||
if (varargsParameterType.isPrimitive()) {
|
if (varargsParamType.isPrimitive()) {
|
||||||
match = null;
|
match = null;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
if (varargsParameterType != suppliedArg.getType()) {
|
else {
|
||||||
if (ClassUtils.isAssignable(varargsParameterType, suppliedArg.getType())) {
|
if (varargsParamType != suppliedArg.getType()) {
|
||||||
|
if (ClassUtils.isAssignable(varargsParamType, suppliedArg.getType())) {
|
||||||
if (match != ArgsMatchKind.REQUIRES_CONVERSION) {
|
if (match != ArgsMatchKind.REQUIRES_CONVERSION) {
|
||||||
match = ArgsMatchKind.CLOSE;
|
match = ArgsMatchKind.CLOSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (typeConverter.canConvert(suppliedArg, TypeDescriptor.valueOf(varargsParameterType))) {
|
else if (typeConverter.canConvert(suppliedArg, TypeDescriptor.valueOf(varargsParamType))) {
|
||||||
if (argsRequiringConversion == null) {
|
if (argsRequiringConversion == null) {
|
||||||
argsRequiringConversion = new ArrayList<Integer>();
|
argsRequiringConversion = new ArrayList<Integer>();
|
||||||
}
|
}
|
||||||
|
|
@ -274,13 +276,15 @@ public class ReflectionHelper {
|
||||||
*/
|
*/
|
||||||
static void convertArguments(TypeConverter converter, Object[] arguments, Object methodOrCtor,
|
static void convertArguments(TypeConverter converter, Object[] arguments, Object methodOrCtor,
|
||||||
int[] argumentsRequiringConversion, Integer varargsPosition) throws EvaluationException {
|
int[] argumentsRequiringConversion, Integer varargsPosition) throws EvaluationException {
|
||||||
|
|
||||||
if (varargsPosition == null) {
|
if (varargsPosition == null) {
|
||||||
for (int i = 0; i < arguments.length; i++) {
|
for (int i = 0; i < arguments.length; i++) {
|
||||||
TypeDescriptor targetType = new TypeDescriptor(MethodParameter.forMethodOrConstructor(methodOrCtor, i));
|
TypeDescriptor targetType = new TypeDescriptor(MethodParameter.forMethodOrConstructor(methodOrCtor, i));
|
||||||
Object argument = arguments[i];
|
Object argument = arguments[i];
|
||||||
arguments[i] = converter.convertValue(argument, TypeDescriptor.forObject(argument), targetType);
|
arguments[i] = converter.convertValue(argument, TypeDescriptor.forObject(argument), targetType);
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
for (int i = 0; i < varargsPosition; i++) {
|
for (int i = 0; i < varargsPosition; i++) {
|
||||||
TypeDescriptor targetType = new TypeDescriptor(MethodParameter.forMethodOrConstructor(methodOrCtor, i));
|
TypeDescriptor targetType = new TypeDescriptor(MethodParameter.forMethodOrConstructor(methodOrCtor, i));
|
||||||
Object argument = arguments[i];
|
Object argument = arguments[i];
|
||||||
|
|
@ -291,7 +295,8 @@ public class ReflectionHelper {
|
||||||
TypeDescriptor targetType = new TypeDescriptor(methodParam);
|
TypeDescriptor targetType = new TypeDescriptor(methodParam);
|
||||||
Object argument = arguments[varargsPosition];
|
Object argument = arguments[varargsPosition];
|
||||||
arguments[varargsPosition] = converter.convertValue(argument, TypeDescriptor.forObject(argument), targetType);
|
arguments[varargsPosition] = converter.convertValue(argument, TypeDescriptor.forObject(argument), targetType);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
TypeDescriptor targetType = TypeDescriptor.nested(methodParam, 1);
|
TypeDescriptor targetType = TypeDescriptor.nested(methodParam, 1);
|
||||||
for (int i = varargsPosition; i < arguments.length; i++) {
|
for (int i = varargsPosition; i < arguments.length; i++) {
|
||||||
Object argument = arguments[i];
|
Object argument = arguments[i];
|
||||||
|
|
@ -313,28 +318,31 @@ public class ReflectionHelper {
|
||||||
* @param method the target Method
|
* @param method the target Method
|
||||||
* @throws SpelEvaluationException if there is a problem with conversion
|
* @throws SpelEvaluationException if there is a problem with conversion
|
||||||
*/
|
*/
|
||||||
public static void convertAllArguments(TypeConverter converter, Object[] arguments, Method method) throws SpelEvaluationException {
|
public static void convertAllArguments(TypeConverter converter, Object[] arguments, Method method)
|
||||||
|
throws SpelEvaluationException {
|
||||||
|
|
||||||
Integer varargsPosition = null;
|
Integer varargsPosition = null;
|
||||||
if (method.isVarArgs()) {
|
if (method.isVarArgs()) {
|
||||||
Class[] paramTypes = method.getParameterTypes();
|
Class<?>[] paramTypes = method.getParameterTypes();
|
||||||
varargsPosition = paramTypes.length - 1;
|
varargsPosition = paramTypes.length - 1;
|
||||||
}
|
}
|
||||||
for (int argPosition = 0; argPosition < arguments.length; argPosition++) {
|
for (int argPos = 0; argPos < arguments.length; argPos++) {
|
||||||
TypeDescriptor targetType;
|
TypeDescriptor targetType;
|
||||||
if (varargsPosition != null && argPosition >= varargsPosition) {
|
if (varargsPosition != null && argPos >= varargsPosition) {
|
||||||
MethodParameter methodParam = new MethodParameter(method, varargsPosition);
|
MethodParameter methodParam = new MethodParameter(method, varargsPosition);
|
||||||
targetType = TypeDescriptor.nested(methodParam, 1);
|
targetType = TypeDescriptor.nested(methodParam, 1);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
targetType = new TypeDescriptor(new MethodParameter(method, argPosition));
|
targetType = new TypeDescriptor(new MethodParameter(method, argPos));
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
Object argument = arguments[argPosition];
|
Object argument = arguments[argPos];
|
||||||
if (argument != null && !targetType.getObjectType().isInstance(argument)) {
|
if (argument != null && !targetType.getObjectType().isInstance(argument)) {
|
||||||
if (converter == null) {
|
if (converter == null) {
|
||||||
throw new SpelEvaluationException(SpelMessage.TYPE_CONVERSION_ERROR, argument.getClass().getName(), targetType);
|
throw new SpelEvaluationException(
|
||||||
|
SpelMessage.TYPE_CONVERSION_ERROR, argument.getClass().getName(), targetType);
|
||||||
}
|
}
|
||||||
arguments[argPosition] = converter.convertValue(argument, TypeDescriptor.forObject(argument), targetType);
|
arguments[argPos] = converter.convertValue(argument, TypeDescriptor.forObject(argument), targetType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (EvaluationException ex) {
|
catch (EvaluationException ex) {
|
||||||
|
|
@ -343,7 +351,8 @@ public class ReflectionHelper {
|
||||||
throw (SpelEvaluationException)ex;
|
throw (SpelEvaluationException)ex;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
throw new SpelEvaluationException(ex, SpelMessage.TYPE_CONVERSION_ERROR,arguments[argPosition].getClass().getName(), targetType);
|
throw new SpelEvaluationException(ex,
|
||||||
|
SpelMessage.TYPE_CONVERSION_ERROR,arguments[argPos].getClass().getName(), targetType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -358,7 +367,7 @@ public class ReflectionHelper {
|
||||||
* @param args the arguments to be setup ready for the invocation
|
* @param args the arguments to be setup ready for the invocation
|
||||||
* @return a repackaged array of arguments where any varargs setup has been done
|
* @return a repackaged array of arguments where any varargs setup has been done
|
||||||
*/
|
*/
|
||||||
public static Object[] setupArgumentsForVarargsInvocation(Class[] requiredParameterTypes, Object... args) {
|
public static Object[] setupArgumentsForVarargsInvocation(Class<?>[] requiredParameterTypes, Object... args) {
|
||||||
// Check if array already built for final argument
|
// Check if array already built for final argument
|
||||||
int parameterCount = requiredParameterTypes.length;
|
int parameterCount = requiredParameterTypes.length;
|
||||||
int argumentCount = args.length;
|
int argumentCount = args.length;
|
||||||
|
|
@ -366,99 +375,54 @@ public class ReflectionHelper {
|
||||||
// Check if repackaging is needed:
|
// Check if repackaging is needed:
|
||||||
if (parameterCount != args.length ||
|
if (parameterCount != args.length ||
|
||||||
requiredParameterTypes[parameterCount - 1] !=
|
requiredParameterTypes[parameterCount - 1] !=
|
||||||
(args[argumentCount - 1] == null ? null : args[argumentCount - 1].getClass())) {
|
(args[argumentCount - 1] != null ? args[argumentCount - 1].getClass() : null)) {
|
||||||
int arraySize = 0; // zero size array if nothing to pass as the varargs parameter
|
|
||||||
|
int arraySize = 0; // zero size array if nothing to pass as the varargs parameter
|
||||||
if (argumentCount >= parameterCount) {
|
if (argumentCount >= parameterCount) {
|
||||||
arraySize = argumentCount - (parameterCount - 1);
|
arraySize = argumentCount - (parameterCount - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create an array for the varargs arguments
|
// Create an array for the varargs arguments
|
||||||
Object[] newArgs = new Object[parameterCount];
|
Object[] newArgs = new Object[parameterCount];
|
||||||
for (int i = 0; i < newArgs.length - 1; i++) {
|
System.arraycopy(args, 0, newArgs, 0, newArgs.length - 1);
|
||||||
newArgs[i] = args[i];
|
|
||||||
}
|
// Now sort out the final argument, which is the varargs one. Before entering this method,
|
||||||
// Now sort out the final argument, which is the varargs one. Before entering this
|
// the arguments should have been converted to the box form of the required type.
|
||||||
// method the arguments should have been converted to the box form of the required type.
|
Class<?> componentType = requiredParameterTypes[parameterCount - 1].getComponentType();
|
||||||
Class<?> componentType = requiredParameterTypes[parameterCount-1].getComponentType();
|
Object repackagedArgs = Array.newInstance(componentType, arraySize);
|
||||||
if (componentType.isPrimitive()) {
|
for (int i = 0; i < arraySize; i++) {
|
||||||
if (componentType==Integer.TYPE) {
|
Array.set(repackagedArgs, i, args[parameterCount - 1 + i]);
|
||||||
int[] repackagedArguments = (int[]) Array.newInstance(componentType, arraySize);
|
|
||||||
for (int i = 0; i < arraySize; i++) {
|
|
||||||
repackagedArguments[i] = ((Integer)args[parameterCount + i - 1]).intValue();
|
|
||||||
}
|
|
||||||
newArgs[newArgs.length - 1] = repackagedArguments;
|
|
||||||
} else if(componentType==Float.TYPE) {
|
|
||||||
float[] repackagedArguments = (float[]) Array.newInstance(componentType, arraySize);
|
|
||||||
for (int i = 0; i < arraySize; i++) {
|
|
||||||
repackagedArguments[i] = ((Float)args[parameterCount + i - 1]).floatValue();
|
|
||||||
}
|
|
||||||
newArgs[newArgs.length - 1] = repackagedArguments;
|
|
||||||
} else if(componentType==Double.TYPE) {
|
|
||||||
double[] repackagedArguments = (double[]) Array.newInstance(componentType, arraySize);
|
|
||||||
for (int i = 0; i < arraySize; i++) {
|
|
||||||
repackagedArguments[i] = ((Double)args[parameterCount + i - 1]).doubleValue();
|
|
||||||
}
|
|
||||||
newArgs[newArgs.length - 1] = repackagedArguments;
|
|
||||||
} else if(componentType==Short.TYPE) {
|
|
||||||
short[] repackagedArguments = (short[]) Array.newInstance(componentType, arraySize);
|
|
||||||
for (int i = 0; i < arraySize; i++) {
|
|
||||||
repackagedArguments[i] = ((Short)args[parameterCount + i - 1]).shortValue();
|
|
||||||
}
|
|
||||||
newArgs[newArgs.length - 1] = repackagedArguments;
|
|
||||||
} else if(componentType==Character.TYPE) {
|
|
||||||
char[] repackagedArguments = (char[]) Array.newInstance(componentType, arraySize);
|
|
||||||
for (int i = 0; i < arraySize; i++) {
|
|
||||||
repackagedArguments[i] = ((Character)args[parameterCount + i - 1]).charValue();
|
|
||||||
}
|
|
||||||
newArgs[newArgs.length - 1] = repackagedArguments;
|
|
||||||
} else if(componentType==Byte.TYPE) {
|
|
||||||
byte[] repackagedArguments = (byte[]) Array.newInstance(componentType, arraySize);
|
|
||||||
for (int i = 0; i < arraySize; i++) {
|
|
||||||
repackagedArguments[i] = ((Byte)args[parameterCount + i - 1]).byteValue();
|
|
||||||
}
|
|
||||||
newArgs[newArgs.length - 1] = repackagedArguments;
|
|
||||||
} else if(componentType==Boolean.TYPE) {
|
|
||||||
boolean[] repackagedArguments = (boolean[]) Array.newInstance(componentType, arraySize);
|
|
||||||
for (int i = 0; i < arraySize; i++) {
|
|
||||||
repackagedArguments[i] = ((Boolean)args[parameterCount + i - 1]).booleanValue();
|
|
||||||
}
|
|
||||||
newArgs[newArgs.length - 1] = repackagedArguments;
|
|
||||||
} else if(componentType==Long.TYPE) {
|
|
||||||
long[] repackagedArguments = (long[]) Array.newInstance(componentType, arraySize);
|
|
||||||
for (int i = 0; i < arraySize; i++) {
|
|
||||||
repackagedArguments[i] = ((Long)args[parameterCount + i - 1]).longValue();
|
|
||||||
}
|
|
||||||
newArgs[newArgs.length - 1] = repackagedArguments;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Object[] repackagedArguments = (Object[]) Array.newInstance(componentType, arraySize);
|
|
||||||
// Copy all but the varargs arguments
|
|
||||||
for (int i = 0; i < arraySize; i++) {
|
|
||||||
repackagedArguments[i] = args[parameterCount + i - 1];
|
|
||||||
}
|
|
||||||
newArgs[newArgs.length - 1] = repackagedArguments;
|
|
||||||
}
|
}
|
||||||
|
newArgs[newArgs.length - 1] = repackagedArgs;
|
||||||
return newArgs;
|
return newArgs;
|
||||||
}
|
}
|
||||||
return args;
|
return args;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated as of Spring 3.2.7, since there is no need to ever refer to this directly...
|
||||||
|
* and {@link #REQUIRES_CONVERSION} is effectively unused, going away in Spring 4.0
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public static enum ArgsMatchKind {
|
public static enum ArgsMatchKind {
|
||||||
// An exact match is where the parameter types exactly match what the method/constructor being invoked is expecting
|
|
||||||
|
/** An exact match is where the parameter types exactly match what the method/constructor is expecting */
|
||||||
EXACT,
|
EXACT,
|
||||||
// A close match is where the parameter types either exactly match or are assignment compatible with the method/constructor being invoked
|
|
||||||
|
/** A close match is where the parameter types either exactly match or are assignment-compatible */
|
||||||
CLOSE,
|
CLOSE,
|
||||||
// A conversion match is where the type converter must be used to transform some of the parameter types
|
|
||||||
|
/** A conversion match is where the type converter must be used to transform some of the parameter types */
|
||||||
REQUIRES_CONVERSION
|
REQUIRES_CONVERSION
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An instance of ArgumentsMatchInfo describes what kind of match was achieved between two sets of arguments - the set that a
|
* An instance of ArgumentsMatchInfo describes what kind of match was achieved between two sets of arguments -
|
||||||
* method/constructor is expecting and the set that are being supplied at the point of invocation. If the kind
|
* the set that a method/constructor is expecting and the set that are being supplied at the point of invocation.
|
||||||
* indicates that conversion is required for some of the arguments then the arguments that require conversion are
|
* If the kind indicates that conversion is required for some of the arguments then the arguments that require
|
||||||
* listed in the argsRequiringConversion array.
|
* conversion are listed in the argsRequiringConversion array.
|
||||||
*/
|
*/
|
||||||
public static class ArgumentsMatchInfo {
|
public static class ArgumentsMatchInfo {
|
||||||
|
|
||||||
|
|
@ -487,11 +451,12 @@ public class ReflectionHelper {
|
||||||
return (this.kind == ArgsMatchKind.REQUIRES_CONVERSION);
|
return (this.kind == ArgsMatchKind.REQUIRES_CONVERSION);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.append("ArgumentMatch: ").append(this.kind);
|
sb.append("ArgumentsMatchInfo: ").append(this.kind);
|
||||||
if (this.argsRequiringConversion != null) {
|
if (this.argsRequiringConversion != null) {
|
||||||
sb.append(" (argsForConversion:");
|
sb.append(" (argsRequiringConversion:");
|
||||||
for (int i = 0; i < this.argsRequiringConversion.length;i++) {
|
for (int i = 0; i < this.argsRequiringConversion.length;i++) {
|
||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
sb.append(",");
|
sb.append(",");
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2012 the original author or authors.
|
* Copyright 2002-2013 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -32,7 +32,7 @@ import org.springframework.expression.EvaluationException;
|
||||||
import org.springframework.expression.TypeConverter;
|
import org.springframework.expression.TypeConverter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A constructor resolver that uses reflection to locate the constructor that should be invoked
|
* A constructor resolver that uses reflection to locate the constructor that should be invoked.
|
||||||
*
|
*
|
||||||
* @author Andy Clement
|
* @author Andy Clement
|
||||||
* @author Juergen Hoeller
|
* @author Juergen Hoeller
|
||||||
|
|
@ -55,28 +55,28 @@ public class ReflectiveConstructorResolver implements ConstructorResolver {
|
||||||
try {
|
try {
|
||||||
TypeConverter typeConverter = context.getTypeConverter();
|
TypeConverter typeConverter = context.getTypeConverter();
|
||||||
Class<?> type = context.getTypeLocator().findType(typename);
|
Class<?> type = context.getTypeLocator().findType(typename);
|
||||||
Constructor[] ctors = type.getConstructors();
|
Constructor<?>[] ctors = type.getConstructors();
|
||||||
|
|
||||||
Arrays.sort(ctors, new Comparator<Constructor>() {
|
Arrays.sort(ctors, new Comparator<Constructor<?>>() {
|
||||||
public int compare(Constructor c1, Constructor c2) {
|
public int compare(Constructor<?> c1, Constructor<?> c2) {
|
||||||
int c1pl = c1.getParameterTypes().length;
|
int c1pl = c1.getParameterTypes().length;
|
||||||
int c2pl = c2.getParameterTypes().length;
|
int c2pl = c2.getParameterTypes().length;
|
||||||
return (new Integer(c1pl)).compareTo(c2pl);
|
return (new Integer(c1pl)).compareTo(c2pl);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Constructor closeMatch = null;
|
Constructor<?> closeMatch = null;
|
||||||
int[] argsToConvert = null;
|
int[] argsToConvert = null;
|
||||||
Constructor matchRequiringConversion = null;
|
Constructor matchRequiringConversion = null;
|
||||||
|
|
||||||
for (Constructor ctor : ctors) {
|
for (Constructor<?> ctor : ctors) {
|
||||||
Class[] paramTypes = ctor.getParameterTypes();
|
Class<?>[] paramTypes = ctor.getParameterTypes();
|
||||||
List<TypeDescriptor> paramDescriptors = new ArrayList<TypeDescriptor>(paramTypes.length);
|
List<TypeDescriptor> paramDescriptors = new ArrayList<TypeDescriptor>(paramTypes.length);
|
||||||
for (int i = 0; i < paramTypes.length; i++) {
|
for (int i = 0; i < paramTypes.length; i++) {
|
||||||
paramDescriptors.add(new TypeDescriptor(new MethodParameter(ctor, i)));
|
paramDescriptors.add(new TypeDescriptor(new MethodParameter(ctor, i)));
|
||||||
}
|
}
|
||||||
ReflectionHelper.ArgumentsMatchInfo matchInfo = null;
|
ReflectionHelper.ArgumentsMatchInfo matchInfo = null;
|
||||||
if (ctor.isVarArgs() && argumentTypes.size() >= (paramTypes.length - 1)) {
|
if (ctor.isVarArgs() && argumentTypes.size() >= paramTypes.length - 1) {
|
||||||
// *sigh* complicated
|
// *sigh* complicated
|
||||||
// Basically.. we have to have all parameters match up until the varargs one, then the rest of what is
|
// Basically.. we have to have all parameters match up until the varargs one, then the rest of what is
|
||||||
// being provided should be
|
// being provided should be
|
||||||
|
|
@ -90,18 +90,19 @@ public class ReflectiveConstructorResolver implements ConstructorResolver {
|
||||||
matchInfo = ReflectionHelper.compareArguments(paramDescriptors, argumentTypes, typeConverter);
|
matchInfo = ReflectionHelper.compareArguments(paramDescriptors, argumentTypes, typeConverter);
|
||||||
}
|
}
|
||||||
if (matchInfo != null) {
|
if (matchInfo != null) {
|
||||||
if (matchInfo.kind == ReflectionHelper.ArgsMatchKind.EXACT) {
|
if (matchInfo.isExactMatch()) {
|
||||||
return new ReflectiveConstructorExecutor(ctor, null);
|
return new ReflectiveConstructorExecutor(ctor, null);
|
||||||
}
|
}
|
||||||
else if (matchInfo.kind == ReflectionHelper.ArgsMatchKind.CLOSE) {
|
else if (matchInfo.isCloseMatch()) {
|
||||||
closeMatch = ctor;
|
closeMatch = ctor;
|
||||||
}
|
}
|
||||||
else if (matchInfo.kind == ReflectionHelper.ArgsMatchKind.REQUIRES_CONVERSION) {
|
else if (matchInfo.isMatchRequiringConversion()) {
|
||||||
argsToConvert = matchInfo.argsRequiringConversion;
|
argsToConvert = matchInfo.argsRequiringConversion;
|
||||||
matchRequiringConversion = ctor;
|
matchRequiringConversion = ctor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (closeMatch != null) {
|
if (closeMatch != null) {
|
||||||
return new ReflectiveConstructorExecutor(closeMatch, null);
|
return new ReflectiveConstructorExecutor(closeMatch, null);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -53,8 +53,6 @@ import org.springframework.expression.spel.SpelMessage;
|
||||||
*/
|
*/
|
||||||
public class ReflectiveMethodResolver implements MethodResolver {
|
public class ReflectiveMethodResolver implements MethodResolver {
|
||||||
|
|
||||||
private static Method[] NO_METHODS = new Method[0];
|
|
||||||
|
|
||||||
private Map<Class<?>, MethodFilter> filters = null;
|
private Map<Class<?>, MethodFilter> filters = null;
|
||||||
|
|
||||||
// Using distance will ensure a more accurate match is discovered,
|
// Using distance will ensure a more accurate match is discovered,
|
||||||
|
|
@ -78,6 +76,7 @@ public class ReflectiveMethodResolver implements MethodResolver {
|
||||||
this.useDistance = useDistance;
|
this.useDistance = useDistance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Locate a method on a type. There are three kinds of match that might occur:
|
* Locate a method on a type. There are three kinds of match that might occur:
|
||||||
* <ol>
|
* <ol>
|
||||||
|
|
@ -140,27 +139,27 @@ public class ReflectiveMethodResolver implements MethodResolver {
|
||||||
matchInfo = ReflectionHelper.compareArgumentsVarargs(paramDescriptors, argumentTypes, typeConverter);
|
matchInfo = ReflectionHelper.compareArgumentsVarargs(paramDescriptors, argumentTypes, typeConverter);
|
||||||
}
|
}
|
||||||
else if (paramTypes.length == argumentTypes.size()) {
|
else if (paramTypes.length == argumentTypes.size()) {
|
||||||
// name and parameter number match, check the arguments
|
// Name and parameter number match, check the arguments
|
||||||
matchInfo = ReflectionHelper.compareArguments(paramDescriptors, argumentTypes, typeConverter);
|
matchInfo = ReflectionHelper.compareArguments(paramDescriptors, argumentTypes, typeConverter);
|
||||||
}
|
}
|
||||||
if (matchInfo != null) {
|
if (matchInfo != null) {
|
||||||
if (matchInfo.kind == ReflectionHelper.ArgsMatchKind.EXACT) {
|
if (matchInfo.isExactMatch()) {
|
||||||
return new ReflectiveMethodExecutor(method, null);
|
return new ReflectiveMethodExecutor(method, null);
|
||||||
}
|
}
|
||||||
else if (matchInfo.kind == ReflectionHelper.ArgsMatchKind.CLOSE) {
|
else if (matchInfo.isCloseMatch()) {
|
||||||
if (!this.useDistance) {
|
if (!this.useDistance) {
|
||||||
closeMatch = method;
|
closeMatch = method;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
int matchDistance = ReflectionHelper.getTypeDifferenceWeight(paramDescriptors, argumentTypes);
|
int matchDistance = ReflectionHelper.getTypeDifferenceWeight(paramDescriptors, argumentTypes);
|
||||||
if (matchDistance<closeMatchDistance) {
|
if (matchDistance < closeMatchDistance) {
|
||||||
// this is a better match
|
// This is a better match...
|
||||||
closeMatchDistance = matchDistance;
|
closeMatchDistance = matchDistance;
|
||||||
closeMatch = method;
|
closeMatch = method;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (matchInfo.kind == ReflectionHelper.ArgsMatchKind.REQUIRES_CONVERSION) {
|
else if (matchInfo.isMatchRequiringConversion()) {
|
||||||
if (matchRequiringConversion != null) {
|
if (matchRequiringConversion != null) {
|
||||||
multipleOptions = true;
|
multipleOptions = true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue