Skip to content

Commit bdc4ecd

Browse files
committed
Merge branch '6.1.x'
# Conflicts: # spring-expression/src/test/java/org/springframework/expression/spel/SpelCompilationCoverageTests.java
2 parents 92f54da + aebc48e commit bdc4ecd

File tree

3 files changed

+101
-21
lines changed

3 files changed

+101
-21
lines changed

spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectionHelper.java

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -448,24 +448,29 @@ private static boolean isFirstEntryInArray(Object value, @Nullable Object possib
448448
}
449449

450450
/**
451-
* Package up the arguments so that they correctly match what is expected in requiredParameterTypes.
452-
* <p>For example, if requiredParameterTypes is {@code (int, String[])} because the second parameter
453-
* was declared {@code String...}, then if arguments is {@code [1,"a","b"]} then it must be
454-
* repackaged as {@code [1,new String[]{"a","b"}]} in order to match the expected types.
451+
* Package up the supplied {@code args} so that they correctly match what is
452+
* expected in {@code requiredParameterTypes}.
453+
* <p>For example, if {@code requiredParameterTypes} is {@code (int, String[])}
454+
* because the second parameter was declared as {@code String...}, then if
455+
* {@code args} is {@code [1, "a", "b"]} it must be repackaged as
456+
* {@code [1, new String[] {"a", "b"}]} in order to match the expected types.
455457
* @param requiredParameterTypes the types of the parameters for the invocation
456-
* @param args the arguments to be setup ready for the invocation
457-
* @return a repackaged array of arguments where any varargs setup has been done
458+
* @param args the arguments to be set up for the invocation
459+
* @return a repackaged array of arguments where any varargs setup has performed
458460
*/
459461
public static Object[] setupArgumentsForVarargsInvocation(Class<?>[] requiredParameterTypes, Object... args) {
460-
// Check if array already built for final argument
462+
Assert.notEmpty(requiredParameterTypes, "Required parameter types array must not be empty");
463+
461464
int parameterCount = requiredParameterTypes.length;
465+
Class<?> lastRequiredParameterType = requiredParameterTypes[parameterCount - 1];
466+
Assert.isTrue(lastRequiredParameterType.isArray(),
467+
"The last required parameter type must be an array to support varargs invocation");
468+
462469
int argumentCount = args.length;
470+
Object lastArgument = (argumentCount > 0 ? args[argumentCount - 1] : null);
463471

464472
// Check if repackaging is needed...
465-
if (parameterCount != args.length ||
466-
requiredParameterTypes[parameterCount - 1] !=
467-
(args[argumentCount - 1] != null ? args[argumentCount - 1].getClass() : null)) {
468-
473+
if (parameterCount != argumentCount || !lastRequiredParameterType.isInstance(lastArgument)) {
469474
// Create an array for the leading arguments plus the varargs array argument.
470475
Object[] newArgs = new Object[parameterCount];
471476
// Copy all leading arguments to the new array, omitting the varargs array argument.
@@ -477,7 +482,7 @@ public static Object[] setupArgumentsForVarargsInvocation(Class<?>[] requiredPar
477482
if (argumentCount >= parameterCount) {
478483
varargsArraySize = argumentCount - (parameterCount - 1);
479484
}
480-
Class<?> componentType = requiredParameterTypes[parameterCount - 1].componentType();
485+
Class<?> componentType = lastRequiredParameterType.componentType();
481486
Object varargsArray = Array.newInstance(componentType, varargsArraySize);
482487
for (int i = 0; i < varargsArraySize; i++) {
483488
Array.set(varargsArray, i, args[parameterCount - 1 + i]);
@@ -486,6 +491,7 @@ public static Object[] setupArgumentsForVarargsInvocation(Class<?>[] requiredPar
486491
newArgs[newArgs.length - 1] = varargsArray;
487492
return newArgs;
488493
}
494+
489495
return args;
490496
}
491497

spring-expression/src/test/java/org/springframework/expression/spel/SpelCompilationCoverageTests.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4994,9 +4994,20 @@ void methodReferenceVarargs() {
49944994
assertThat(tc.s).isEqualTo("aaabbbccc");
49954995
tc.reset();
49964996

4997+
expression = parser.parseExpression("sixteen(seventeen)");
4998+
assertCannotCompile(expression);
4999+
expression.getValue(tc);
5000+
assertThat(tc.s).isEqualTo("aaabbbccc");
5001+
assertCanCompile(expression);
5002+
tc.reset();
5003+
// see TODO below
5004+
// expression.getValue(tc);
5005+
// assertThat(tc.s).isEqualTo("aaabbbccc");
5006+
// tc.reset();
5007+
49975008
// TODO Determine why the String[] is passed as the first element of the Object... varargs array instead of the entire varargs array.
49985009
// expression = parser.parseExpression("sixteen(stringArray)");
4999-
// assertCantCompile(expression);
5010+
// assertCannotCompile(expression);
50005011
// expression.getValue(tc);
50015012
// assertThat(tc.s).isEqualTo("aaabbbccc");
50025013
// assertCanCompile(expression);
@@ -6848,6 +6859,10 @@ public void sixteen(Object... vargs) {
68486859
}
68496860
}
68506861
}
6862+
6863+
public String[] seventeen() {
6864+
return new String[] { "aaa", "bbb", "ccc" };
6865+
}
68516866
}
68526867

68536868

spring-expression/src/test/java/org/springframework/expression/spel/support/ReflectionHelperTests.java

Lines changed: 67 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@
4040

4141
import static org.assertj.core.api.Assertions.assertThat;
4242
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
43+
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
44+
import static org.assertj.core.api.InstanceOfAssertFactories.array;
4345
import static org.springframework.expression.spel.support.ReflectionHelper.ArgumentsMatchKind.CLOSE;
4446
import static org.springframework.expression.spel.support.ReflectionHelper.ArgumentsMatchKind.EXACT;
4547
import static org.springframework.expression.spel.support.ReflectionHelper.ArgumentsMatchKind.REQUIRES_CONVERSION;
@@ -250,16 +252,73 @@ void convertAllArguments() throws Exception {
250252
checkArguments(args, "3", null, "3.0");
251253
}
252254

255+
@Test
256+
void setupArgumentsForVarargsInvocationPreconditions() {
257+
assertThatIllegalArgumentException()
258+
.isThrownBy(() -> ReflectionHelper.setupArgumentsForVarargsInvocation(new Class[] {}, "a"))
259+
.withMessage("Required parameter types array must not be empty");
260+
261+
assertThatIllegalArgumentException()
262+
.isThrownBy(() -> ReflectionHelper.setupArgumentsForVarargsInvocation(
263+
new Class<?>[] { Integer.class, Integer.class }, 123))
264+
.withMessage("The last required parameter type must be an array to support varargs invocation");
265+
}
266+
253267
@Test
254268
void setupArgumentsForVarargsInvocation() {
255-
Object[] newArray = ReflectionHelper.setupArgumentsForVarargsInvocation(
256-
new Class<?>[] {String[].class}, "a", "b", "c");
257-
258-
assertThat(newArray).hasSize(1);
259-
Object firstParam = newArray[0];
260-
assertThat(firstParam.getClass().componentType()).isEqualTo(String.class);
261-
Object[] firstParamArray = (Object[]) firstParam;
262-
assertThat(firstParamArray).containsExactly("a", "b", "c");
269+
Object[] newArray;
270+
271+
newArray = ReflectionHelper.setupArgumentsForVarargsInvocation(new Class<?>[] { String[].class }, "a", "b", "c");
272+
assertThat(newArray)
273+
.singleElement()
274+
.asInstanceOf(array(String[].class))
275+
.containsExactly("a", "b", "c");
276+
277+
newArray = ReflectionHelper.setupArgumentsForVarargsInvocation(new Class<?>[] { Object[].class }, "a", "b", "c");
278+
assertThat(newArray)
279+
.singleElement()
280+
.asInstanceOf(array(Object[].class))
281+
.containsExactly("a", "b", "c");
282+
283+
newArray = ReflectionHelper.setupArgumentsForVarargsInvocation(
284+
new Class<?>[] { Integer.class, Integer.class, String[].class }, 123, 456, "a", "b", "c");
285+
assertThat(newArray).satisfiesExactly(
286+
one -> assertThat(one).isEqualTo(123),
287+
two -> assertThat(two).isEqualTo(456),
288+
three -> assertThat(three).asInstanceOf(array(String[].class)).containsExactly("a", "b", "c"));
289+
290+
newArray = ReflectionHelper.setupArgumentsForVarargsInvocation(new Class<?>[] { String[].class });
291+
assertThat(newArray)
292+
.singleElement()
293+
.asInstanceOf(array(String[].class))
294+
.isEmpty();
295+
296+
newArray = ReflectionHelper.setupArgumentsForVarargsInvocation(
297+
new Class<?>[] { String[].class }, new Object[] { new String[] { "a", "b", "c" } });
298+
assertThat(newArray)
299+
.singleElement()
300+
.asInstanceOf(array(String[].class))
301+
.containsExactly("a", "b", "c");
302+
303+
newArray = ReflectionHelper.setupArgumentsForVarargsInvocation(
304+
new Class<?>[] { Object[].class }, new Object[] { new String[] { "a", "b", "c" } });
305+
assertThat(newArray)
306+
.singleElement()
307+
.asInstanceOf(array(Object[].class))
308+
.containsExactly("a", "b", "c");
309+
310+
newArray = ReflectionHelper.setupArgumentsForVarargsInvocation(new Class<?>[] { String[].class }, "a");
311+
assertThat(newArray)
312+
.singleElement()
313+
.asInstanceOf(array(String[].class))
314+
.containsExactly("a");
315+
316+
newArray = ReflectionHelper.setupArgumentsForVarargsInvocation(new Class<?>[] { String[].class }, new Object[] { null });
317+
assertThat(newArray)
318+
.singleElement()
319+
.asInstanceOf(array(String[].class))
320+
.singleElement()
321+
.isNull();
263322
}
264323

265324
@Test

0 commit comments

Comments
 (0)