1717package org .springframework .expression .spel .support ;
1818
1919import java .lang .reflect .Array ;
20+ import java .lang .reflect .Method ;
2021import java .util .ArrayList ;
2122import java .util .List ;
2223
24+ import org .springframework .core .MethodParameter ;
2325import org .springframework .core .convert .TypeDescriptor ;
2426import org .springframework .expression .EvaluationException ;
2527import org .springframework .expression .TypeConverter ;
2931import org .springframework .util .ClassUtils ;
3032
3133/**
32- * Utility methods used by the reflection resolver code to discover the appropriae
34+ * Utility methods used by the reflection resolver code to discover the appropriate
3335 * methods/constructors and fields that should be used in expressions.
3436 *
3537 * @author Andy Clement
3941public class ReflectionHelper {
4042
4143 /**
42- * Compare argument arrays and return information about whether they match. A supplied type converter and
43- * conversionAllowed flag allow for matches to take into account that a type may be transformed into a different
44- * type by the converter.
44+ * Compare argument arrays and return information about whether they match. A supplied type converter
45+ * and conversionAllowed flag allow for matches to take into account that a type may be transformed
46+ * into a different type by the converter.
4547 * @param expectedArgTypes the array of types the method/constructor is expecting
4648 * @param suppliedArgTypes the array of types that are being supplied at the point of invocation
4749 * @param typeConverter a registered type converter
4850 * @return a MatchInfo object indicating what kind of match it was or null if it was not a match
4951 */
50- public static ArgumentsMatchInfo compareArguments (
52+ static ArgumentsMatchInfo compareArguments (
5153 Class [] expectedArgTypes , Class [] suppliedArgTypes , TypeConverter typeConverter ) {
5254
5355 Assert .isTrue (expectedArgTypes .length == suppliedArgTypes .length ,
@@ -110,11 +112,13 @@ else if (typeConverter.canConvert(suppliedArg, expectedArg)) {
110112 * @param typeConverter a registered type converter
111113 * @return a MatchInfo object indicating what kind of match it was or null if it was not a match
112114 */
113- public static ArgumentsMatchInfo compareArgumentsVarargs (
115+ static ArgumentsMatchInfo compareArgumentsVarargs (
114116 Class [] expectedArgTypes , Class [] suppliedArgTypes , TypeConverter typeConverter ) {
115117
116- Assert .isTrue (expectedArgTypes !=null && expectedArgTypes .length >0 , "Expected arguments must at least include one array (the vargargs parameter)" );
117- Assert .isTrue (expectedArgTypes [expectedArgTypes .length -1 ].isArray (), "Final expected argument should be array type (the varargs parameter)" );
118+ Assert .isTrue (expectedArgTypes != null && expectedArgTypes .length > 0 ,
119+ "Expected arguments must at least include one array (the vargargs parameter)" );
120+ Assert .isTrue (expectedArgTypes [expectedArgTypes .length - 1 ].isArray (),
121+ "Final expected argument should be array type (the varargs parameter)" );
118122
119123 ArgsMatchKind match = ArgsMatchKind .EXACT ;
120124 List <Integer > argsRequiringConversion = null ;
@@ -214,76 +218,67 @@ else if (typeConverter.canConvert(suppliedArg, varargsParameterType)) {
214218 }
215219
216220 /**
217- * Takes an input set of argument values and, following the positions specified in the int array, it converts
218- * them to the types specified as the required parameter types. The arguments are converted 'in-place' in the
219- * input array.
220- * @param requiredParameterTypes the types that the caller would like to have
221- * @param isVarargs whether the requiredParameterTypes is a varargs list
221+ * Takes an input set of argument values and, following the positions specified in the int array,
222+ * it converts them to the types specified as the required parameter types. The arguments are
223+ * converted 'in-place' in the input array.
222224 * @param converter the type converter to use for attempting conversions
223- * @param argumentsRequiringConversion details which of the input arguments need conversion
224225 * @param arguments the actual arguments that need conversion
226+ * @param methodOrCtor the target Method or Constructor
227+ * @param argumentsRequiringConversion details which of the input arguments need conversion
228+ * @param varargsPosition the known position of the varargs argument, if any
225229 * @throws EvaluationException if a problem occurs during conversion
226230 */
227- public static void convertArguments (Class [] requiredParameterTypes , boolean isVarargs , TypeConverter converter ,
228- int [] argumentsRequiringConversion , Object [] arguments ) throws EvaluationException {
229-
230- Assert .notNull (argumentsRequiringConversion ,"should not be called if no conversions required" );
231- Assert .notNull (arguments ,"should not be called if no conversions required" );
232-
233- Class varargsType = null ;
234- if (isVarargs ) {
235- Assert .isTrue (requiredParameterTypes [requiredParameterTypes .length -1 ].isArray (),"if varargs then last parameter type must be array" );
236- varargsType = requiredParameterTypes [requiredParameterTypes .length - 1 ].getComponentType ();
237- }
238- for (Integer argPosition : argumentsRequiringConversion ) {
239- Class <?> targetType = null ;
240- if (isVarargs && argPosition >= (requiredParameterTypes .length - 1 )) {
241- targetType = varargsType ;
231+ static void convertArguments (TypeConverter converter , Object [] arguments , Object methodOrCtor ,
232+ int [] argumentsRequiringConversion , Integer varargsPosition ) throws EvaluationException {
233+
234+ for (int argPosition : argumentsRequiringConversion ) {
235+ TypeDescriptor targetType ;
236+ if (varargsPosition != null && argPosition >= varargsPosition ) {
237+ MethodParameter methodParam = MethodParameter .forMethodOrConstructor (methodOrCtor , varargsPosition );
238+ targetType = new TypeDescriptor (methodParam , methodParam .getParameterType ().getComponentType ());
242239 }
243240 else {
244- targetType = requiredParameterTypes [ argPosition ] ;
241+ targetType = new TypeDescriptor ( MethodParameter . forMethodOrConstructor ( methodOrCtor , argPosition )) ;
245242 }
246- arguments [argPosition ] = converter .convertValue (arguments [argPosition ], TypeDescriptor .forObject (arguments [argPosition ]), TypeDescriptor .valueOf (targetType ));
243+ arguments [argPosition ] = converter .convertValue (
244+ arguments [argPosition ], TypeDescriptor .forObject (arguments [argPosition ]), targetType );
247245 }
248246 }
249247
250248 /**
251- * Convert a supplied set of arguments into the requested types. If the parameterTypes are related to
249+ * Convert a supplied set of arguments into the requested types. If the parameterTypes are related to
252250 * a varargs method then the final entry in the parameterTypes array is going to be an array itself whose
253251 * component type should be used as the conversion target for extraneous arguments. (For example, if the
254252 * parameterTypes are {Integer, String[]} and the input arguments are {Integer, boolean, float} then both
255- * the boolean and float must be converted to strings). This method does not repackage the arguments
253+ * the boolean and float must be converted to strings). This method does not repackage the arguments
256254 * into a form suitable for the varargs invocation
257- * @param parameterTypes the types to be converted to
258- * @param isVarargs whether parameterTypes relates to a varargs method
259255 * @param converter the converter to use for type conversions
260256 * @param arguments the arguments to convert to the requested parameter types
257+ * @param method the target Method
261258 * @throws SpelEvaluationException if there is a problem with conversion
262259 */
263- public static void convertAllArguments (Class [] parameterTypes , boolean isVarargs , TypeConverter converter ,
264- Object [] arguments ) throws SpelEvaluationException {
265-
266- Assert .notNull (arguments ,"should not be called if nothing to convert" );
267-
268- Class varargsType = null ;
269- if (isVarargs ) {
270- Assert .isTrue (parameterTypes [parameterTypes .length -1 ].isArray (),"if varargs then last parameter type must be array" );
271- varargsType = parameterTypes [parameterTypes .length - 1 ].getComponentType ();
260+ public static void convertAllArguments (TypeConverter converter , Object [] arguments , Method method ) throws SpelEvaluationException {
261+ Integer varargsPosition = null ;
262+ if (method .isVarArgs ()) {
263+ Class [] paramTypes = method .getParameterTypes ();
264+ varargsPosition = paramTypes .length - 1 ;
272265 }
273- for (int i = 0 ; i < arguments .length ; i ++) {
274- Class <?> targetType = null ;
275- if (isVarargs && i >= (parameterTypes .length - 1 )) {
276- targetType = varargsType ;
266+ for (int argPosition = 0 ; argPosition < arguments .length ; argPosition ++) {
267+ TypeDescriptor targetType ;
268+ if (varargsPosition != null && argPosition >= varargsPosition ) {
269+ MethodParameter methodParam = new MethodParameter (method , varargsPosition );
270+ targetType = new TypeDescriptor (methodParam , methodParam .getParameterType ().getComponentType ());
277271 }
278272 else {
279- targetType = parameterTypes [ i ] ;
273+ targetType = new TypeDescriptor ( new MethodParameter ( method , argPosition )) ;
280274 }
281275 try {
282- if (arguments [i ] != null && arguments [i ].getClass () != targetType ) {
276+ Object argument = arguments [argPosition ];
277+ if (argument != null && !targetType .getObjectType ().isInstance (argument )) {
283278 if (converter == null ) {
284- throw new SpelEvaluationException (SpelMessage .TYPE_CONVERSION_ERROR , arguments [ i ] .getClass ().getName (),targetType );
279+ throw new SpelEvaluationException (SpelMessage .TYPE_CONVERSION_ERROR , argument .getClass ().getName (), targetType );
285280 }
286- arguments [i ] = converter .convertValue (arguments [ i ] , TypeDescriptor .forObject (arguments [ i ] ), TypeDescriptor . valueOf ( targetType ) );
281+ arguments [argPosition ] = converter .convertValue (argument , TypeDescriptor .forObject (argument ), targetType );
287282 }
288283 }
289284 catch (EvaluationException ex ) {
@@ -292,7 +287,7 @@ public static void convertAllArguments(Class[] parameterTypes, boolean isVarargs
292287 throw (SpelEvaluationException )ex ;
293288 }
294289 else {
295- throw new SpelEvaluationException (ex , SpelMessage .TYPE_CONVERSION_ERROR ,arguments [i ].getClass ().getName (),targetType );
290+ throw new SpelEvaluationException (ex , SpelMessage .TYPE_CONVERSION_ERROR ,arguments [argPosition ].getClass ().getName (), targetType );
296291 }
297292 }
298293 }
@@ -313,14 +308,15 @@ public static Object[] setupArgumentsForVarargsInvocation(Class[] requiredParame
313308 int argumentCount = args .length ;
314309
315310 // Check if repackaging is needed:
316- if (parameterCount != args .length || requiredParameterTypes [parameterCount - 1 ] != (args [argumentCount - 1 ] == null ? null : args [argumentCount - 1 ].getClass ())) {
311+ if (parameterCount != args .length ||
312+ requiredParameterTypes [parameterCount - 1 ] !=
313+ (args [argumentCount - 1 ] == null ? null : args [argumentCount - 1 ].getClass ())) {
317314 int arraySize = 0 ; // zero size array if nothing to pass as the varargs parameter
318315 if (argumentCount >= parameterCount ) {
319316 arraySize = argumentCount - (parameterCount - 1 );
320317 }
321318 Object [] repackagedArguments = (Object []) Array .newInstance (requiredParameterTypes [parameterCount - 1 ].getComponentType (),
322319 arraySize );
323-
324320 // Copy all but the varargs arguments
325321 for (int i = 0 ; i < arraySize ; i ++) {
326322 repackagedArguments [i ] = args [parameterCount + i - 1 ];
0 commit comments