Merge branch '6.2.x'
This commit is contained in:
commit
18e31fcfba
|
@ -319,8 +319,8 @@ public abstract class ReflectionHelper {
|
|||
(sourceType.isArray() && !sourceType.isAssignableTo(targetType)) ||
|
||||
(argument instanceof List)) {
|
||||
|
||||
TypeDescriptor targetTypeToUse =
|
||||
(sourceType.isArray() || argument instanceof List ? targetType : componentTypeDesc);
|
||||
TypeDescriptor targetTypeToUse = (sourceType.isArray() || argument instanceof List ||
|
||||
converter.canConvert(sourceType, targetType) ? targetType : componentTypeDesc);
|
||||
arguments[varargsPosition] = converter.convertValue(argument, sourceType, targetTypeToUse);
|
||||
}
|
||||
// Possible outcomes of the above if-else block:
|
||||
|
@ -421,8 +421,8 @@ public abstract class ReflectionHelper {
|
|||
(sourceType.isArray() && !sourceType.isAssignableTo(varargsArrayType)) ||
|
||||
(argument instanceof List)) {
|
||||
|
||||
TypeDescriptor targetTypeToUse =
|
||||
(sourceType.isArray() || argument instanceof List ? varargsArrayType : varargsComponentType);
|
||||
TypeDescriptor targetTypeToUse = (sourceType.isArray() || argument instanceof List ||
|
||||
converter.canConvert(sourceType, varargsArrayType) ? varargsArrayType : varargsComponentType);
|
||||
arguments[varargsPosition] = converter.convertValue(argument, sourceType, targetTypeToUse);
|
||||
}
|
||||
// Possible outcomes of the above if-else block:
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -118,6 +118,11 @@ class TestScenarioCreator {
|
|||
"varargsFunction", MethodType.methodType(String.class, String[].class));
|
||||
testContext.registerFunction("varargsFunctionHandle", varargsFunctionHandle);
|
||||
|
||||
// #varargsObjectFunctionHandle(args...)
|
||||
MethodHandle varargsObjectFunctionHandle = MethodHandles.lookup().findStatic(TestScenarioCreator.class,
|
||||
"varargsObjectFunction", MethodType.methodType(String.class, Object[].class));
|
||||
testContext.registerFunction("varargsObjectFunctionHandle", varargsObjectFunctionHandle);
|
||||
|
||||
// #add(int, int)
|
||||
MethodHandle add = MethodHandles.lookup().findStatic(TestScenarioCreator.class,
|
||||
"add", MethodType.methodType(int.class, int.class, int.class));
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -16,11 +16,21 @@
|
|||
|
||||
package org.springframework.expression.spel;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.core.convert.converter.GenericConverter;
|
||||
import org.springframework.core.convert.support.DefaultConversionService;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.spel.standard.SpelExpression;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
import org.springframework.expression.spel.support.StandardTypeConverter;
|
||||
import org.springframework.expression.spel.support.StandardTypeLocator;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
|
@ -266,11 +276,10 @@ class VariableAndFunctionTests extends AbstractExpressionTests {
|
|||
|
||||
@Test
|
||||
void functionMethodMustBeStatic() throws Exception {
|
||||
SpelExpressionParser parser = new SpelExpressionParser();
|
||||
StandardEvaluationContext ctx = new StandardEvaluationContext();
|
||||
ctx.setVariable("notStatic", this.getClass().getMethod("nonStatic"));
|
||||
context.registerFunction("nonStatic", this.getClass().getMethod("nonStatic"));
|
||||
SpelExpression expression = parser.parseRaw("#nonStatic()");
|
||||
assertThatExceptionOfType(SpelEvaluationException.class)
|
||||
.isThrownBy(() -> parser.parseRaw("#notStatic()").getValue(ctx))
|
||||
.isThrownBy(() -> expression.getValue(context))
|
||||
.satisfies(ex -> assertThat(ex.getMessageCode()).isEqualTo(FUNCTION_MUST_BE_STATIC));
|
||||
}
|
||||
|
||||
|
@ -279,4 +288,75 @@ class VariableAndFunctionTests extends AbstractExpressionTests {
|
|||
public void nonStatic() {
|
||||
}
|
||||
|
||||
|
||||
@Nested // gh-34371
|
||||
class VarargsAndPojoToArrayConversionTests {
|
||||
|
||||
private final StandardEvaluationContext context = TestScenarioCreator.getTestEvaluationContext();
|
||||
|
||||
private final ArrayHolder arrayHolder = new ArrayHolder("a", "b", "c");
|
||||
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
DefaultConversionService conversionService = new DefaultConversionService();
|
||||
conversionService.addConverter(new ArrayHolderConverter());
|
||||
context.setTypeConverter(new StandardTypeConverter(conversionService));
|
||||
context.setVariable("arrayHolder", arrayHolder);
|
||||
}
|
||||
|
||||
@Test
|
||||
void functionWithVarargsAndPojoToArrayConversion() {
|
||||
// #varargsFunction: static String varargsFunction(String... strings) -> Arrays.toString(strings)
|
||||
evaluate("#varargsFunction(#arrayHolder)", "[a, b, c]");
|
||||
|
||||
// #varargsObjectFunction: static String varargsObjectFunction(Object... args) -> Arrays.toString(args)
|
||||
//
|
||||
// Since ArrayHolder is an "instanceof Object" and Object is the varargs component type,
|
||||
// we expect the ArrayHolder not to be converted to an array but rather to be passed
|
||||
// "as is" as a single argument to the varargs method.
|
||||
evaluate("#varargsObjectFunction(#arrayHolder)", "[" + arrayHolder.toString() + "]");
|
||||
}
|
||||
|
||||
@Test
|
||||
void functionWithVarargsAndPojoToArrayConversionViaMethodHandle() {
|
||||
// #varargsFunctionHandle: static String varargsFunction(String... strings) -> Arrays.toString(strings)
|
||||
evaluate("#varargsFunctionHandle(#arrayHolder)", "[a, b, c]");
|
||||
|
||||
// #varargsObjectFunctionHandle: static String varargsObjectFunction(Object... args) -> Arrays.toString(args)
|
||||
//
|
||||
// Since ArrayHolder is an "instanceof Object" and Object is the varargs component type,
|
||||
// we expect the ArrayHolder not to be converted to an array but rather to be passed
|
||||
// "as is" as a single argument to the varargs method.
|
||||
evaluate("#varargsObjectFunctionHandle(#arrayHolder)", "[" + arrayHolder.toString() + "]");
|
||||
}
|
||||
|
||||
private void evaluate(String expression, Object expectedValue) {
|
||||
Expression expr = parser.parseExpression(expression);
|
||||
assertThat(expr).as("expression").isNotNull();
|
||||
Object value = expr.getValue(context);
|
||||
assertThat(value).as("expression '" + expression + "'").isEqualTo(expectedValue);
|
||||
}
|
||||
|
||||
|
||||
record ArrayHolder(String... array) {
|
||||
}
|
||||
|
||||
static class ArrayHolderConverter implements GenericConverter {
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Set<ConvertiblePair> getConvertibleTypes() {
|
||||
return Set.of(new ConvertiblePair(ArrayHolder.class, Object[].class));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String[] convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
return ((ArrayHolder) source).array();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue