|
|
|
|
@ -1,5 +1,5 @@
@@ -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,27 +16,24 @@
@@ -16,27 +16,24 @@
|
|
|
|
|
|
|
|
|
|
package org.springframework.expression.spel; |
|
|
|
|
|
|
|
|
|
import java.util.ArrayList; |
|
|
|
|
import java.util.Collection; |
|
|
|
|
import java.util.Collections; |
|
|
|
|
import java.util.List; |
|
|
|
|
import java.util.Set; |
|
|
|
|
|
|
|
|
|
import org.junit.jupiter.api.BeforeEach; |
|
|
|
|
import org.junit.jupiter.api.Test; |
|
|
|
|
|
|
|
|
|
import org.springframework.core.MethodParameter; |
|
|
|
|
import org.springframework.core.convert.ConversionService; |
|
|
|
|
import org.springframework.core.convert.TypeDescriptor; |
|
|
|
|
import org.springframework.core.convert.support.DefaultConversionService; |
|
|
|
|
import org.springframework.expression.EvaluationException; |
|
|
|
|
import org.springframework.expression.Expression; |
|
|
|
|
import org.springframework.expression.TypeConverter; |
|
|
|
|
import org.springframework.expression.spel.support.StandardEvaluationContext; |
|
|
|
|
import org.springframework.expression.spel.support.StandardTypeConverter; |
|
|
|
|
import org.springframework.util.ReflectionUtils; |
|
|
|
|
|
|
|
|
|
import static org.assertj.core.api.Assertions.assertThat; |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Expression evaluation where the TypeConverter plugged in is the |
|
|
|
|
* Expression evaluation where the TypeConverter plugged in uses the |
|
|
|
|
* {@link org.springframework.core.convert.support.GenericConversionService}. |
|
|
|
|
* |
|
|
|
|
* @author Andy Clement |
|
|
|
|
@ -44,54 +41,43 @@ import static org.assertj.core.api.Assertions.assertThat;
@@ -44,54 +41,43 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|
|
|
|
*/ |
|
|
|
|
class ExpressionWithConversionTests extends AbstractExpressionTests { |
|
|
|
|
|
|
|
|
|
private static List<String> listOfString = new ArrayList<>(); |
|
|
|
|
private static TypeDescriptor typeDescriptorForListOfString = null; |
|
|
|
|
private static List<Integer> listOfInteger = new ArrayList<>(); |
|
|
|
|
private static TypeDescriptor typeDescriptorForListOfInteger = null; |
|
|
|
|
|
|
|
|
|
static { |
|
|
|
|
listOfString.add("1"); |
|
|
|
|
listOfString.add("2"); |
|
|
|
|
listOfString.add("3"); |
|
|
|
|
listOfInteger.add(4); |
|
|
|
|
listOfInteger.add(5); |
|
|
|
|
listOfInteger.add(6); |
|
|
|
|
} |
|
|
|
|
private static final List<String> listOfString = List.of("1", "2", "3"); |
|
|
|
|
private static final List<Integer> listOfInteger = List.of(4, 5, 6); |
|
|
|
|
|
|
|
|
|
@BeforeEach |
|
|
|
|
void setUp() throws Exception { |
|
|
|
|
ExpressionWithConversionTests.typeDescriptorForListOfString = new TypeDescriptor(ExpressionWithConversionTests.class.getDeclaredField("listOfString")); |
|
|
|
|
ExpressionWithConversionTests.typeDescriptorForListOfInteger = new TypeDescriptor(ExpressionWithConversionTests.class.getDeclaredField("listOfInteger")); |
|
|
|
|
} |
|
|
|
|
private static final TypeDescriptor typeDescriptorForListOfString = |
|
|
|
|
new TypeDescriptor(ReflectionUtils.findField(ExpressionWithConversionTests.class, "listOfString")); |
|
|
|
|
private static TypeDescriptor typeDescriptorForListOfInteger = |
|
|
|
|
new TypeDescriptor(ReflectionUtils.findField(ExpressionWithConversionTests.class, "listOfInteger")); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Test the service can convert what we are about to use in the expression evaluation tests. |
|
|
|
|
*/ |
|
|
|
|
@Test |
|
|
|
|
void testConversionsAvailable() { |
|
|
|
|
TypeConvertorUsingConversionService tcs = new TypeConvertorUsingConversionService(); |
|
|
|
|
void conversionsAreSupportedByStandardTypeConverter() { |
|
|
|
|
StandardTypeConverter typeConverter = new StandardTypeConverter(); |
|
|
|
|
|
|
|
|
|
// ArrayList containing List<Integer> to List<String>
|
|
|
|
|
// List<Integer> to List<String>
|
|
|
|
|
Class<?> clazz = typeDescriptorForListOfString.getElementTypeDescriptor().getType(); |
|
|
|
|
assertThat(clazz).isEqualTo(String.class); |
|
|
|
|
List<?> l = (List<?>) tcs.convertValue(listOfInteger, TypeDescriptor.forObject(listOfInteger), typeDescriptorForListOfString); |
|
|
|
|
List<?> l = (List<?>) typeConverter.convertValue(listOfInteger, TypeDescriptor.forObject(listOfInteger), typeDescriptorForListOfString); |
|
|
|
|
assertThat(l).isNotNull(); |
|
|
|
|
|
|
|
|
|
// ArrayList containing List<String> to List<Integer>
|
|
|
|
|
// List<String> to List<Integer>
|
|
|
|
|
clazz = typeDescriptorForListOfInteger.getElementTypeDescriptor().getType(); |
|
|
|
|
assertThat(clazz).isEqualTo(Integer.class); |
|
|
|
|
|
|
|
|
|
l = (List<?>) tcs.convertValue(listOfString, TypeDescriptor.forObject(listOfString), typeDescriptorForListOfString); |
|
|
|
|
l = (List<?>) typeConverter.convertValue(listOfString, TypeDescriptor.forObject(listOfString), typeDescriptorForListOfString); |
|
|
|
|
assertThat(l).isNotNull(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
void testSetParameterizedList() { |
|
|
|
|
void setParameterizedList() { |
|
|
|
|
StandardEvaluationContext context = TestScenarioCreator.getTestEvaluationContext(); |
|
|
|
|
|
|
|
|
|
Expression e = parser.parseExpression("listOfInteger.size()"); |
|
|
|
|
assertThat(e.getValue(context, Integer.class)).isZero(); |
|
|
|
|
context.setTypeConverter(new TypeConvertorUsingConversionService()); |
|
|
|
|
|
|
|
|
|
// Assign a List<String> to the List<Integer> field - the component elements should be converted
|
|
|
|
|
parser.parseExpression("listOfInteger").setValue(context,listOfString); |
|
|
|
|
// size now 3
|
|
|
|
|
@ -101,7 +87,7 @@ class ExpressionWithConversionTests extends AbstractExpressionTests {
@@ -101,7 +87,7 @@ class ExpressionWithConversionTests extends AbstractExpressionTests {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
void testCoercionToCollectionOfPrimitive() throws Exception { |
|
|
|
|
void coercionToCollectionOfPrimitive() throws Exception { |
|
|
|
|
|
|
|
|
|
class TestTarget { |
|
|
|
|
@SuppressWarnings("unused") |
|
|
|
|
@ -115,28 +101,28 @@ class ExpressionWithConversionTests extends AbstractExpressionTests {
@@ -115,28 +101,28 @@ class ExpressionWithConversionTests extends AbstractExpressionTests {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
StandardEvaluationContext evaluationContext = new StandardEvaluationContext(); |
|
|
|
|
TypeConverter typeConverter = evaluationContext.getTypeConverter(); |
|
|
|
|
|
|
|
|
|
TypeDescriptor collectionType = new TypeDescriptor(new MethodParameter(TestTarget.class.getDeclaredMethod( |
|
|
|
|
"sum", Collection.class), 0)); |
|
|
|
|
// The type conversion is possible
|
|
|
|
|
assertThat(evaluationContext.getTypeConverter() |
|
|
|
|
.canConvert(TypeDescriptor.valueOf(String.class), collectionType)).isTrue(); |
|
|
|
|
assertThat(typeConverter.canConvert(TypeDescriptor.valueOf(String.class), collectionType)).isTrue(); |
|
|
|
|
// ... and it can be done successfully
|
|
|
|
|
assertThat(evaluationContext.getTypeConverter().convertValue("1,2,3,4", TypeDescriptor.valueOf(String.class), collectionType).toString()).isEqualTo("[1, 2, 3, 4]"); |
|
|
|
|
assertThat(typeConverter.convertValue("1,2,3,4", TypeDescriptor.valueOf(String.class), collectionType)) |
|
|
|
|
.hasToString("[1, 2, 3, 4]"); |
|
|
|
|
|
|
|
|
|
evaluationContext.setVariable("target", new TestTarget()); |
|
|
|
|
|
|
|
|
|
// OK up to here, so the evaluation should be fine...
|
|
|
|
|
// ... but this fails
|
|
|
|
|
int result = (Integer) parser.parseExpression("#target.sum(#root)").getValue(evaluationContext, "1,2,3,4"); |
|
|
|
|
assertThat(result).as("Wrong result: " + result).isEqualTo(10); |
|
|
|
|
|
|
|
|
|
int result = parser.parseExpression("#target.sum(#root)").getValue(evaluationContext, "1,2,3,4", int.class); |
|
|
|
|
assertThat(result).isEqualTo(10); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
void testConvert() { |
|
|
|
|
void convert() { |
|
|
|
|
Foo root = new Foo("bar"); |
|
|
|
|
Collection<String> foos = Collections.singletonList("baz"); |
|
|
|
|
Collection<String> foos = Set.of("baz"); |
|
|
|
|
|
|
|
|
|
StandardEvaluationContext context = new StandardEvaluationContext(root); |
|
|
|
|
|
|
|
|
|
@ -163,26 +149,7 @@ class ExpressionWithConversionTests extends AbstractExpressionTests {
@@ -163,26 +149,7 @@ class ExpressionWithConversionTests extends AbstractExpressionTests {
|
|
|
|
|
expression = parser.parseExpression("setFoos(getFoosAsObjects())"); |
|
|
|
|
expression.getValue(context); |
|
|
|
|
baz = root.getFoos().iterator().next(); |
|
|
|
|
assertThat(baz.value).isEqualTo("baz"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Type converter that uses the core conversion service. |
|
|
|
|
*/ |
|
|
|
|
private static class TypeConvertorUsingConversionService implements TypeConverter { |
|
|
|
|
|
|
|
|
|
private final ConversionService service = new DefaultConversionService(); |
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
public boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType) { |
|
|
|
|
return this.service.canConvert(sourceType, targetType); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
public Object convertValue(Object value, TypeDescriptor sourceType, TypeDescriptor targetType) throws EvaluationException { |
|
|
|
|
return this.service.convert(value, sourceType, targetType); |
|
|
|
|
} |
|
|
|
|
assertThat(baz.value).isEqualTo("quux"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -205,11 +172,11 @@ class ExpressionWithConversionTests extends AbstractExpressionTests {
@@ -205,11 +172,11 @@ class ExpressionWithConversionTests extends AbstractExpressionTests {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public Collection<String> getFoosAsStrings() { |
|
|
|
|
return Collections.singletonList("baz"); |
|
|
|
|
return Set.of("baz"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public Collection<?> getFoosAsObjects() { |
|
|
|
|
return Collections.singletonList("baz"); |
|
|
|
|
return Set.of("quux"); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|