|
|
|
|
@ -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) { |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|