Browse Source

Improve tests for indexing and collection selection/projection in SpEL

pull/32215/head
Sam Brannen 2 years ago
parent
commit
9a38355896
  1. 233
      spring-expression/src/test/java/org/springframework/expression/spel/IndexingTests.java
  2. 455
      spring-expression/src/test/java/org/springframework/expression/spel/SelectionAndProjectionTests.java

233
spring-expression/src/test/java/org/springframework/expression/spel/IndexingTests.java

@ -30,7 +30,6 @@ import java.util.Map; @@ -30,7 +30,6 @@ import java.util.Map;
import org.junit.jupiter.api.Test;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.EvaluationException;
import org.springframework.expression.Expression;
import org.springframework.expression.PropertyAccessor;
import org.springframework.expression.TypedValue;
@ -38,6 +37,9 @@ import org.springframework.expression.spel.standard.SpelExpressionParser; @@ -38,6 +37,9 @@ import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.springframework.expression.spel.SpelMessage.INDEXING_NOT_SUPPORTED_FOR_TYPE;
import static org.springframework.expression.spel.SpelMessage.UNABLE_TO_GROW_COLLECTION_UNKNOWN_ELEMENT_TYPE;
@SuppressWarnings("rawtypes")
class IndexingTests {
@ -50,16 +52,14 @@ class IndexingTests { @@ -50,16 +52,14 @@ class IndexingTests {
this.property = property;
SpelExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression("property");
assertThat(expression.getValueTypeDescriptor(this).toString()).isEqualTo("@org.springframework.expression.spel.IndexingTests$FieldAnnotation java.util.HashMap<?, ?>");
assertThat(expression.getValueTypeDescriptor(this)).asString()
.isEqualTo("@%s java.util.HashMap<?, ?>", FieldAnnotation.class.getName());
assertThat(expression.getValue(this)).isEqualTo(property);
assertThat(expression.getValue(this, Map.class)).isEqualTo(property);
expression = parser.parseExpression("property['foo']");
assertThat(expression.getValue(this)).isEqualTo("bar");
}
@FieldAnnotation
public Object property;
@Test
@SuppressWarnings("unchecked")
void indexIntoGenericPropertyContainingMapObject() {
@ -72,43 +72,14 @@ class IndexingTests { @@ -72,43 +72,14 @@ class IndexingTests {
context.addPropertyAccessor(new MapAccessor());
context.setRootObject(property);
Expression expression = parser.parseExpression("property");
assertThat(expression.getValueTypeDescriptor(context).toString()).isEqualTo("java.util.HashMap<?, ?>");
assertThat(expression.getValueTypeDescriptor(context)).asString()
.isEqualTo("java.util.HashMap<?, ?>");
assertThat(expression.getValue(context)).isEqualTo(map);
assertThat(expression.getValue(context, Map.class)).isEqualTo(map);
expression = parser.parseExpression("property['foo']");
assertThat(expression.getValue(context)).isEqualTo("bar");
}
public static class MapAccessor implements PropertyAccessor {
@Override
public boolean canRead(EvaluationContext context, Object target, String name) {
return (((Map<?, ?>) target).containsKey(name));
}
@Override
public TypedValue read(EvaluationContext context, Object target, String name) {
return new TypedValue(((Map<?, ?>) target).get(name));
}
@Override
public boolean canWrite(EvaluationContext context, Object target, String name) {
return true;
}
@Override
@SuppressWarnings("unchecked")
public void write(EvaluationContext context, Object target, String name, Object newValue) {
((Map) target).put(name, newValue);
}
@Override
public Class<?>[] getSpecificTargetClasses() {
return new Class<?>[] {Map.class};
}
}
@Test
void setGenericPropertyContainingMap() {
Map<String, String> property = new HashMap<>();
@ -116,7 +87,8 @@ class IndexingTests { @@ -116,7 +87,8 @@ class IndexingTests {
this.property = property;
SpelExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression("property");
assertThat(expression.getValueTypeDescriptor(this).toString()).isEqualTo("@org.springframework.expression.spel.IndexingTests$FieldAnnotation java.util.HashMap<?, ?>");
assertThat(expression.getValueTypeDescriptor(this)).asString()
.isEqualTo("@%s java.util.HashMap<?, ?>", FieldAnnotation.class.getName());
assertThat(expression.getValue(this)).isEqualTo(property);
expression = parser.parseExpression("property['foo']");
assertThat(expression.getValue(this)).isEqualTo("bar");
@ -131,7 +103,8 @@ class IndexingTests { @@ -131,7 +103,8 @@ class IndexingTests {
this.parameterizedMap = property;
SpelExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression("parameterizedMap");
assertThat(expression.getValueTypeDescriptor(this).toString()).isEqualTo("java.util.HashMap<java.lang.Integer, java.lang.Integer>");
assertThat(expression.getValueTypeDescriptor(this)).asString()
.isEqualTo("java.util.HashMap<java.lang.Integer, java.lang.Integer>");
assertThat(expression.getValue(this)).isEqualTo(property);
expression = parser.parseExpression("parameterizedMap['9']");
assertThat(expression.getValue(this)).isEqualTo(3);
@ -139,14 +112,13 @@ class IndexingTests { @@ -139,14 +112,13 @@ class IndexingTests {
assertThat(expression.getValue(this)).isEqualTo(37);
}
public Map<Integer, Integer> parameterizedMap;
@Test
void setPropertyContainingMapAutoGrow() {
SpelExpressionParser parser = new SpelExpressionParser(new SpelParserConfiguration(true, false));
Expression expression = parser.parseExpression("parameterizedMap");
assertThat(expression.getValueTypeDescriptor(this).toString()).isEqualTo("java.util.Map<java.lang.Integer, java.lang.Integer>");
assertThat(expression.getValue(this)).isEqualTo(property);
assertThat(expression.getValueTypeDescriptor(this)).asString()
.isEqualTo("java.util.Map<java.lang.Integer, java.lang.Integer>");
assertThat(expression.getValue(this)).isNull();
expression = parser.parseExpression("parameterizedMap['9']");
assertThat(expression.getValue(this)).isNull();
expression.setValue(this, "37");
@ -160,7 +132,8 @@ class IndexingTests { @@ -160,7 +132,8 @@ class IndexingTests {
this.property = property;
SpelExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression("property");
assertThat(expression.getValueTypeDescriptor(this).toString()).isEqualTo("@org.springframework.expression.spel.IndexingTests$FieldAnnotation java.util.ArrayList<?>");
assertThat(expression.getValueTypeDescriptor(this)).asString()
.isEqualTo("@%s java.util.ArrayList<?>", FieldAnnotation.class.getName());
assertThat(expression.getValue(this)).isEqualTo(property);
expression = parser.parseExpression("property[0]");
assertThat(expression.getValue(this)).isEqualTo("bar");
@ -173,7 +146,8 @@ class IndexingTests { @@ -173,7 +146,8 @@ class IndexingTests {
this.property = property;
SpelExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression("property");
assertThat(expression.getValueTypeDescriptor(this).toString()).isEqualTo("@org.springframework.expression.spel.IndexingTests$FieldAnnotation java.util.ArrayList<?>");
assertThat(expression.getValueTypeDescriptor(this)).asString()
.isEqualTo("@%s java.util.ArrayList<?>", FieldAnnotation.class.getName());
assertThat(expression.getValue(this)).isEqualTo(property);
expression = parser.parseExpression("property[0]");
assertThat(expression.getValue(this)).isEqualTo(3);
@ -187,18 +161,15 @@ class IndexingTests { @@ -187,18 +161,15 @@ class IndexingTests {
this.property = property;
SpelExpressionParser parser = new SpelExpressionParser(new SpelParserConfiguration(true, true));
Expression expression = parser.parseExpression("property");
assertThat(expression.getValueTypeDescriptor(this).toString()).isEqualTo("@org.springframework.expression.spel.IndexingTests$FieldAnnotation java.util.ArrayList<?>");
assertThat(expression.getValueTypeDescriptor(this)).asString()
.isEqualTo("@%s java.util.ArrayList<?>", FieldAnnotation.class.getName());
assertThat(expression.getValue(this)).isEqualTo(property);
expression = parser.parseExpression("property[0]");
try {
expression.setValue(this, "4");
}
catch (EvaluationException ex) {
assertThat(ex.getMessage()).startsWith("EL1053E");
}
}
public List<BigDecimal> decimals;
Expression indexExpression = parser.parseExpression("property[0]");
assertThatExceptionOfType(SpelEvaluationException.class)
.isThrownBy(() -> indexExpression.getValue(this))
.satisfies(ex -> assertThat(ex.getMessageCode()).isEqualTo(UNABLE_TO_GROW_COLLECTION_UNKNOWN_ELEMENT_TYPE));
}
@Test
void autoGrowListOfElementsWithoutDefaultConstructor() {
@ -225,14 +196,13 @@ class IndexingTests { @@ -225,14 +196,13 @@ class IndexingTests {
this.parameterizedList = property;
SpelExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression("parameterizedList");
assertThat(expression.getValueTypeDescriptor(this).toString()).isEqualTo("java.util.ArrayList<java.lang.Integer>");
assertThat(expression.getValueTypeDescriptor(this)).asString()
.isEqualTo("java.util.ArrayList<java.lang.Integer>");
assertThat(expression.getValue(this)).isEqualTo(property);
expression = parser.parseExpression("parameterizedList[0]");
assertThat(expression.getValue(this)).isEqualTo(3);
}
public List<Integer> parameterizedList;
@Test
void indexIntoPropertyContainingListOfList() {
List<List<Integer>> property = new ArrayList<>();
@ -240,14 +210,13 @@ class IndexingTests { @@ -240,14 +210,13 @@ class IndexingTests {
this.parameterizedListOfList = property;
SpelExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression("parameterizedListOfList[0]");
assertThat(expression.getValueTypeDescriptor(this).toString()).isEqualTo("java.util.Arrays$ArrayList<java.lang.Integer>");
assertThat(expression.getValueTypeDescriptor(this)).asString()
.isEqualTo("java.util.Arrays$ArrayList<java.lang.Integer>");
assertThat(expression.getValue(this)).isEqualTo(property.get(0));
expression = parser.parseExpression("parameterizedListOfList[0][0]");
assertThat(expression.getValue(this)).isEqualTo(3);
}
public List<List<Integer>> parameterizedListOfList;
@Test
void setPropertyContainingList() {
List<Integer> property = new ArrayList<>();
@ -255,7 +224,8 @@ class IndexingTests { @@ -255,7 +224,8 @@ class IndexingTests {
this.parameterizedList = property;
SpelExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression("parameterizedList");
assertThat(expression.getValueTypeDescriptor(this).toString()).isEqualTo("java.util.ArrayList<java.lang.Integer>");
assertThat(expression.getValueTypeDescriptor(this)).asString()
.isEqualTo("java.util.ArrayList<java.lang.Integer>");
assertThat(expression.getValue(this)).isEqualTo(property);
expression = parser.parseExpression("parameterizedList[0]");
assertThat(expression.getValue(this)).isEqualTo(3);
@ -268,15 +238,14 @@ class IndexingTests { @@ -268,15 +238,14 @@ class IndexingTests {
SpelParserConfiguration configuration = new SpelParserConfiguration(true, true);
SpelExpressionParser parser = new SpelExpressionParser(configuration);
Expression expression = parser.parseExpression("property");
assertThat(expression.getValueTypeDescriptor(this).toString()).isEqualTo("@org.springframework.expression.spel.IndexingTests$FieldAnnotation java.lang.Object");
assertThat(expression.getValue(this)).isEqualTo(property);
expression = parser.parseExpression("property[0]");
try {
assertThat(expression.getValue(this)).isEqualTo("bar");
}
catch (EvaluationException ex) {
assertThat(ex.getMessage()).startsWith("EL1027E");
}
assertThat(expression.getValueTypeDescriptor(this)).asString()
.isEqualTo("@%s java.lang.Object", FieldAnnotation.class.getName());
assertThat(expression.getValue(this)).isNull();
Expression indexExpression = parser.parseExpression("property[0]");
assertThatExceptionOfType(SpelEvaluationException.class)
.isThrownBy(() -> indexExpression.getValue(this))
.satisfies(ex -> assertThat(ex.getMessageCode()).isEqualTo(INDEXING_NOT_SUPPORTED_FOR_TYPE));
}
@Test
@ -286,15 +255,14 @@ class IndexingTests { @@ -286,15 +255,14 @@ class IndexingTests {
SpelParserConfiguration configuration = new SpelParserConfiguration(true, true);
SpelExpressionParser parser = new SpelExpressionParser(configuration);
Expression expression = parser.parseExpression("property");
assertThat(expression.getValueTypeDescriptor(this).toString()).isEqualTo("@org.springframework.expression.spel.IndexingTests$FieldAnnotation java.util.ArrayList<?>");
assertThat(expression.getValueTypeDescriptor(this)).asString()
.isEqualTo("@%s java.util.ArrayList<?>", FieldAnnotation.class.getName());
assertThat(expression.getValue(this)).isEqualTo(property);
expression = parser.parseExpression("property[0]");
try {
assertThat(expression.getValue(this)).isEqualTo("bar");
}
catch (EvaluationException ex) {
assertThat(ex.getMessage()).startsWith("EL1053E");
}
Expression indexExpression = parser.parseExpression("property[0]");
assertThatExceptionOfType(SpelEvaluationException.class)
.isThrownBy(() -> indexExpression.getValue(this))
.satisfies(ex -> assertThat(ex.getMessageCode()).isEqualTo(UNABLE_TO_GROW_COLLECTION_UNKNOWN_ELEMENT_TYPE));
}
@Test
@ -304,18 +272,14 @@ class IndexingTests { @@ -304,18 +272,14 @@ class IndexingTests {
SpelParserConfiguration configuration = new SpelParserConfiguration(true, true);
SpelExpressionParser parser = new SpelExpressionParser(configuration);
Expression expression = parser.parseExpression("property2");
assertThat(expression.getValueTypeDescriptor(this).toString()).isEqualTo("java.util.ArrayList<?>");
assertThat(expression.getValueTypeDescriptor(this)).asString().isEqualTo("java.util.ArrayList<?>");
assertThat(expression.getValue(this)).isEqualTo(property2);
expression = parser.parseExpression("property2[0]");
try {
assertThat(expression.getValue(this)).isEqualTo("bar");
}
catch (EvaluationException ex) {
assertThat(ex.getMessage()).startsWith("EL1053E");
}
}
public List property2;
Expression indexExpression = parser.parseExpression("property2[0]");
assertThatExceptionOfType(SpelEvaluationException.class)
.isThrownBy(() -> indexExpression.getValue(this))
.satisfies(ex -> assertThat(ex.getMessageCode()).isEqualTo(UNABLE_TO_GROW_COLLECTION_UNKNOWN_ELEMENT_TYPE));
}
@Test
void indexIntoGenericPropertyContainingArray() {
@ -323,7 +287,8 @@ class IndexingTests { @@ -323,7 +287,8 @@ class IndexingTests {
this.property = property;
SpelExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression("property");
assertThat(expression.getValueTypeDescriptor(this).toString()).isEqualTo("@org.springframework.expression.spel.IndexingTests$FieldAnnotation java.lang.String[]");
assertThat(expression.getValueTypeDescriptor(this)).asString()
.isEqualTo("@%s java.lang.String[]", FieldAnnotation.class.getName());
assertThat(expression.getValue(this)).isEqualTo(property);
expression = parser.parseExpression("property[0]");
assertThat(expression.getValue(this)).isEqualTo("bar");
@ -334,19 +299,20 @@ class IndexingTests { @@ -334,19 +299,20 @@ class IndexingTests {
listOfScalarNotGeneric = new ArrayList();
SpelExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression("listOfScalarNotGeneric");
assertThat(expression.getValueTypeDescriptor(this).toString()).isEqualTo("java.util.ArrayList<?>");
assertThat(expression.getValueTypeDescriptor(this)).asString().isEqualTo("java.util.ArrayList<?>");
assertThat(expression.getValue(this, String.class)).isEmpty();
}
@SuppressWarnings("unchecked")
@Test
@SuppressWarnings("unchecked")
void resolveCollectionElementType() {
listNotGeneric = new ArrayList(2);
listNotGeneric.add(5);
listNotGeneric.add(6);
SpelExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression("listNotGeneric");
assertThat(expression.getValueTypeDescriptor(this).toString()).isEqualTo("@org.springframework.expression.spel.IndexingTests$FieldAnnotation java.util.ArrayList<?>");
assertThat(expression.getValueTypeDescriptor(this)).asString()
.isEqualTo("@%s java.util.ArrayList<?>", FieldAnnotation.class.getName());
assertThat(expression.getValue(this, String.class)).isEqualTo("5,6");
}
@ -354,16 +320,8 @@ class IndexingTests { @@ -354,16 +320,8 @@ class IndexingTests {
void resolveCollectionElementTypeNull() {
SpelExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression("listNotGeneric");
assertThat(expression.getValueTypeDescriptor(this).toString()).isEqualTo("@org.springframework.expression.spel.IndexingTests$FieldAnnotation java.util.List<?>");
}
@FieldAnnotation
public List listNotGeneric;
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface FieldAnnotation {
assertThat(expression.getValueTypeDescriptor(this)).asString()
.isEqualTo("@%s java.util.List<?>", FieldAnnotation.class.getName());
}
@SuppressWarnings("unchecked")
@ -374,14 +332,12 @@ class IndexingTests { @@ -374,14 +332,12 @@ class IndexingTests {
mapNotGeneric.put("bonusAmount", 7.17);
SpelExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression("mapNotGeneric");
assertThat(expression.getValueTypeDescriptor(this).toString()).isEqualTo("@org.springframework.expression.spel.IndexingTests$FieldAnnotation java.util.HashMap<?, ?>");
assertThat(expression.getValueTypeDescriptor(this)).asString()
.isEqualTo("@%s java.util.HashMap<?, ?>", FieldAnnotation.class.getName());
}
@FieldAnnotation
public Map mapNotGeneric;
@SuppressWarnings("unchecked")
@Test
@SuppressWarnings("unchecked")
void testListOfScalar() {
listOfScalarNotGeneric = new ArrayList(1);
listOfScalarNotGeneric.add("5");
@ -390,11 +346,8 @@ class IndexingTests { @@ -390,11 +346,8 @@ class IndexingTests {
assertThat(expression.getValue(this, Integer.class)).isEqualTo(Integer.valueOf(5));
}
public List listOfScalarNotGeneric;
@SuppressWarnings("unchecked")
@Test
@SuppressWarnings("unchecked")
void testListsOfMap() {
listOfMapsNotGeneric = new ArrayList();
Map map = new HashMap();
@ -405,6 +358,64 @@ class IndexingTests { @@ -405,6 +358,64 @@ class IndexingTests {
assertThat(expression.getValue(this, String.class)).isEqualTo("apple");
}
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@interface FieldAnnotation {
}
@FieldAnnotation
public Object property;
public List property2;
public Map<Integer, Integer> parameterizedMap;
public List<BigDecimal> decimals;
public List<Integer> parameterizedList;
public List<List<Integer>> parameterizedListOfList;
@FieldAnnotation
public List listNotGeneric;
@FieldAnnotation
public Map mapNotGeneric;
public List listOfScalarNotGeneric;
public List listOfMapsNotGeneric;
private static class MapAccessor implements PropertyAccessor {
@Override
public boolean canRead(EvaluationContext context, Object target, String name) {
return (((Map<?, ?>) target).containsKey(name));
}
@Override
public TypedValue read(EvaluationContext context, Object target, String name) {
return new TypedValue(((Map<?, ?>) target).get(name));
}
@Override
public boolean canWrite(EvaluationContext context, Object target, String name) {
return true;
}
@Override
@SuppressWarnings("unchecked")
public void write(EvaluationContext context, Object target, String name, Object newValue) {
((Map) target).put(name, newValue);
}
@Override
public Class<?>[] getSpecificTargetClasses() {
return new Class<?>[] {Map.class};
}
}
}

455
spring-expression/src/test/java/org/springframework/expression/spel/SelectionAndProjectionTests.java

@ -17,18 +17,22 @@ @@ -17,18 +17,22 @@
package org.springframework.expression.spel;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.standard.SpelExpression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
@ -36,6 +40,7 @@ import org.springframework.expression.spel.support.StandardEvaluationContext; @@ -36,6 +40,7 @@ import org.springframework.expression.spel.support.StandardEvaluationContext;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.InstanceOfAssertFactories.INTEGER;
import static org.assertj.core.api.InstanceOfAssertFactories.LIST;
import static org.assertj.core.api.InstanceOfAssertFactories.array;
import static org.springframework.expression.spel.SpelMessage.INVALID_TYPE_FOR_SELECTION;
import static org.springframework.expression.spel.SpelMessage.PROJECTION_NOT_SUPPORTED_ON_TYPE;
import static org.springframework.expression.spel.SpelMessage.RESULT_OF_SELECTION_CRITERIA_IS_NOT_BOOLEAN;
@ -46,241 +51,244 @@ import static org.springframework.expression.spel.SpelMessage.RESULT_OF_SELECTIO @@ -46,241 +51,244 @@ import static org.springframework.expression.spel.SpelMessage.RESULT_OF_SELECTIO
* @author Juergen Hoeller
* @author Andy Clement
*/
class SelectionAndProjectionTests extends AbstractExpressionTests {
class SelectionAndProjectionTests {
@Test
void selectionOnUnsupportedType() {
evaluateAndCheckError("'abc'.?[#this<5]", INVALID_TYPE_FOR_SELECTION);
evaluateAndCheckError("null.?[#this<5]", INVALID_TYPE_FOR_SELECTION);
}
@Nested
class SelectionTests extends AbstractExpressionTests {
@Test
void projectionOnUnsupportedType() {
evaluateAndCheckError("'abc'.![true]", PROJECTION_NOT_SUPPORTED_ON_TYPE);
evaluateAndCheckError("null.![true]", PROJECTION_NOT_SUPPORTED_ON_TYPE);
}
@Test
void selectionOnUnsupportedType() {
evaluateAndCheckError("'abc'.?[#this < 5]", INVALID_TYPE_FOR_SELECTION);
evaluateAndCheckError("null.?[#this < 5]", INVALID_TYPE_FOR_SELECTION);
}
@Test
void selectionOnNullWithSafeNavigation() {
evaluate("null?.?[#this<5]", null, null);
}
@Test
void selectionWithNonBooleanSelectionCriteria() {
evaluateAndCheckError("mapOfNumbersUpToTen.?['hello']", RESULT_OF_SELECTION_CRITERIA_IS_NOT_BOOLEAN);
evaluateAndCheckError("mapOfNumbersUpToTen.keySet().?['hello']", RESULT_OF_SELECTION_CRITERIA_IS_NOT_BOOLEAN);
}
@Test
void projectionOnNullWithSafeNavigation() {
evaluate("null?.![true]", null, null);
}
@Test
void selectionWithSafeNavigation() {
evaluate("null?.?[true]", null, null);
evaluate("{1,2,3}?.?[true]", List.of(1, 2, 3), ArrayList.class);
evaluate("{1,2,3,4,5,6}?.?[#this between {2, 4}]", List.of(2, 3, 4), ArrayList.class);
}
@Test
void selectionWithNonBooleanSelectionCriteria() {
evaluateAndCheckError("mapOfNumbersUpToTen.?['hello']", RESULT_OF_SELECTION_CRITERIA_IS_NOT_BOOLEAN);
evaluateAndCheckError("mapOfNumbersUpToTen.keySet().?['hello']", RESULT_OF_SELECTION_CRITERIA_IS_NOT_BOOLEAN);
}
@Test
void selectionAST() {
// select first
SpelExpression expr = (SpelExpression) parser.parseExpression("'abc'.^[true]");
assertThat(expr.toStringAST()).isEqualTo("'abc'.^[true]");
@Test
void selectionAST() {
// select first
SpelExpression expr = (SpelExpression) parser.parseExpression("'abc'.^[true]");
assertThat(expr.toStringAST()).isEqualTo("'abc'.^[true]");
// select all
expr = (SpelExpression) parser.parseExpression("'abc'.?[true]");
assertThat(expr.toStringAST()).isEqualTo("'abc'.?[true]");
// select all
expr = (SpelExpression) parser.parseExpression("'abc'.?[true]");
assertThat(expr.toStringAST()).isEqualTo("'abc'.?[true]");
// select last
expr = (SpelExpression) parser.parseExpression("'abc'.$[true]");
assertThat(expr.toStringAST()).isEqualTo("'abc'.$[true]");
}
// select last
expr = (SpelExpression) parser.parseExpression("'abc'.$[true]");
assertThat(expr.toStringAST()).isEqualTo("'abc'.$[true]");
}
@Test
@SuppressWarnings("unchecked")
void selectionWithList() {
Expression expression = new SpelExpressionParser().parseRaw("integers.?[#this < 5]");
EvaluationContext context = new StandardEvaluationContext(new ListTestBean());
assertThat(expression.getValue(context)).asInstanceOf(LIST).containsExactly(0, 1, 2, 3, 4);
}
@Test
@SuppressWarnings("unchecked")
void selectionWithList() {
Expression expression = new SpelExpressionParser().parseRaw("integers.?[#this<5]");
EvaluationContext context = new StandardEvaluationContext(new ListTestBean());
assertThat(expression.getValue(context)).asInstanceOf(LIST).containsExactly(0, 1, 2, 3, 4);
}
@Test
void selectFirstItemInList() {
Expression expression = new SpelExpressionParser().parseRaw("integers.^[#this < 5]");
EvaluationContext context = new StandardEvaluationContext(new ListTestBean());
assertThat(expression.getValue(context)).asInstanceOf(INTEGER).isZero();
}
@Test
void selectFirstItemInList() {
Expression expression = new SpelExpressionParser().parseRaw("integers.^[#this<5]");
EvaluationContext context = new StandardEvaluationContext(new ListTestBean());
assertThat(expression.getValue(context)).asInstanceOf(INTEGER).isZero();
}
@Test
void selectLastItemInList() {
Expression expression = new SpelExpressionParser().parseRaw("integers.$[#this < 5]");
EvaluationContext context = new StandardEvaluationContext(new ListTestBean());
assertThat(expression.getValue(context)).asInstanceOf(INTEGER).isEqualTo(4);
}
@Test
void selectLastItemInList() {
Expression expression = new SpelExpressionParser().parseRaw("integers.$[#this<5]");
EvaluationContext context = new StandardEvaluationContext(new ListTestBean());
assertThat(expression.getValue(context)).asInstanceOf(INTEGER).isEqualTo(4);
}
@Test
void selectionWithSetAndRegex() {
evaluate("testMap.keySet().?[#this matches '.*o.*']", "[monday]", ArrayList.class);
evaluate("testMap.keySet().?[#this matches '.*r.*'].contains('saturday')", "true", Boolean.class);
evaluate("testMap.keySet().?[#this matches '.*r.*'].size()", "3", Integer.class);
}
@Test
void selectionWithSetAndRegex() {
evaluate("testMap.keySet().?[#this matches '.*o.*']", "[monday]", ArrayList.class);
evaluate("testMap.keySet().?[#this matches '.*r.*'].contains('saturday')", "true", Boolean.class);
evaluate("testMap.keySet().?[#this matches '.*r.*'].size()", "3", Integer.class);
}
@Test
@SuppressWarnings("unchecked")
void selectionWithSet() {
Expression expression = new SpelExpressionParser().parseRaw("integers.?[#this < 5]");
EvaluationContext context = new StandardEvaluationContext(new SetTestBean());
assertThat(expression.getValue(context)).asInstanceOf(LIST).containsExactly(0, 1, 2, 3, 4);
}
@Test
@SuppressWarnings("unchecked")
void selectionWithSet() {
Expression expression = new SpelExpressionParser().parseRaw("integers.?[#this<5]");
EvaluationContext context = new StandardEvaluationContext(new SetTestBean());
assertThat(expression.getValue(context)).asInstanceOf(LIST).containsExactly(0, 1, 2, 3, 4);
}
@Test
void selectFirstItemInSet() {
Expression expression = new SpelExpressionParser().parseRaw("integers.^[#this < 5]");
EvaluationContext context = new StandardEvaluationContext(new SetTestBean());
assertThat(expression.getValue(context)).asInstanceOf(INTEGER).isZero();
}
@Test
void selectFirstItemInSet() {
Expression expression = new SpelExpressionParser().parseRaw("integers.^[#this<5]");
EvaluationContext context = new StandardEvaluationContext(new SetTestBean());
assertThat(expression.getValue(context)).asInstanceOf(INTEGER).isZero();
}
@Test
void selectLastItemInSet() {
Expression expression = new SpelExpressionParser().parseRaw("integers.$[#this < 5]");
EvaluationContext context = new StandardEvaluationContext(new SetTestBean());
assertThat(expression.getValue(context)).asInstanceOf(INTEGER).isEqualTo(4);
}
@Test
void selectLastItemInSet() {
Expression expression = new SpelExpressionParser().parseRaw("integers.$[#this<5]");
EvaluationContext context = new StandardEvaluationContext(new SetTestBean());
assertThat(expression.getValue(context)).asInstanceOf(INTEGER).isEqualTo(4);
}
@ParameterizedTest
@ValueSource(strings = {"#root.?[#this < 3]", "?[#this < 3]"})
void selectionWithIterable(String expressionString) {
Expression expression = new SpelExpressionParser().parseRaw(expressionString);
EvaluationContext context = new StandardEvaluationContext(new IterableTestBean());
assertThat(expression.getValue(context)).asInstanceOf(LIST).containsExactly(1, 2);
}
@Test
@SuppressWarnings("unchecked")
void selectionWithIterable() {
Expression expression = new SpelExpressionParser().parseRaw("integers.?[#this<5]");
EvaluationContext context = new StandardEvaluationContext(new IterableTestBean());
assertThat(expression.getValue(context)).asInstanceOf(LIST).containsExactly(0, 1, 2, 3, 4);
}
@Test
void selectionWithArray() {
Expression expression = new SpelExpressionParser().parseRaw("integers.?[#this < 5]");
EvaluationContext context = new StandardEvaluationContext(new ArrayTestBean());
Object value = expression.getValue(context);
assertThat(value).asInstanceOf(array(Integer[].class)).containsExactly(0, 1, 2, 3, 4);
}
@Test
void selectionWithArray() {
Expression expression = new SpelExpressionParser().parseRaw("integers.?[#this<5]");
EvaluationContext context = new StandardEvaluationContext(new ArrayTestBean());
Object value = expression.getValue(context);
assertThat(value.getClass().isArray()).isTrue();
TypedValue typedValue = new TypedValue(value);
assertThat(typedValue.getTypeDescriptor().getElementTypeDescriptor().getType()).isEqualTo(Integer.class);
assertThat((Integer[]) value).containsExactly(0, 1, 2, 3, 4);
}
@Test
void selectFirstItemInArray() {
Expression expression = new SpelExpressionParser().parseRaw("integers.^[#this < 5]");
EvaluationContext context = new StandardEvaluationContext(new ArrayTestBean());
assertThat(expression.getValue(context)).asInstanceOf(INTEGER).isZero();
}
@Test
void selectFirstItemInArray() {
Expression expression = new SpelExpressionParser().parseRaw("integers.^[#this<5]");
EvaluationContext context = new StandardEvaluationContext(new ArrayTestBean());
assertThat(expression.getValue(context)).asInstanceOf(INTEGER).isZero();
}
@Test
void selectLastItemInArray() {
Expression expression = new SpelExpressionParser().parseRaw("integers.$[#this < 5]");
EvaluationContext context = new StandardEvaluationContext(new ArrayTestBean());
assertThat(expression.getValue(context)).asInstanceOf(INTEGER).isEqualTo(4);
}
@Test
void selectLastItemInArray() {
Expression expression = new SpelExpressionParser().parseRaw("integers.$[#this<5]");
EvaluationContext context = new StandardEvaluationContext(new ArrayTestBean());
assertThat(expression.getValue(context)).asInstanceOf(INTEGER).isEqualTo(4);
}
@Test
void selectionWithPrimitiveArray() {
Expression expression = new SpelExpressionParser().parseRaw("ints.?[#this < 5]");
EvaluationContext context = new StandardEvaluationContext(new ArrayTestBean());
Object value = expression.getValue(context);
assertThat(value).asInstanceOf(array(Integer[].class)).containsExactly(0, 1, 2, 3, 4);
}
@Test
void selectionWithPrimitiveArray() {
Expression expression = new SpelExpressionParser().parseRaw("ints.?[#this<5]");
EvaluationContext context = new StandardEvaluationContext(new ArrayTestBean());
Object value = expression.getValue(context);
assertThat(value.getClass().isArray()).isTrue();
TypedValue typedValue = new TypedValue(value);
assertThat(typedValue.getTypeDescriptor().getElementTypeDescriptor().getType()).isEqualTo(Integer.class);
assertThat((Integer[]) value).containsExactly(0, 1, 2, 3, 4);
}
@Test
void selectFirstItemInPrimitiveArray() {
Expression expression = new SpelExpressionParser().parseRaw("ints.^[#this < 5]");
EvaluationContext context = new StandardEvaluationContext(new ArrayTestBean());
assertThat(expression.getValue(context)).asInstanceOf(INTEGER).isZero();
}
@Test
void selectFirstItemInPrimitiveArray() {
Expression expression = new SpelExpressionParser().parseRaw("ints.^[#this<5]");
EvaluationContext context = new StandardEvaluationContext(new ArrayTestBean());
assertThat(expression.getValue(context)).asInstanceOf(INTEGER).isZero();
}
@Test
void selectLastItemInPrimitiveArray() {
Expression expression = new SpelExpressionParser().parseRaw("ints.$[#this < 5]");
EvaluationContext context = new StandardEvaluationContext(new ArrayTestBean());
assertThat(expression.getValue(context)).asInstanceOf(INTEGER).isEqualTo(4);
}
@Test
void selectLastItemInPrimitiveArray() {
Expression expression = new SpelExpressionParser().parseRaw("ints.$[#this<5]");
EvaluationContext context = new StandardEvaluationContext(new ArrayTestBean());
assertThat(expression.getValue(context)).asInstanceOf(INTEGER).isEqualTo(4);
}
@Test
@SuppressWarnings("unchecked")
void selectionWithMap() {
EvaluationContext context = new StandardEvaluationContext(new MapTestBean());
ExpressionParser parser = new SpelExpressionParser();
@Test
@SuppressWarnings("unchecked")
void selectionWithMap() {
EvaluationContext context = new StandardEvaluationContext(new MapTestBean());
ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("colors.?[key.startsWith('b')]");
Map<String, String> colorsMap = (Map<String, String>) exp.getValue(context);
assertThat(colorsMap).containsOnlyKeys("beige", "blue", "brown");
Expression exp = parser.parseExpression("colors.?[key.startsWith('b')]");
Map<String, String> colorsMap = (Map<String, String>) exp.getValue(context);
assertThat(colorsMap).containsOnlyKeys("beige", "blue", "brown");
exp = parser.parseExpression("colors.?[key.startsWith('X')]");
exp = parser.parseExpression("colors.?[key.startsWith('X')]");
colorsMap = (Map<String, String>) exp.getValue(context);
assertThat(colorsMap).isEmpty();
}
colorsMap = (Map<String, String>) exp.getValue(context);
assertThat(colorsMap).isEmpty();
}
@Test
@SuppressWarnings("unchecked")
void selectFirstItemInMap() {
EvaluationContext context = new StandardEvaluationContext(new MapTestBean());
ExpressionParser parser = new SpelExpressionParser();
@Test
@SuppressWarnings("unchecked")
void selectFirstItemInMap() {
EvaluationContext context = new StandardEvaluationContext(new MapTestBean());
ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("colors.^[key.startsWith('b')]");
Map<String, String> colorsMap = (Map<String, String>) exp.getValue(context);
assertThat(colorsMap).containsOnlyKeys("beige");
}
Expression exp = parser.parseExpression("colors.^[key.startsWith('b')]");
Map<String, String> colorsMap = (Map<String, String>) exp.getValue(context);
assertThat(colorsMap).containsOnlyKeys("beige");
}
@Test
@SuppressWarnings("unchecked")
void selectLastItemInMap() {
EvaluationContext context = new StandardEvaluationContext(new MapTestBean());
ExpressionParser parser = new SpelExpressionParser();
@Test
@SuppressWarnings("unchecked")
void selectLastItemInMap() {
EvaluationContext context = new StandardEvaluationContext(new MapTestBean());
ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("colors.$[key.startsWith('b')]");
Map<String, String> colorsMap = (Map<String, String>) exp.getValue(context);
assertThat(colorsMap).containsOnlyKeys("brown");
}
Expression exp = parser.parseExpression("colors.$[key.startsWith('b')]");
Map<String, String> colorsMap = (Map<String, String>) exp.getValue(context);
assertThat(colorsMap).containsOnlyKeys("brown");
}
@Test
@SuppressWarnings("unchecked")
void projectionWithList() {
Expression expression = new SpelExpressionParser().parseRaw("#testList.![wrapper.value]");
EvaluationContext context = new StandardEvaluationContext();
context.setVariable("testList", IntegerTestBean.createList());
assertThat(expression.getValue(context)).asInstanceOf(LIST).containsExactly(5, 6, 7);
}
@Nested
class ProjectionTests extends AbstractExpressionTests {
@Test
void projectionWithMap() {
evaluate("mapOfNumbersUpToTen.![key > 5 ? value : null]",
@Test
void projectionOnUnsupportedType() {
evaluateAndCheckError("'abc'.![true]", PROJECTION_NOT_SUPPORTED_ON_TYPE);
evaluateAndCheckError("null.![true]", PROJECTION_NOT_SUPPORTED_ON_TYPE);
}
@Test
void projectionWithSafeNavigation() {
evaluate("null?.![#this]", null, null);
evaluate("{1,2,3}?.![#this % 2]", List.of(1, 0, 1), ArrayList.class);
}
@Test
@SuppressWarnings("unchecked")
void projectionWithList() {
Expression expression = new SpelExpressionParser().parseRaw("#testList.![wrapper.value]");
EvaluationContext context = new StandardEvaluationContext();
context.setVariable("testList", IntegerTestBean.createList());
assertThat(expression.getValue(context)).asInstanceOf(LIST).containsExactly(5, 6, 7);
}
@Test
void projectionWithMap() {
evaluate("mapOfNumbersUpToTen.![key > 5 ? value : null]",
"[null, null, null, null, null, six, seven, eight, nine, ten]", ArrayList.class);
}
}
@Test
@SuppressWarnings("unchecked")
void projectionWithSet() {
Expression expression = new SpelExpressionParser().parseRaw("#testList.![wrapper.value]");
EvaluationContext context = new StandardEvaluationContext();
context.setVariable("testList", IntegerTestBean.createSet());
assertThat(expression.getValue(context)).asInstanceOf(LIST).containsExactly(5, 6, 7);
}
@Test
@SuppressWarnings("unchecked")
void projectionWithSet() {
Expression expression = new SpelExpressionParser().parseRaw("#testSet.![wrapper.value]");
EvaluationContext context = new StandardEvaluationContext();
context.setVariable("testSet", IntegerTestBean.createSet());
assertThat(expression.getValue(context)).asInstanceOf(LIST).containsExactly(5, 6, 7);
}
@Test
@SuppressWarnings("unchecked")
void projectionWithIterable() {
Expression expression = new SpelExpressionParser().parseRaw("#testList.![wrapper.value]");
EvaluationContext context = new StandardEvaluationContext();
context.setVariable("testList", IntegerTestBean.createIterable());
assertThat(expression.getValue(context)).asInstanceOf(LIST).containsExactly(5, 6, 7);
}
@ParameterizedTest
@ValueSource(strings = {"#root.![#this * 2]", "![#this * 2]"})
void projectionWithIterable(String expressionString) {
Expression expression = new SpelExpressionParser().parseRaw(expressionString);
EvaluationContext context = new StandardEvaluationContext(new IterableTestBean());
assertThat(expression.getValue(context)).asInstanceOf(LIST).containsExactly(2, 4, 6, 8, 10);
}
@Test
void projectionWithArray() {
Expression expression = new SpelExpressionParser().parseRaw("#testArray.![wrapper.value]");
EvaluationContext context = new StandardEvaluationContext();
context.setVariable("testArray", IntegerTestBean.createArray());
Object value = expression.getValue(context);
assertThat(value).asInstanceOf(array(Number[].class)).containsExactly(5, 5.9f, 7);
}
@Test
void projectionWithArray() {
Expression expression = new SpelExpressionParser().parseRaw("#testArray.![wrapper.value]");
EvaluationContext context = new StandardEvaluationContext();
context.setVariable("testArray", IntegerTestBean.createArray());
Object value = expression.getValue(context);
assertThat(value.getClass().isArray()).isTrue();
TypedValue typedValue = new TypedValue(value);
assertThat(typedValue.getTypeDescriptor().getElementTypeDescriptor().getType()).isEqualTo(Number.class);
assertThat((Number[]) value).containsExactly(5, 5.9f, 7);
}
@ -288,7 +296,7 @@ class SelectionAndProjectionTests extends AbstractExpressionTests { @@ -288,7 +296,7 @@ class SelectionAndProjectionTests extends AbstractExpressionTests {
private final List<Integer> integers = new ArrayList<>();
ListTestBean() {
{
for (int i = 0; i < 10; i++) {
integers.add(i);
}
@ -304,7 +312,7 @@ class SelectionAndProjectionTests extends AbstractExpressionTests { @@ -304,7 +312,7 @@ class SelectionAndProjectionTests extends AbstractExpressionTests {
private final Set<Integer> integers = new LinkedHashSet<>();
SetTestBean() {
{
for (int i = 0; i < 10; i++) {
integers.add(i);
}
@ -316,18 +324,13 @@ class SelectionAndProjectionTests extends AbstractExpressionTests { @@ -316,18 +324,13 @@ class SelectionAndProjectionTests extends AbstractExpressionTests {
}
static class IterableTestBean {
static class IterableTestBean implements Iterable<Integer> {
private final Set<Integer> integers = new LinkedHashSet<>();
private final Collection<Integer> integers = List.of(1, 2, 3, 4, 5);
IterableTestBean() {
for (int i = 0; i < 10; i++) {
integers.add(i);
}
}
public Iterable<Integer> getIntegers() {
return integers;
@Override
public Iterator<Integer> iterator() {
return integers.iterator();
}
}
@ -338,7 +341,7 @@ class SelectionAndProjectionTests extends AbstractExpressionTests { @@ -338,7 +341,7 @@ class SelectionAndProjectionTests extends AbstractExpressionTests {
private final Integer[] integers = new Integer[10];
ArrayTestBean() {
{
for (int i = 0; i < 10; i++) {
ints[i] = i;
integers[i] = i;
@ -359,8 +362,7 @@ class SelectionAndProjectionTests extends AbstractExpressionTests { @@ -359,8 +362,7 @@ class SelectionAndProjectionTests extends AbstractExpressionTests {
private final Map<String, String> colors = new TreeMap<>();
MapTestBean() {
// colors.put("black", "schwarz");
{
colors.put("red", "rot");
colors.put("brown", "braun");
colors.put("blue", "blau");
@ -376,13 +378,13 @@ class SelectionAndProjectionTests extends AbstractExpressionTests { @@ -376,13 +378,13 @@ class SelectionAndProjectionTests extends AbstractExpressionTests {
static class IntegerTestBean {
private final IntegerWrapper wrapper;
private final NumberWrapper wrapper;
IntegerTestBean(Number value) {
this.wrapper = new IntegerWrapper(value);
this.wrapper = new NumberWrapper(value);
}
public IntegerWrapper getWrapper() {
public NumberWrapper getWrapper() {
return this.wrapper;
}
@ -402,11 +404,6 @@ class SelectionAndProjectionTests extends AbstractExpressionTests { @@ -402,11 +404,6 @@ class SelectionAndProjectionTests extends AbstractExpressionTests {
return set;
}
static Iterable<IntegerTestBean> createIterable() {
final Set<IntegerTestBean> set = createSet();
return set;
}
static IntegerTestBean[] createArray() {
IntegerTestBean[] array = new IntegerTestBean[3];
for (int i = 0; i < 3; i++) {
@ -422,17 +419,7 @@ class SelectionAndProjectionTests extends AbstractExpressionTests { @@ -422,17 +419,7 @@ class SelectionAndProjectionTests extends AbstractExpressionTests {
}
static class IntegerWrapper {
private final Number value;
IntegerWrapper(Number value) {
this.value = value;
}
public Number getValue() {
return this.value;
}
}
record NumberWrapper(Number value) {
};
}

Loading…
Cancel
Save