Support varargs-only MethodHandle as SpEL function
Prior to this commit, if a MethodHandle was registered as a custom function in the Spring Expression Language (SpEL) for a static method that accepted only a variable argument list (for example, `static String func(String... args)`), attempting to invoke the registered function within a SpEL expression resulted in a ClassCastException because the varargs array was unnecessarily wrapped in an Object[]. This commit modifies the logic in FunctionReference's internal executeFunctionViaMethodHandle() method to address that. Closes gh-34109
This commit is contained in:
parent
a942362221
commit
c1236a3340
|
@ -229,8 +229,9 @@ public class FunctionReference extends SpelNodeImpl {
|
|||
ReflectionHelper.convertAllMethodHandleArguments(converter, functionArgs, methodHandle, varArgPosition);
|
||||
|
||||
if (isSuspectedVarargs) {
|
||||
if (declaredParamCount == 1) {
|
||||
// We only repackage the varargs if it is the ONLY argument -- for example,
|
||||
if (declaredParamCount == 1 && !methodHandle.isVarargsCollector()) {
|
||||
// We only repackage the arguments if the MethodHandle accepts a single
|
||||
// argument AND the MethodHandle is not a "varargs collector" -- for example,
|
||||
// when we are dealing with a bound MethodHandle.
|
||||
functionArgs = ReflectionHelper.setupArgumentsForVarargsInvocation(
|
||||
methodHandle.type().parameterArray(), functionArgs);
|
||||
|
|
|
@ -108,11 +108,16 @@ class TestScenarioCreator {
|
|||
"formatObjectVarargs", MethodType.methodType(String.class, String.class, Object[].class));
|
||||
testContext.registerFunction("formatObjectVarargs", formatObjectVarargs);
|
||||
|
||||
// #formatObjectVarargs(format, args...)
|
||||
// #formatPrimitiveVarargs(format, args...)
|
||||
MethodHandle formatPrimitiveVarargs = MethodHandles.lookup().findStatic(TestScenarioCreator.class,
|
||||
"formatPrimitiveVarargs", MethodType.methodType(String.class, String.class, int[].class));
|
||||
testContext.registerFunction("formatPrimitiveVarargs", formatPrimitiveVarargs);
|
||||
|
||||
// #varargsFunctionHandle(args...)
|
||||
MethodHandle varargsFunctionHandle = MethodHandles.lookup().findStatic(TestScenarioCreator.class,
|
||||
"varargsFunction", MethodType.methodType(String.class, String[].class));
|
||||
testContext.registerFunction("varargsFunctionHandle", varargsFunctionHandle);
|
||||
|
||||
// #add(int, int)
|
||||
MethodHandle add = MethodHandles.lookup().findStatic(TestScenarioCreator.class,
|
||||
"add", MethodType.methodType(int.class, int.class, int.class));
|
||||
|
|
|
@ -79,6 +79,8 @@ class VariableAndFunctionTests extends AbstractExpressionTests {
|
|||
|
||||
@Test
|
||||
void functionWithVarargs() {
|
||||
// static String varargsFunction(String... strings) -> Arrays.toString(strings)
|
||||
|
||||
evaluate("#varargsFunction()", "[]", String.class);
|
||||
evaluate("#varargsFunction(new String[0])", "[]", String.class);
|
||||
evaluate("#varargsFunction('a')", "[a]", String.class);
|
||||
|
@ -241,6 +243,27 @@ class VariableAndFunctionTests extends AbstractExpressionTests {
|
|||
evaluate("#formatObjectVarargs('x -> %s %s %s', {'a', 'b', 'c'})", expected, String.class);
|
||||
}
|
||||
|
||||
@Test // gh-34109
|
||||
void functionViaMethodHandleForStaticMethodThatAcceptsOnlyVarargs() {
|
||||
// #varargsFunctionHandle: static String varargsFunction(String... strings) -> Arrays.toString(strings)
|
||||
|
||||
evaluate("#varargsFunctionHandle()", "[]", String.class);
|
||||
evaluate("#varargsFunctionHandle(new String[0])", "[]", String.class);
|
||||
evaluate("#varargsFunctionHandle('a')", "[a]", String.class);
|
||||
evaluate("#varargsFunctionHandle('a','b','c')", "[a, b, c]", String.class);
|
||||
evaluate("#varargsFunctionHandle(new String[]{'a','b','c'})", "[a, b, c]", String.class);
|
||||
// Conversion from int to String
|
||||
evaluate("#varargsFunctionHandle(25)", "[25]", String.class);
|
||||
evaluate("#varargsFunctionHandle('b',25)", "[b, 25]", String.class);
|
||||
evaluate("#varargsFunctionHandle(new int[]{1, 2, 3})", "[1, 2, 3]", String.class);
|
||||
// Strings that contain a comma
|
||||
evaluate("#varargsFunctionHandle('a,b')", "[a,b]", String.class);
|
||||
evaluate("#varargsFunctionHandle('a', 'x,y', 'd')", "[a, x,y, d]", String.class);
|
||||
// null values
|
||||
evaluate("#varargsFunctionHandle(null)", "[null]", String.class);
|
||||
evaluate("#varargsFunctionHandle('a',null,'b')", "[a, null, b]", String.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void functionMethodMustBeStatic() throws Exception {
|
||||
SpelExpressionParser parser = new SpelExpressionParser();
|
||||
|
|
Loading…
Reference in New Issue