Merge branch '6.1.x'
This commit is contained in:
commit
bb64e22266
|
@ -180,13 +180,28 @@ public class FunctionReference extends SpelNodeImpl {
|
||||||
int spelParamCount = functionArgs.length;
|
int spelParamCount = functionArgs.length;
|
||||||
int declaredParamCount = declaredParams.parameterCount();
|
int declaredParamCount = declaredParams.parameterCount();
|
||||||
|
|
||||||
|
// We don't use methodHandle.isVarargsCollector(), because a MethodHandle created via
|
||||||
|
// MethodHandle#bindTo() is "never a variable-arity method handle, even if the original
|
||||||
|
// target method handle was." Thus, we merely assume/suspect that varargs are supported
|
||||||
|
// if the last parameter type is an array.
|
||||||
boolean isSuspectedVarargs = declaredParams.lastParameterType().isArray();
|
boolean isSuspectedVarargs = declaredParams.lastParameterType().isArray();
|
||||||
|
|
||||||
if (spelParamCount < declaredParamCount || (spelParamCount > declaredParamCount && !isSuspectedVarargs)) {
|
if (isSuspectedVarargs) {
|
||||||
// incorrect number, including more arguments and not a vararg
|
if (spelParamCount < declaredParamCount - 1) {
|
||||||
// perhaps a subset of arguments was provided but the MethodHandle wasn't bound?
|
// Varargs, but the number of provided arguments (potentially 0) is insufficient
|
||||||
|
// for a varargs invocation for the number of declared parameters.
|
||||||
|
//
|
||||||
|
// As stated in the Javadoc for MethodHandle#asVarargsCollector(), "the caller
|
||||||
|
// must supply, at a minimum, N-1 arguments, where N is the arity of the target."
|
||||||
|
throw new SpelEvaluationException(SpelMessage.INCORRECT_NUMBER_OF_ARGUMENTS_TO_FUNCTION,
|
||||||
|
this.name, spelParamCount, (declaredParamCount - 1) + " or more");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (spelParamCount != declaredParamCount) {
|
||||||
|
// Incorrect number and not varargs. Perhaps a subset of arguments was provided,
|
||||||
|
// but the MethodHandle wasn't bound?
|
||||||
throw new SpelEvaluationException(SpelMessage.INCORRECT_NUMBER_OF_ARGUMENTS_TO_FUNCTION,
|
throw new SpelEvaluationException(SpelMessage.INCORRECT_NUMBER_OF_ARGUMENTS_TO_FUNCTION,
|
||||||
this.name, functionArgs.length, declaredParamCount);
|
this.name, spelParamCount, declaredParamCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
// simplest case: the MethodHandle is fully bound or represents a static method with no params:
|
// simplest case: the MethodHandle is fully bound or represents a static method with no params:
|
||||||
|
|
|
@ -105,7 +105,12 @@ class TestScenarioCreator {
|
||||||
MethodHandle formatObjectVarargs = MethodHandles.lookup().findStatic(TestScenarioCreator.class,
|
MethodHandle formatObjectVarargs = MethodHandles.lookup().findStatic(TestScenarioCreator.class,
|
||||||
"formatObjectVarargs", MethodType.methodType(String.class, String.class, Object[].class));
|
"formatObjectVarargs", MethodType.methodType(String.class, String.class, Object[].class));
|
||||||
testContext.registerFunction("formatObjectVarargs", formatObjectVarargs);
|
testContext.registerFunction("formatObjectVarargs", formatObjectVarargs);
|
||||||
}
|
|
||||||
|
// #add(int, int)
|
||||||
|
MethodHandle add = MethodHandles.lookup().findStatic(TestScenarioCreator.class,
|
||||||
|
"add", MethodType.methodType(int.class, int.class, int.class));
|
||||||
|
testContext.registerFunction("add", add);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register some variables that can be referenced from the tests
|
* Register some variables that can be referenced from the tests
|
||||||
|
@ -163,4 +168,8 @@ class TestScenarioCreator {
|
||||||
return String.format(format, args);
|
return String.format(format, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int add(int x, int y) {
|
||||||
|
return x + y;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,9 +54,13 @@ class VariableAndFunctionTests extends AbstractExpressionTests {
|
||||||
evaluateAndCheckError("#reverseInt(1,2)", INCORRECT_NUMBER_OF_ARGUMENTS_TO_FUNCTION, 0, "reverseInt", 2, 3);
|
evaluateAndCheckError("#reverseInt(1,2)", INCORRECT_NUMBER_OF_ARGUMENTS_TO_FUNCTION, 0, "reverseInt", 2, 3);
|
||||||
evaluateAndCheckError("#reverseInt(1,2,3,4)", INCORRECT_NUMBER_OF_ARGUMENTS_TO_FUNCTION, 0, "reverseInt", 4, 3);
|
evaluateAndCheckError("#reverseInt(1,2,3,4)", INCORRECT_NUMBER_OF_ARGUMENTS_TO_FUNCTION, 0, "reverseInt", 4, 3);
|
||||||
|
|
||||||
// MethodHandle: #message(template, args...)
|
// MethodHandle: #message(String, Object...)
|
||||||
evaluateAndCheckError("#message()", INCORRECT_NUMBER_OF_ARGUMENTS_TO_FUNCTION, 0, "message", 0, 2);
|
evaluateAndCheckError("#message()", INCORRECT_NUMBER_OF_ARGUMENTS_TO_FUNCTION, 0, "message", 0, "1 or more");
|
||||||
evaluateAndCheckError("#message('%s')", INCORRECT_NUMBER_OF_ARGUMENTS_TO_FUNCTION, 0, "message", 1, 2);
|
|
||||||
|
// MethodHandle: #add(int, int)
|
||||||
|
evaluateAndCheckError("#add()", INCORRECT_NUMBER_OF_ARGUMENTS_TO_FUNCTION, 0, "add", 0, 2);
|
||||||
|
evaluateAndCheckError("#add(1)", INCORRECT_NUMBER_OF_ARGUMENTS_TO_FUNCTION, 0, "add", 1, 2);
|
||||||
|
evaluateAndCheckError("#add(1, 2, 3)", INCORRECT_NUMBER_OF_ARGUMENTS_TO_FUNCTION, 0, "add", 3, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -107,12 +111,6 @@ class VariableAndFunctionTests extends AbstractExpressionTests {
|
||||||
void functionWithVarargsViaMethodHandle_CurrentlyFailing() {
|
void functionWithVarargsViaMethodHandle_CurrentlyFailing() {
|
||||||
// Calling 'public static String formatObjectVarargs(String format, Object... args)' -> String.format(format, args)
|
// Calling 'public static String formatObjectVarargs(String format, Object... args)' -> String.format(format, args)
|
||||||
|
|
||||||
// No var-args and no conversion necessary
|
|
||||||
evaluate("#formatObjectVarargs('x')", "x", String.class);
|
|
||||||
|
|
||||||
// No var-args but conversion necessary
|
|
||||||
evaluate("#formatObjectVarargs(9)", "9", String.class);
|
|
||||||
|
|
||||||
// No conversion necessary
|
// No conversion necessary
|
||||||
evaluate("#formatObjectVarargs('x -> %s', new Object[]{''})", "x -> ", String.class);
|
evaluate("#formatObjectVarargs('x -> %s', new Object[]{''})", "x -> ", String.class);
|
||||||
evaluate("#formatObjectVarargs('x -> %s', new String[]{''})", "x -> ", String.class);
|
evaluate("#formatObjectVarargs('x -> %s', new String[]{''})", "x -> ", String.class);
|
||||||
|
@ -128,13 +126,21 @@ class VariableAndFunctionTests extends AbstractExpressionTests {
|
||||||
void functionWithVarargsViaMethodHandle() {
|
void functionWithVarargsViaMethodHandle() {
|
||||||
// Calling 'public static String formatObjectVarargs(String format, Object... args)' -> String.format(format, args)
|
// Calling 'public static String formatObjectVarargs(String format, Object... args)' -> String.format(format, args)
|
||||||
|
|
||||||
|
// No var-args and no conversion necessary
|
||||||
|
evaluate("#formatObjectVarargs('x')", "x", String.class);
|
||||||
|
|
||||||
|
// No var-args but conversion necessary
|
||||||
|
evaluate("#formatObjectVarargs(9)", "9", String.class);
|
||||||
|
|
||||||
// No conversion necessary
|
// No conversion necessary
|
||||||
|
evaluate("#add(3, 4)", 7, Integer.class);
|
||||||
evaluate("#formatObjectVarargs('x -> %s', '')", "x -> ", String.class);
|
evaluate("#formatObjectVarargs('x -> %s', '')", "x -> ", String.class);
|
||||||
evaluate("#formatObjectVarargs('x -> %s', ' ')", "x -> ", String.class);
|
evaluate("#formatObjectVarargs('x -> %s', ' ')", "x -> ", String.class);
|
||||||
evaluate("#formatObjectVarargs('x -> %s', 'a')", "x -> a", String.class);
|
evaluate("#formatObjectVarargs('x -> %s', 'a')", "x -> a", String.class);
|
||||||
evaluate("#formatObjectVarargs('x -> %s %s %s', 'a', 'b', 'c')", "x -> a b c", String.class);
|
evaluate("#formatObjectVarargs('x -> %s %s %s', 'a', 'b', 'c')", "x -> a b c", String.class);
|
||||||
|
|
||||||
// Conversion necessary
|
// Conversion necessary
|
||||||
|
evaluate("#add('2', 5.0)", 7, Integer.class);
|
||||||
evaluate("#formatObjectVarargs('x -> %s %s', 2, 3)", "x -> 2 3", String.class);
|
evaluate("#formatObjectVarargs('x -> %s %s', 2, 3)", "x -> 2 3", String.class);
|
||||||
evaluate("#formatObjectVarargs('x -> %s %s', 'a', 3.0d)", "x -> a 3.0", String.class);
|
evaluate("#formatObjectVarargs('x -> %s %s', 'a', 3.0d)", "x -> a 3.0", String.class);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue