Skip to content

Commit 78c96b6

Browse files
committed
Fix SpEL collection selection/projection examples in reference manual
This commit also updates and polishes the documentation tests.
1 parent 43bbe8f commit 78c96b6

File tree

3 files changed

+59
-44
lines changed

3 files changed

+59
-44
lines changed

framework-docs/modules/ROOT/pages/core/expressions/language-ref/collection-projection.adoc

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,18 @@ Java::
1313
+
1414
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
1515
----
16-
// returns ['Smiljan', 'Idvor' ]
17-
List placesOfBirth = (List)parser.parseExpression("members.![placeOfBirth.city]");
16+
// evaluates to ["SmilJan", "Idvor"]
17+
List placesOfBirth = parser.parseExpression("members.![placeOfBirth.city]")
18+
.getValue(societyContext, List.class);
1819
----
1920
2021
Kotlin::
2122
+
2223
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
2324
----
24-
// returns ['Smiljan', 'Idvor' ]
25-
val placesOfBirth = parser.parseExpression("members.![placeOfBirth.city]") as List<*>
25+
// evaluates to ["SmilJan", "Idvor"]
26+
val placesOfBirth = parser.parseExpression("members.![placeOfBirth.city]")
27+
.getValue(societyContext) as List<*>
2628
----
2729
======
2830

framework-docs/modules/ROOT/pages/core/expressions/language-ref/collection-selection.adoc

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,35 +28,36 @@ Kotlin::
2828
======
2929

3030
Selection is supported for arrays and anything that implements `java.lang.Iterable` or
31-
`java.util.Map`. For a list or array, the selection criteria is evaluated against each
32-
individual element. Against a map, the selection criteria is evaluated against each map
33-
entry (objects of the Java type `Map.Entry`). Each map entry has its `key` and `value`
34-
accessible as properties for use in the selection.
31+
`java.util.Map`. For an array or `Iterable`, the selection expression is evaluated
32+
against each individual element. Against a map, the selection expression is evaluated
33+
against each map entry (objects of the Java type `Map.Entry`). Each map entry has its
34+
`key` and `value` accessible as properties for use in the selection.
3535

36-
The following expression returns a new map that consists of those elements of the
37-
original map where the entry's value is less than 27:
36+
Given a `Map` stored in a variable named `#map`, the following expression returns a new
37+
map that consists of those elements of the original map where the entry's value is less
38+
than 27:
3839

3940
[tabs]
4041
======
4142
Java::
4243
+
4344
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
4445
----
45-
Map newMap = parser.parseExpression("map.?[value<27]").getValue();
46+
Map newMap = parser.parseExpression("#map.?[value < 27]").getValue(Map.class);
4647
----
4748
4849
Kotlin::
4950
+
5051
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
5152
----
52-
val newMap = parser.parseExpression("map.?[value<27]").getValue()
53+
val newMap = parser.parseExpression("#map.?[value < 27]").getValue() as Map
5354
----
5455
======
5556

5657
In addition to returning all the selected elements, you can retrieve only the first or
57-
the last element. To obtain the first element matching the selection, the syntax is
58-
`.^[selectionExpression]`. To obtain the last matching selection, the syntax is
59-
`.$[selectionExpression]`.
58+
the last element. To obtain the first element matching the selection expression, the
59+
syntax is `.^[selectionExpression]`. To obtain the last element matching the selection
60+
expression, the syntax is `.$[selectionExpression]`.
6061

6162

6263

spring-expression/src/test/java/org/springframework/expression/spel/SpelDocumentationTests.java

Lines changed: 41 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
import java.util.ArrayList;
2323
import java.util.Date;
2424
import java.util.GregorianCalendar;
25-
import java.util.HashMap;
2625
import java.util.List;
2726
import java.util.Map;
2827

@@ -172,28 +171,24 @@ void propertyAccess() {
172171
@Test
173172
void propertyNavigation() {
174173
ExpressionParser parser = new SpelExpressionParser();
175-
176-
// Inventions Array
177174
StandardEvaluationContext teslaContext = TestScenarioCreator.getTestEvaluationContext();
178-
// teslaContext.setRootObject(tesla);
179175

176+
// Inventions Array
180177
// evaluates to "Induction motor"
181178
String invention = parser.parseExpression("inventions[3]").getValue(teslaContext, String.class);
182179
assertThat(invention).isEqualTo("Induction motor");
183180

184181
// Members List
185182
StandardEvaluationContext societyContext = new StandardEvaluationContext();
186-
IEEE ieee = new IEEE();
187-
ieee.Members[0]= tesla;
188-
societyContext.setRootObject(ieee);
183+
societyContext.setRootObject(new IEEE());
189184

190185
// evaluates to "Nikola Tesla"
191-
String name = parser.parseExpression("Members[0].Name").getValue(societyContext, String.class);
186+
String name = parser.parseExpression("members[0].Name").getValue(societyContext, String.class);
192187
assertThat(name).isEqualTo("Nikola Tesla");
193188

194189
// List and Array navigation
195190
// evaluates to "Wireless communication"
196-
invention = parser.parseExpression("Members[0].Inventions[6]").getValue(societyContext, String.class);
191+
invention = parser.parseExpression("members[0].Inventions[6]").getValue(societyContext, String.class);
197192
assertThat(invention).isEqualTo("Wireless communication");
198193
}
199194

@@ -210,12 +205,12 @@ void maps() {
210205
assertThat(city).isNotNull();
211206

212207
// setting values
213-
Inventor i = parser.parseExpression("officers['advisors'][0]").getValue(societyContext,Inventor.class);
208+
Inventor i = parser.parseExpression("officers['advisors'][0]").getValue(societyContext, Inventor.class);
214209
assertThat(i.getName()).isEqualTo("Nikola Tesla");
215210

216211
parser.parseExpression("officers['advisors'][0].PlaceOfBirth.Country").setValue(societyContext, "Croatia");
217212

218-
Inventor i2 = parser.parseExpression("reverse[0]['advisors'][0]").getValue(societyContext,Inventor.class);
213+
Inventor i2 = parser.parseExpression("reverse[0]['advisors'][0]").getValue(societyContext, Inventor.class);
219214
assertThat(i2.getName()).isEqualTo("Nikola Tesla");
220215
}
221216
}
@@ -489,7 +484,7 @@ void constructors() {
489484
parser.parseExpression("new org.springframework.expression.spel.testresources.Inventor('Albert Einstein',new java.util.Date(), 'German')").getValue(Inventor.class);
490485
assertThat(einstein.getName()).isEqualTo("Albert Einstein");
491486
//create new inventor instance within add method of List
492-
parser.parseExpression("Members2.add(new org.springframework.expression.spel.testresources.Inventor('Albert Einstein', 'German'))").getValue(societyContext);
487+
parser.parseExpression("members.add(new org.springframework.expression.spel.testresources.Inventor('Albert Einstein', 'German'))").getValue(societyContext);
493488
}
494489
}
495490

@@ -632,11 +627,25 @@ class CollectionSelection {
632627
@Test
633628
@SuppressWarnings("unchecked")
634629
void selection() {
635-
StandardEvaluationContext societyContext = new StandardEvaluationContext();
636-
societyContext.setRootObject(new IEEE());
637-
List<Inventor> list = (List<Inventor>) parser.parseExpression("Members2.?[nationality == 'Serbian']").getValue(societyContext);
638-
assertThat(list).hasSize(1);
639-
assertThat(list.get(0).getName()).isEqualTo("Nikola Tesla");
630+
StandardEvaluationContext societyContext = new StandardEvaluationContext(new IEEE());
631+
// evaluates to ["Nikola Tesla"]
632+
List<Inventor> list = (List<Inventor>) parser.parseExpression("members.?[nationality == 'Serbian']")
633+
.getValue(societyContext);
634+
assertThat(list).map(Inventor::getName).containsOnly("Nikola Tesla");
635+
}
636+
}
637+
638+
@Nested
639+
class CollectionProjection {
640+
641+
@Test
642+
@SuppressWarnings("unchecked")
643+
void projection() {
644+
StandardEvaluationContext societyContext = new StandardEvaluationContext(new IEEE());
645+
// evaluates to ["SmilJan", "Idvor"]
646+
List placesOfBirth = parser.parseExpression("members.![placeOfBirth.city]")
647+
.getValue(societyContext, List.class);
648+
assertThat(placesOfBirth).containsExactly("SmilJan", "Idvor");
640649
}
641650
}
642651

@@ -654,22 +663,20 @@ void templating() {
654663

655664

656665
static class IEEE {
666+
657667
private String name;
658668

659-
public Inventor[] Members = new Inventor[1];
660-
public List Members2 = new ArrayList();
661-
public Map<String,Object> officers = new HashMap<>();
669+
public List<Inventor> members = new ArrayList<>();
670+
671+
public Map<String,Object> officers = Map.of(
672+
"president", pupin,
673+
"advisors", List.of(tesla));
662674

663675
public List<Map<String, Object>> reverse = new ArrayList<>();
664676

665-
@SuppressWarnings("unchecked")
666677
IEEE() {
667-
officers.put("president",pupin);
668-
List linv = new ArrayList();
669-
linv.add(tesla);
670-
officers.put("advisors",linv);
671-
Members2.add(tesla);
672-
Members2.add(pupin);
678+
members.add(tesla);
679+
members.add(pupin);
673680

674681
reverse.add(officers);
675682
}
@@ -678,8 +685,13 @@ public boolean isMember(String name) {
678685
return true;
679686
}
680687

681-
public String getName() { return name; }
682-
public void setName(String n) { this.name = n; }
688+
public String getName() {
689+
return this.name;
690+
}
691+
692+
public void setName(String n) {
693+
this.name = n;
694+
}
683695
}
684696

685697
static class StringUtils {

0 commit comments

Comments
 (0)