diff --git a/framework-docs/modules/ROOT/pages/core/expressions/language-ref/collection-projection.adoc b/framework-docs/modules/ROOT/pages/core/expressions/language-ref/collection-projection.adoc index 101fc5cc9f..efc43fe8c1 100644 --- a/framework-docs/modules/ROOT/pages/core/expressions/language-ref/collection-projection.adoc +++ b/framework-docs/modules/ROOT/pages/core/expressions/language-ref/collection-projection.adoc @@ -13,16 +13,18 @@ Java:: + [source,java,indent=0,subs="verbatim,quotes",role="primary"] ---- - // returns ['Smiljan', 'Idvor' ] - List placesOfBirth = (List)parser.parseExpression("members.![placeOfBirth.city]"); + // evaluates to ["SmilJan", "Idvor"] + List placesOfBirth = parser.parseExpression("members.![placeOfBirth.city]") + .getValue(societyContext, List.class); ---- Kotlin:: + [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] ---- - // returns ['Smiljan', 'Idvor' ] - val placesOfBirth = parser.parseExpression("members.![placeOfBirth.city]") as List<*> + // evaluates to ["SmilJan", "Idvor"] + val placesOfBirth = parser.parseExpression("members.![placeOfBirth.city]") + .getValue(societyContext) as List<*> ---- ====== diff --git a/framework-docs/modules/ROOT/pages/core/expressions/language-ref/collection-selection.adoc b/framework-docs/modules/ROOT/pages/core/expressions/language-ref/collection-selection.adoc index 3f87541a81..f0f70ffad9 100644 --- a/framework-docs/modules/ROOT/pages/core/expressions/language-ref/collection-selection.adoc +++ b/framework-docs/modules/ROOT/pages/core/expressions/language-ref/collection-selection.adoc @@ -28,13 +28,14 @@ Kotlin:: ====== Selection is supported for arrays and anything that implements `java.lang.Iterable` or -`java.util.Map`. For a list or array, the selection criteria is evaluated against each -individual element. Against a map, the selection criteria is evaluated against each map -entry (objects of the Java type `Map.Entry`). Each map entry has its `key` and `value` -accessible as properties for use in the selection. +`java.util.Map`. For an array or `Iterable`, the selection expression is evaluated +against each individual element. Against a map, the selection expression is evaluated +against each map entry (objects of the Java type `Map.Entry`). Each map entry has its +`key` and `value` accessible as properties for use in the selection. -The following expression returns a new map that consists of those elements of the -original map where the entry's value is less than 27: +Given a `Map` stored in a variable named `#map`, the following expression returns a new +map that consists of those elements of the original map where the entry's value is less +than 27: [tabs] ====== @@ -42,21 +43,21 @@ Java:: + [source,java,indent=0,subs="verbatim,quotes",role="primary"] ---- - Map newMap = parser.parseExpression("map.?[value<27]").getValue(); + Map newMap = parser.parseExpression("#map.?[value < 27]").getValue(Map.class); ---- Kotlin:: + [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] ---- - val newMap = parser.parseExpression("map.?[value<27]").getValue() + val newMap = parser.parseExpression("#map.?[value < 27]").getValue() as Map ---- ====== In addition to returning all the selected elements, you can retrieve only the first or -the last element. To obtain the first element matching the selection, the syntax is -`.^[selectionExpression]`. To obtain the last matching selection, the syntax is -`.$[selectionExpression]`. +the last element. To obtain the first element matching the selection expression, the +syntax is `.^[selectionExpression]`. To obtain the last element matching the selection +expression, the syntax is `.$[selectionExpression]`. diff --git a/spring-expression/src/test/java/org/springframework/expression/spel/SpelDocumentationTests.java b/spring-expression/src/test/java/org/springframework/expression/spel/SpelDocumentationTests.java index 5aedfcba8a..36789d14d2 100644 --- a/spring-expression/src/test/java/org/springframework/expression/spel/SpelDocumentationTests.java +++ b/spring-expression/src/test/java/org/springframework/expression/spel/SpelDocumentationTests.java @@ -22,7 +22,6 @@ import java.lang.invoke.MethodType; import java.util.ArrayList; import java.util.Date; import java.util.GregorianCalendar; -import java.util.HashMap; import java.util.List; import java.util.Map; @@ -172,28 +171,24 @@ class SpelDocumentationTests extends AbstractExpressionTests { @Test void propertyNavigation() { ExpressionParser parser = new SpelExpressionParser(); + StandardEvaluationContext teslaContext = TestScenarioCreator.getTestEvaluationContext(); // Inventions Array - StandardEvaluationContext teslaContext = TestScenarioCreator.getTestEvaluationContext(); - // teslaContext.setRootObject(tesla); - // evaluates to "Induction motor" String invention = parser.parseExpression("inventions[3]").getValue(teslaContext, String.class); assertThat(invention).isEqualTo("Induction motor"); // Members List StandardEvaluationContext societyContext = new StandardEvaluationContext(); - IEEE ieee = new IEEE(); - ieee.Members[0]= tesla; - societyContext.setRootObject(ieee); + societyContext.setRootObject(new IEEE()); // evaluates to "Nikola Tesla" - String name = parser.parseExpression("Members[0].Name").getValue(societyContext, String.class); + String name = parser.parseExpression("members[0].Name").getValue(societyContext, String.class); assertThat(name).isEqualTo("Nikola Tesla"); // List and Array navigation // evaluates to "Wireless communication" - invention = parser.parseExpression("Members[0].Inventions[6]").getValue(societyContext, String.class); + invention = parser.parseExpression("members[0].Inventions[6]").getValue(societyContext, String.class); assertThat(invention).isEqualTo("Wireless communication"); } @@ -210,12 +205,12 @@ class SpelDocumentationTests extends AbstractExpressionTests { assertThat(city).isNotNull(); // setting values - Inventor i = parser.parseExpression("officers['advisors'][0]").getValue(societyContext,Inventor.class); + Inventor i = parser.parseExpression("officers['advisors'][0]").getValue(societyContext, Inventor.class); assertThat(i.getName()).isEqualTo("Nikola Tesla"); parser.parseExpression("officers['advisors'][0].PlaceOfBirth.Country").setValue(societyContext, "Croatia"); - Inventor i2 = parser.parseExpression("reverse[0]['advisors'][0]").getValue(societyContext,Inventor.class); + Inventor i2 = parser.parseExpression("reverse[0]['advisors'][0]").getValue(societyContext, Inventor.class); assertThat(i2.getName()).isEqualTo("Nikola Tesla"); } } @@ -489,7 +484,7 @@ class SpelDocumentationTests extends AbstractExpressionTests { parser.parseExpression("new org.springframework.expression.spel.testresources.Inventor('Albert Einstein',new java.util.Date(), 'German')").getValue(Inventor.class); assertThat(einstein.getName()).isEqualTo("Albert Einstein"); //create new inventor instance within add method of List - parser.parseExpression("Members2.add(new org.springframework.expression.spel.testresources.Inventor('Albert Einstein', 'German'))").getValue(societyContext); + parser.parseExpression("members.add(new org.springframework.expression.spel.testresources.Inventor('Albert Einstein', 'German'))").getValue(societyContext); } } @@ -632,11 +627,25 @@ class SpelDocumentationTests extends AbstractExpressionTests { @Test @SuppressWarnings("unchecked") void selection() { - StandardEvaluationContext societyContext = new StandardEvaluationContext(); - societyContext.setRootObject(new IEEE()); - List list = (List) parser.parseExpression("Members2.?[nationality == 'Serbian']").getValue(societyContext); - assertThat(list).hasSize(1); - assertThat(list.get(0).getName()).isEqualTo("Nikola Tesla"); + StandardEvaluationContext societyContext = new StandardEvaluationContext(new IEEE()); + // evaluates to ["Nikola Tesla"] + List list = (List) parser.parseExpression("members.?[nationality == 'Serbian']") + .getValue(societyContext); + assertThat(list).map(Inventor::getName).containsOnly("Nikola Tesla"); + } + } + + @Nested + class CollectionProjection { + + @Test + @SuppressWarnings("unchecked") + void projection() { + StandardEvaluationContext societyContext = new StandardEvaluationContext(new IEEE()); + // evaluates to ["SmilJan", "Idvor"] + List placesOfBirth = parser.parseExpression("members.![placeOfBirth.city]") + .getValue(societyContext, List.class); + assertThat(placesOfBirth).containsExactly("SmilJan", "Idvor"); } } @@ -654,22 +663,20 @@ class SpelDocumentationTests extends AbstractExpressionTests { static class IEEE { + private String name; - public Inventor[] Members = new Inventor[1]; - public List Members2 = new ArrayList(); - public Map officers = new HashMap<>(); + public List members = new ArrayList<>(); + + public Map officers = Map.of( + "president", pupin, + "advisors", List.of(tesla)); public List> reverse = new ArrayList<>(); - @SuppressWarnings("unchecked") IEEE() { - officers.put("president",pupin); - List linv = new ArrayList(); - linv.add(tesla); - officers.put("advisors",linv); - Members2.add(tesla); - Members2.add(pupin); + members.add(tesla); + members.add(pupin); reverse.add(officers); } @@ -678,8 +685,13 @@ class SpelDocumentationTests extends AbstractExpressionTests { return true; } - public String getName() { return name; } - public void setName(String n) { this.name = n; } + public String getName() { + return this.name; + } + + public void setName(String n) { + this.name = n; + } } static class StringUtils {