|
|
|
@ -1,5 +1,5 @@ |
|
|
|
/* |
|
|
|
/* |
|
|
|
* Copyright 2002-2013 the original author or authors. |
|
|
|
* Copyright 2002-2015 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,13 +42,14 @@ import org.springframework.util.MethodInvoker; |
|
|
|
public class ReflectionHelper { |
|
|
|
public class ReflectionHelper { |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Compare argument arrays and return information about whether they match. A supplied |
|
|
|
* Compare argument arrays and return information about whether they match. |
|
|
|
* type converter and conversionAllowed flag allow for matches to take into account |
|
|
|
* A supplied type converter and conversionAllowed flag allow for matches to take |
|
|
|
* that a type may be transformed into a different type by the converter. |
|
|
|
* into account 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 types the method/constructor is expecting |
|
|
|
* @param suppliedArgTypes the array of types that are being supplied at the point of invocation |
|
|
|
* @param suppliedArgTypes the types that are being supplied at the point of invocation |
|
|
|
* @param typeConverter a registered type converter |
|
|
|
* @param typeConverter a registered type converter |
|
|
|
* @return a MatchInfo object indicating what kind of match it was or null if it was not a match |
|
|
|
* @return a MatchInfo object indicating what kind of match it was, |
|
|
|
|
|
|
|
* or {@code null} if it was not a match |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
static ArgumentsMatchInfo compareArguments( |
|
|
|
static ArgumentsMatchInfo compareArguments( |
|
|
|
List<TypeDescriptor> expectedArgTypes, List<TypeDescriptor> suppliedArgTypes, TypeConverter typeConverter) { |
|
|
|
List<TypeDescriptor> expectedArgTypes, List<TypeDescriptor> suppliedArgTypes, TypeConverter typeConverter) { |
|
|
|
@ -111,7 +112,7 @@ public class ReflectionHelper { |
|
|
|
int result = 0; |
|
|
|
int result = 0; |
|
|
|
for (int i = 0; i < paramTypes.size(); i++) { |
|
|
|
for (int i = 0; i < paramTypes.size(); i++) { |
|
|
|
TypeDescriptor paramType = paramTypes.get(i); |
|
|
|
TypeDescriptor paramType = paramTypes.get(i); |
|
|
|
TypeDescriptor argType = argTypes.get(i); |
|
|
|
TypeDescriptor argType = (i < argTypes.size() ? argTypes.get(i) : null); |
|
|
|
if (argType == null) { |
|
|
|
if (argType == null) { |
|
|
|
if (paramType.isPrimitive()) { |
|
|
|
if (paramType.isPrimitive()) { |
|
|
|
return Integer.MAX_VALUE; |
|
|
|
return Integer.MAX_VALUE; |
|
|
|
@ -148,13 +149,15 @@ public class ReflectionHelper { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Compare argument arrays and return information about whether they match. A supplied type converter and |
|
|
|
* Compare argument arrays and return information about whether they match. |
|
|
|
* conversionAllowed flag allow for matches to take into account that a type may be transformed into a different |
|
|
|
* A supplied type converter and conversionAllowed flag allow for matches to |
|
|
|
* type by the converter. This variant of compareArguments also allows for a varargs match. |
|
|
|
* take into account that a type may be transformed into a different type by the |
|
|
|
* @param expectedArgTypes the array of types the method/constructor is expecting |
|
|
|
* converter. This variant of compareArguments also allows for a varargs match. |
|
|
|
* @param suppliedArgTypes the array of types that are being supplied at the point of invocation |
|
|
|
* @param expectedArgTypes the types the method/constructor is expecting |
|
|
|
|
|
|
|
* @param suppliedArgTypes the types that are being supplied at the point of invocation |
|
|
|
* @param typeConverter a registered type converter |
|
|
|
* @param typeConverter a registered type converter |
|
|
|
* @return a MatchInfo object indicating what kind of match it was or null if it was not a match |
|
|
|
* @return a MatchInfo object indicating what kind of match it was, |
|
|
|
|
|
|
|
* or {@code null} if it was not a match |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
static ArgumentsMatchInfo compareArgumentsVarargs( |
|
|
|
static ArgumentsMatchInfo compareArgumentsVarargs( |
|
|
|
List<TypeDescriptor> expectedArgTypes, List<TypeDescriptor> suppliedArgTypes, TypeConverter typeConverter) { |
|
|
|
List<TypeDescriptor> expectedArgTypes, List<TypeDescriptor> suppliedArgTypes, TypeConverter typeConverter) { |
|
|
|
@ -264,14 +267,15 @@ public class ReflectionHelper { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Takes an input set of argument values and, following the positions specified in the int array, |
|
|
|
* Takes an input set of argument values and converts them to the types specified as the |
|
|
|
* it converts them to the types specified as the required parameter types. The arguments are |
|
|
|
* required parameter types. The arguments are converted 'in-place' in the input array. |
|
|
|
* converted 'in-place' in the input array. |
|
|
|
|
|
|
|
* @param converter the type converter to use for attempting conversions |
|
|
|
* @param converter the type converter to use for attempting conversions |
|
|
|
* @param arguments the actual arguments that need conversion |
|
|
|
* @param arguments the actual arguments that need conversion |
|
|
|
* @param methodOrCtor the target Method or Constructor |
|
|
|
* @param methodOrCtor the target Method or Constructor |
|
|
|
* @param argumentsRequiringConversion details which of the input arguments for sure need conversion |
|
|
|
* @param argumentsRequiringConversion details which of the input arguments need conversion |
|
|
|
* @param varargsPosition the known position of the varargs argument, if any |
|
|
|
* @param varargsPosition the known position of the varargs argument, if any |
|
|
|
|
|
|
|
* ({@code null} if not varargs) |
|
|
|
|
|
|
|
* @return {@code true} if some kind of conversion occurred on an argument |
|
|
|
* @throws EvaluationException if a problem occurs during conversion |
|
|
|
* @throws EvaluationException if a problem occurs during conversion |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
static void convertArguments(TypeConverter converter, Object[] arguments, Object methodOrCtor, |
|
|
|
static void convertArguments(TypeConverter converter, Object[] arguments, Object methodOrCtor, |
|
|
|
@ -285,6 +289,7 @@ public class ReflectionHelper { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
else { |
|
|
|
else { |
|
|
|
|
|
|
|
// Convert everything up to the varargs position
|
|
|
|
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]; |
|
|
|
@ -292,11 +297,13 @@ public class ReflectionHelper { |
|
|
|
} |
|
|
|
} |
|
|
|
MethodParameter methodParam = MethodParameter.forMethodOrConstructor(methodOrCtor, varargsPosition); |
|
|
|
MethodParameter methodParam = MethodParameter.forMethodOrConstructor(methodOrCtor, varargsPosition); |
|
|
|
if (varargsPosition == arguments.length - 1) { |
|
|
|
if (varargsPosition == arguments.length - 1) { |
|
|
|
|
|
|
|
// If the target is varargs and there is just one more argument then convert it here
|
|
|
|
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 { |
|
|
|
|
|
|
|
// Convert remaining arguments to the varargs element type
|
|
|
|
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]; |
|
|
|
@ -307,12 +314,14 @@ public class ReflectionHelper { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Convert a supplied set of arguments into the requested types. If the parameterTypes are related to |
|
|
|
* Convert a supplied set of arguments into the requested types. |
|
|
|
* a varargs method then the final entry in the parameterTypes array is going to be an array itself whose |
|
|
|
* If the parameterTypes are related to a varargs method, then the final entry |
|
|
|
* component type should be used as the conversion target for extraneous arguments. (For example, if the |
|
|
|
* in the parameterTypes array is going to be an array itself whose component type |
|
|
|
* parameterTypes are {Integer, String[]} and the input arguments are {Integer, boolean, float} then both |
|
|
|
* should be used as the conversion target for extraneous arguments. (For example, |
|
|
|
* the boolean and float must be converted to strings). This method does not repackage the arguments |
|
|
|
* if the parameterTypes are {@code {Integer, String[]}} and the input arguments |
|
|
|
* into a form suitable for the varargs invocation |
|
|
|
* are {@code {Integer, boolean, float}} then both the boolean and float must be |
|
|
|
|
|
|
|
* converted to Strings). This method does not repackage the arguments into a |
|
|
|
|
|
|
|
* form suitable for the varargs invocation. |
|
|
|
* @param converter the converter to use for type conversions |
|
|
|
* @param converter the converter to use for type conversions |
|
|
|
* @param arguments the arguments to convert to the requested parameter types |
|
|
|
* @param arguments the arguments to convert to the requested parameter types |
|
|
|
* @param method the target Method |
|
|
|
* @param method the target Method |
|
|
|
@ -359,10 +368,10 @@ public class ReflectionHelper { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Package up the arguments so that they correctly match what is expected in parameterTypes. For example, if |
|
|
|
* Package up the arguments so that they correctly match what is expected in parameterTypes. |
|
|
|
* parameterTypes is (int, String[]) because the second parameter was declared String... then if arguments is |
|
|
|
* For example, if parameterTypes is {@code (int, String[])} because the second parameter |
|
|
|
* [1,"a","b"] then it must be repackaged as [1,new String[]{"a","b"}] in order to match the expected |
|
|
|
* was declared {@code String...}, then if arguments is {@code [1,"a","b"]} then it must be |
|
|
|
* parameterTypes. |
|
|
|
* repackaged as {@code [1,new String[]{"a","b"}]} in order to match the expected types. |
|
|
|
* @param requiredParameterTypes the types of the parameters for the invocation |
|
|
|
* @param requiredParameterTypes the types of the parameters for the invocation |
|
|
|
* @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 |
|
|
|
@ -372,7 +381,7 @@ public class ReflectionHelper { |
|
|
|
int parameterCount = requiredParameterTypes.length; |
|
|
|
int parameterCount = requiredParameterTypes.length; |
|
|
|
int argumentCount = args.length; |
|
|
|
int argumentCount = args.length; |
|
|
|
|
|
|
|
|
|
|
|
// 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 ? args[argumentCount - 1].getClass() : null)) { |
|
|
|
(args[argumentCount - 1] != null ? args[argumentCount - 1].getClass() : null)) { |
|
|
|
@ -421,10 +430,11 @@ public class ReflectionHelper { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* An instance of ArgumentsMatchInfo describes what kind of match was achieved between two sets of arguments - |
|
|
|
* An instance of ArgumentsMatchInfo describes what kind of match was achieved |
|
|
|
* the set that a method/constructor is expecting and the set that are being supplied at the point of invocation. |
|
|
|
* between two sets of arguments - the set that a method/constructor is expecting |
|
|
|
* If the kind indicates that conversion is required for some of the arguments then the arguments that require |
|
|
|
* and the set that are being supplied at the point of invocation. If the kind |
|
|
|
* conversion are listed in the argsRequiringConversion array. |
|
|
|
* indicates that conversion is required for some of the arguments then the arguments |
|
|
|
|
|
|
|
* that require conversion are listed in the argsRequiringConversion array. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public static class ArgumentsMatchInfo { |
|
|
|
public static class ArgumentsMatchInfo { |
|
|
|
|
|
|
|
|
|
|
|
|