Skip to content

SpEL fails to invoke MethodHandle function reference accepting only varargs #34109

@Nephery

Description

@Nephery

SpEL fails to invoke function references whose function handle only consists of varargs parameters.

org.springframework.expression.spel.SpelEvaluationException: EL1023E: A problem occurred whilst attempting to invoke the function 'varArgsFunction': 'Cannot cast [Ljava.lang.String; to java.lang.String'

	at org.springframework.expression.spel.ast.FunctionReference.executeFunctionViaMethodHandle(FunctionReference.java:257)
	at org.springframework.expression.spel.ast.FunctionReference.getValueInternal(FunctionReference.java:97)
	at org.springframework.expression.spel.ast.SpelNodeImpl.getValue(SpelNodeImpl.java:114)
	at org.springframework.expression.spel.standard.SpelExpression.getValue(SpelExpression.java:273)
	at test.ReproduceVarArgsBugTest.testVarArgsFunction(ReproduceVarArgsBugTest.java:21)
	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
Caused by: java.lang.ClassCastException: Cannot cast [Ljava.lang.String; to java.lang.String
	at java.base/java.lang.Class.cast(Class.java:3889)
	at java.base/java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:732)
	at java.base/java.lang.invoke.MethodHandleImpl$AsVarargsCollector.invokeWithArguments(MethodHandleImpl.java:535)
	at org.springframework.expression.spel.ast.FunctionReference.executeFunctionViaMethodHandle(FunctionReference.java:253)

This seems to be failing because in FunctionReference, methodHandle.invokeWithArguments(functionArgs) is invoked with functionArgs being set as Object[] {String[] {"a", "b", "c"}}. Instead of being wrapped in an Object[], functionArgs should have just been String[] {"a", "b", "c"}.

Reproduction

Spring Framework: 6.1.16

Here's a simple test class to reproduce it:

package test;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;

public class ReproduceVarArgsBugTest {

	// this test fails since varArgsFunction only consists of varargs parameters
	@Test
	void testVarArgsFunction() throws Exception {
		SpelExpressionParser parser = new SpelExpressionParser();
		StandardEvaluationContext context = new StandardEvaluationContext();
		MethodHandle methodHandle = MethodHandles.lookup().findStatic(ReproduceVarArgsBugTest.class,
				"varArgsFunction", MethodType.methodType(String.class, String[].class));
		context.registerFunction("varArgsFunction", methodHandle);
		Assertions.assertEquals("a,b,c", parser.parseExpression("#varArgsFunction('a', 'b', 'c')").getValue(context));
	}

	public static String varArgsFunction(String... input) {
		return String.join(",", input);
	}

	// this passes because varArgsWithOtherParamFunction has at least one parameter that isn't varargs (i.e. otherParam)
	@Test
	void testVarArgsWithOtherParamFunction() throws Exception {
		SpelExpressionParser parser = new SpelExpressionParser();
		StandardEvaluationContext context = new StandardEvaluationContext();
		MethodHandle methodHandle = MethodHandles.lookup().findStatic(ReproduceVarArgsBugTest.class,
				"varArgsWithOtherParamFunction", MethodType.methodType(String.class, String.class, String[].class));
		context.registerFunction("varArgsWithOtherParamFunction", methodHandle);
		Assertions.assertEquals("a,b,c", parser.parseExpression("#varArgsWithOtherParamFunction('a', 'b', 'c')").getValue(context));
	}

	public static String varArgsWithOtherParamFunction(String otherParam, String... input) {
		return otherParam + "," + String.join(",", input);
	}
}

Metadata

Metadata

Assignees

Labels

in: coreIssues in core modules (aop, beans, core, context, expression)status: backportedAn issue that has been backported to maintenance branchestype: bugA general bug

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions