Merge branch '6.1.x'
This commit is contained in:
commit
4de2aadf72
|
|
@ -220,7 +220,7 @@ public class FunctionReference extends SpelNodeImpl {
|
|||
}
|
||||
}
|
||||
|
||||
// more complex case, we need to look at conversion and vararg repacking
|
||||
// more complex case, we need to look at conversion and varargs repackaging
|
||||
Integer varArgPosition = null;
|
||||
if (isSuspectedVarargs) {
|
||||
varArgPosition = declaredParamCount - 1;
|
||||
|
|
@ -228,10 +228,29 @@ public class FunctionReference extends SpelNodeImpl {
|
|||
TypeConverter converter = state.getEvaluationContext().getTypeConverter();
|
||||
ReflectionHelper.convertAllMethodHandleArguments(converter, functionArgs, methodHandle, varArgPosition);
|
||||
|
||||
if (isSuspectedVarargs && declaredParamCount == 1) {
|
||||
// we only repack the varargs if it is the ONLY argument
|
||||
functionArgs = ReflectionHelper.setupArgumentsForVarargsInvocation(
|
||||
methodHandle.type().parameterArray(), functionArgs);
|
||||
if (isSuspectedVarargs) {
|
||||
if (declaredParamCount == 1) {
|
||||
// We only repackage the varargs if it is the ONLY argument -- for example,
|
||||
// when we are dealing with a bound MethodHandle.
|
||||
functionArgs = ReflectionHelper.setupArgumentsForVarargsInvocation(
|
||||
methodHandle.type().parameterArray(), functionArgs);
|
||||
}
|
||||
else if (spelParamCount == declaredParamCount) {
|
||||
// If the varargs were supplied already packaged in an array, we have to create
|
||||
// a new array, add the non-varargs arguments to the beginning of that array,
|
||||
// and add the unpackaged varargs arguments to the end of that array. The reason
|
||||
// is that MethodHandle.invokeWithArguments(Object...) does not expect varargs
|
||||
// to be packaged in an array, in contrast to how method invocation works with
|
||||
// reflection.
|
||||
int actualVarargsIndex = functionArgs.length - 1;
|
||||
if (actualVarargsIndex >= 0 && functionArgs[actualVarargsIndex].getClass().isArray()) {
|
||||
Object[] argsToUnpack = (Object[]) functionArgs[actualVarargsIndex];
|
||||
Object[] newArgs = new Object[actualVarargsIndex + argsToUnpack.length];
|
||||
System.arraycopy(functionArgs, 0, newArgs, 0, actualVarargsIndex);
|
||||
System.arraycopy(argsToUnpack, 0, newArgs, actualVarargsIndex, argsToUnpack.length);
|
||||
functionArgs = newArgs;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -355,10 +355,10 @@ public abstract class ReflectionHelper {
|
|||
MethodHandle methodHandle, @Nullable Integer varargsPosition) throws EvaluationException {
|
||||
|
||||
boolean conversionOccurred = false;
|
||||
MethodType methodHandleArgumentTypes = methodHandle.type();
|
||||
MethodType methodHandleType = methodHandle.type();
|
||||
if (varargsPosition == null) {
|
||||
for (int i = 0; i < arguments.length; i++) {
|
||||
Class<?> argumentClass = methodHandleArgumentTypes.parameterType(i);
|
||||
Class<?> argumentClass = methodHandleType.parameterType(i);
|
||||
ResolvableType resolvableType = ResolvableType.forClass(argumentClass);
|
||||
TypeDescriptor targetType = new TypeDescriptor(resolvableType, argumentClass, null);
|
||||
|
||||
|
|
@ -370,7 +370,7 @@ public abstract class ReflectionHelper {
|
|||
else {
|
||||
// Convert everything up to the varargs position
|
||||
for (int i = 0; i < varargsPosition; i++) {
|
||||
Class<?> argumentClass = methodHandleArgumentTypes.parameterType(i);
|
||||
Class<?> argumentClass = methodHandleType.parameterType(i);
|
||||
ResolvableType resolvableType = ResolvableType.forClass(argumentClass);
|
||||
TypeDescriptor targetType = new TypeDescriptor(resolvableType, argumentClass, null);
|
||||
|
||||
|
|
@ -379,10 +379,10 @@ public abstract class ReflectionHelper {
|
|||
conversionOccurred |= (argument != arguments[i]);
|
||||
}
|
||||
|
||||
Class<?> varArgClass = methodHandleArgumentTypes.lastParameterType().componentType();
|
||||
Class<?> varArgClass = methodHandleType.lastParameterType().componentType();
|
||||
ResolvableType varArgResolvableType = ResolvableType.forClass(varArgClass);
|
||||
TypeDescriptor varArgComponentType = new TypeDescriptor(varArgResolvableType, varArgClass, null);
|
||||
TypeDescriptor componentTypeDesc = varArgComponentType.getElementTypeDescriptor();
|
||||
TypeDescriptor targetType = new TypeDescriptor(varArgResolvableType, varArgClass, null);
|
||||
TypeDescriptor componentTypeDesc = targetType.getElementTypeDescriptor();
|
||||
// TODO Determine why componentTypeDesc can be null.
|
||||
// Assert.state(componentTypeDesc != null, "Component type must not be null for a varargs array");
|
||||
|
||||
|
|
@ -402,7 +402,7 @@ public abstract class ReflectionHelper {
|
|||
// convert a String containing a comma would result in the String being split and
|
||||
// repackaged in an array when it should be used as-is.
|
||||
else if (componentTypeDesc != null && !sourceType.isAssignableTo(componentTypeDesc)) {
|
||||
arguments[varargsPosition] = converter.convertValue(argument, sourceType, varArgComponentType);
|
||||
arguments[varargsPosition] = converter.convertValue(argument, sourceType, targetType);
|
||||
}
|
||||
// Possible outcomes of the above if-else block:
|
||||
// 1) the input argument was null, and nothing was done.
|
||||
|
|
@ -419,7 +419,7 @@ public abstract class ReflectionHelper {
|
|||
else {
|
||||
for (int i = varargsPosition; i < arguments.length; i++) {
|
||||
Object argument = arguments[i];
|
||||
arguments[i] = converter.convertValue(argument, TypeDescriptor.forObject(argument), varArgComponentType);
|
||||
arguments[i] = converter.convertValue(argument, TypeDescriptor.forObject(argument), targetType);
|
||||
conversionOccurred |= (argument != arguments[i]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
package org.springframework.expression.spel;
|
||||
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
|
|
@ -106,22 +105,6 @@ class VariableAndFunctionTests extends AbstractExpressionTests {
|
|||
evaluate("#varargsFunction2(9,'a',null,'b')", "9-[a, null, b]", String.class);
|
||||
}
|
||||
|
||||
@Disabled("Disabled until bugs are reported and fixed")
|
||||
@Test
|
||||
void functionWithVarargsViaMethodHandle_CurrentlyFailing() {
|
||||
// Calling 'public static String formatObjectVarargs(String format, Object... args)' -> String.format(format, args)
|
||||
|
||||
// No conversion necessary
|
||||
evaluate("#formatObjectVarargs('x -> %s', new Object[]{''})", "x -> ", String.class);
|
||||
evaluate("#formatObjectVarargs('x -> %s', new String[]{''})", "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 Object[]{'a'})", "x -> a", String.class);
|
||||
evaluate("#formatObjectVarargs('x -> %s', new String[]{'a'})", "x -> a", String.class);
|
||||
evaluate("#formatObjectVarargs('x -> %s %s %s', new Object[]{'a', 'b', 'c'})", "x -> a b c", String.class);
|
||||
evaluate("#formatObjectVarargs('x -> %s %s %s', new String[]{'a', 'b', 'c'})", "x -> a b c", String.class);
|
||||
}
|
||||
|
||||
@Test // gh-33013
|
||||
void functionWithVarargsViaMethodHandle() {
|
||||
// Calling 'public static String formatObjectVarargs(String format, Object... args)' -> String.format(format, args)
|
||||
|
|
@ -138,6 +121,14 @@ class VariableAndFunctionTests extends AbstractExpressionTests {
|
|||
evaluate("#formatObjectVarargs('x -> %s', ' ')", "x -> ", 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', new Object[]{''})", "x -> ", String.class);
|
||||
evaluate("#formatObjectVarargs('x -> %s', new String[]{''})", "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 Object[]{'a'})", "x -> a", String.class);
|
||||
evaluate("#formatObjectVarargs('x -> %s', new String[]{'a'})", "x -> a", String.class);
|
||||
evaluate("#formatObjectVarargs('x -> %s %s %s', new Object[]{'a', 'b', 'c'})", "x -> a b c", String.class);
|
||||
evaluate("#formatObjectVarargs('x -> %s %s %s', new String[]{'a', 'b', 'c'})", "x -> a b c", String.class);
|
||||
|
||||
// Conversion necessary
|
||||
evaluate("#add('2', 5.0)", 7, Integer.class);
|
||||
|
|
|
|||
Loading…
Reference in New Issue