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)) ||
|
(sourceType.isArray() && !sourceType.isAssignableTo(targetType)) ||
|
||||||
(argument instanceof List)) {
|
(argument instanceof List)) {
|
||||||
|
|
||||||
TypeDescriptor targetTypeToUse =
|
TypeDescriptor targetTypeToUse = (sourceType.isArray() || argument instanceof List ||
|
||||||
(sourceType.isArray() || argument instanceof List ? targetType : componentTypeDesc);
|
converter.canConvert(sourceType, targetType) ? targetType : componentTypeDesc);
|
||||||
arguments[varargsPosition] = converter.convertValue(argument, sourceType, targetTypeToUse);
|
arguments[varargsPosition] = converter.convertValue(argument, sourceType, targetTypeToUse);
|
||||||
}
|
}
|
||||||
// Possible outcomes of the above if-else block:
|
// Possible outcomes of the above if-else block:
|
||||||
|
@ -421,8 +421,8 @@ public abstract class ReflectionHelper {
|
||||||
(sourceType.isArray() && !sourceType.isAssignableTo(varargsArrayType)) ||
|
(sourceType.isArray() && !sourceType.isAssignableTo(varargsArrayType)) ||
|
||||||
(argument instanceof List)) {
|
(argument instanceof List)) {
|
||||||
|
|
||||||
TypeDescriptor targetTypeToUse =
|
TypeDescriptor targetTypeToUse = (sourceType.isArray() || argument instanceof List ||
|
||||||
(sourceType.isArray() || argument instanceof List ? varargsArrayType : varargsComponentType);
|
converter.canConvert(sourceType, varargsArrayType) ? varargsArrayType : varargsComponentType);
|
||||||
arguments[varargsPosition] = converter.convertValue(argument, sourceType, targetTypeToUse);
|
arguments[varargsPosition] = converter.convertValue(argument, sourceType, targetTypeToUse);
|
||||||
}
|
}
|
||||||
// Possible outcomes of the above if-else block:
|
// 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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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));
|
"varargsFunction", MethodType.methodType(String.class, String[].class));
|
||||||
testContext.registerFunction("varargsFunctionHandle", varargsFunctionHandle);
|
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)
|
// #add(int, int)
|
||||||
MethodHandle add = MethodHandles.lookup().findStatic(TestScenarioCreator.class,
|
MethodHandle add = MethodHandles.lookup().findStatic(TestScenarioCreator.class,
|
||||||
"add", MethodType.methodType(int.class, int.class, int.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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -16,11 +16,21 @@
|
||||||
|
|
||||||
package org.springframework.expression.spel;
|
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.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.StandardEvaluationContext;
|
||||||
|
import org.springframework.expression.spel.support.StandardTypeConverter;
|
||||||
import org.springframework.expression.spel.support.StandardTypeLocator;
|
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.assertThat;
|
||||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||||
|
@ -266,11 +276,10 @@ class VariableAndFunctionTests extends AbstractExpressionTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void functionMethodMustBeStatic() throws Exception {
|
void functionMethodMustBeStatic() throws Exception {
|
||||||
SpelExpressionParser parser = new SpelExpressionParser();
|
context.registerFunction("nonStatic", this.getClass().getMethod("nonStatic"));
|
||||||
StandardEvaluationContext ctx = new StandardEvaluationContext();
|
SpelExpression expression = parser.parseRaw("#nonStatic()");
|
||||||
ctx.setVariable("notStatic", this.getClass().getMethod("nonStatic"));
|
|
||||||
assertThatExceptionOfType(SpelEvaluationException.class)
|
assertThatExceptionOfType(SpelEvaluationException.class)
|
||||||
.isThrownBy(() -> parser.parseRaw("#notStatic()").getValue(ctx))
|
.isThrownBy(() -> expression.getValue(context))
|
||||||
.satisfies(ex -> assertThat(ex.getMessageCode()).isEqualTo(FUNCTION_MUST_BE_STATIC));
|
.satisfies(ex -> assertThat(ex.getMessageCode()).isEqualTo(FUNCTION_MUST_BE_STATIC));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,4 +288,75 @@ class VariableAndFunctionTests extends AbstractExpressionTests {
|
||||||
public void nonStatic() {
|
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