11[[expressions-properties-arrays]]
22= Properties, Arrays, Lists, Maps, and Indexers
33
4- Navigating with property references is easy. To do so, use a period to indicate a nested
5- property value. The instances of the `Inventor` class, `pupin` and `tesla`, were
6- populated with data listed in the xref:core/expressions/example-classes.adoc[Classes used in the examples]
7- section. To navigate "down" the object graph and get Tesla's year of birth and
8- Pupin's city of birth, we use the following expressions:
4+ The Spring Expression Language provides support for navigating object graphs and indexing
5+ into various structures.
6+
7+ NOTE: Numerical index values are zero-based, such as when accessing the n^th^ element of
8+ an array in Java.
9+
10+ [[expressions-property-navigation]]
11+ == Property Navigation
12+
13+ You can navigate property references within an object graph by using a period to indicate
14+ a nested property value. The instances of the `Inventor` class, `pupin` and `tesla`, were
15+ populated with data listed in the
16+ xref:core/expressions/example-classes.adoc[Classes used in the examples] section. To
17+ navigate _down_ the object graph and get Tesla's year of birth and Pupin's city of birth,
18+ we use the following expressions:
919
1020[tabs]
1121======
1626 // evaluates to 1856
1727 int year = (Integer) parser.parseExpression("birthdate.year + 1900").getValue(context);
1828
29+ // evaluates to "Smiljan"
1930 String city = (String) parser.parseExpression("placeOfBirth.city").getValue(context);
2031----
2132
@@ -26,6 +37,7 @@ Kotlin::
2637 // evaluates to 1856
2738 val year = parser.parseExpression("birthdate.year + 1900").getValue(context) as Int
2839
40+ // evaluates to "Smiljan"
2941 val city = parser.parseExpression("placeOfBirth.city").getValue(context) as String
3042----
3143======
@@ -39,8 +51,20 @@ method invocations -- for example, `getPlaceOfBirth().getCity()` instead of
3951`placeOfBirth.city`.
4052====
4153
42- The contents of arrays and lists are obtained by using square bracket notation, as the
43- following example shows:
54+ [[expressions-indexing-arrays-and-collections]]
55+ == Indexing into Arrays and Collections
56+
57+ The n^th^ element of an array or collection (for example, a `Set` or `List`) can be
58+ obtained by using square bracket notation, as the following example shows.
59+
60+ [NOTE]
61+ ====
62+ If the indexed collection is a `java.util.List`, the n^th^ element will be accessed
63+ directly via `list.get(n)`.
64+
65+ For any other type of `Collection`, the n^th^ element will be accessed by iterating over
66+ the collection using its `Iterator` and returning the n^th^ element encountered.
67+ ====
4468
4569[tabs]
4670======
6387 String name = parser.parseExpression("members[0].name").getValue(
6488 context, ieee, String.class);
6589
66- // List and Array navigation
90+ // List and Array Indexing
91+
6792 // evaluates to "Wireless communication"
6893 String invention = parser.parseExpression("members[0].inventions[6]").getValue(
6994 context, ieee, String.class);
@@ -88,55 +113,136 @@ Kotlin::
88113 val name = parser.parseExpression("members[0].name").getValue(
89114 context, ieee, String::class.java)
90115
91- // List and Array navigation
116+ // List and Array Indexing
117+
92118 // evaluates to "Wireless communication"
93119 val invention = parser.parseExpression("members[0].inventions[6]").getValue(
94120 context, ieee, String::class.java)
95121----
96122======
97123
98- The contents of maps are obtained by specifying the literal key value within the
99- brackets. In the following example, because keys for the `officers` map are strings, we can specify
100- string literals:
124+ [[expressions-indexing-strings]]
125+ == Indexing into Strings
126+
127+ The n^th^ character of a string can be obtained by specifying the index within square
128+ brackets, as demonstrated in the following example.
129+
130+ NOTE: The n^th^ character of a string will evaluate to a `java.lang.String`, not a
131+ `java.lang.Character`.
101132
102133[tabs]
103134======
104135Java::
105136+
106137[source,java,indent=0,subs="verbatim,quotes",role="primary"]
107138----
108- // Officer's Dictionary
139+ // evaluates to "T" (8th letter of "Nikola Tesla")
140+ String character = parser.parseExpression("members[0].name[7]")
141+ .getValue(societyContext, String.class);
142+ ----
109143
110- Inventor pupin = parser.parseExpression("officers['president']").getValue(
111- societyContext, Inventor.class);
144+ Kotlin::
145+ +
146+ [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
147+ ----
148+ // evaluates to "T" (8th letter of "Nikola Tesla")
149+ val character = parser.parseExpression("members[0].name[7]")
150+ .getValue(societyContext, String::class.java)
151+ ----
152+ ======
153+
154+ [[expressions-indexing-maps]]
155+ == Indexing into Maps
156+
157+ The contents of maps are obtained by specifying the key value within square brackets. In
158+ the following example, because keys for the `officers` map are strings, we can specify
159+ string literals such as `'president'`:
160+
161+ [tabs]
162+ ======
163+ Java::
164+ +
165+ [source,java,indent=0,subs="verbatim,quotes",role="primary"]
166+ ----
167+ // Officer's Map
168+
169+ // evaluates to Inventor("Pupin")
170+ Inventor pupin = parser.parseExpression("officers['president']")
171+ .getValue(societyContext, Inventor.class);
112172
113173 // evaluates to "Idvor"
114- String city = parser.parseExpression("officers['president'].placeOfBirth.city").getValue(
115- societyContext, String.class);
174+ String city = parser.parseExpression("officers['president'].placeOfBirth.city")
175+ .getValue(societyContext, String.class);
176+
177+ String countryExpression = "officers['advisors'][0].placeOfBirth.country";
116178
117179 // setting values
118- parser.parseExpression("officers['advisors'][0].placeOfBirth.country").setValue(
119- societyContext, "Croatia");
180+ parser.parseExpression(countryExpression)
181+ .setValue(societyContext, "Croatia");
182+
183+ // evaluates to "Croatia"
184+ String country = parser.parseExpression(countryExpression)
185+ .getValue(societyContext, String.class);
120186----
121187
122188Kotlin::
123189+
124190[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
125191----
126- // Officer's Dictionary
192+ // Officer's Map
127193
128- val pupin = parser.parseExpression("officers['president']").getValue(
129- societyContext, Inventor::class.java)
194+ // evaluates to Inventor("Pupin")
195+ val pupin = parser.parseExpression("officers['president']")
196+ .getValue(societyContext, Inventor::class.java)
130197
131198 // evaluates to "Idvor"
132- val city = parser.parseExpression("officers['president'].placeOfBirth.city").getValue(
133- societyContext, String::class.java)
199+ val city = parser.parseExpression("officers['president'].placeOfBirth.city")
200+ .getValue(societyContext, String::class.java)
201+
202+ val countryExpression = "officers['advisors'][0].placeOfBirth.country"
134203
135204 // setting values
136- parser.parseExpression("officers['advisors'][0].placeOfBirth.country").setValue(
137- societyContext, "Croatia")
205+ parser.parseExpression(countryExpression)
206+ .setValue(societyContext, "Croatia")
207+
208+ // evaluates to "Croatia"
209+ val country = parser.parseExpression(countryExpression)
210+ .getValue(societyContext, String::class.java)
138211----
139212======
140213
214+ [[expressions-indexing-objects]]
215+ == Indexing into Objects
216+
217+ A property of an object can be obtained by specifying the name of the property within
218+ square brackets. This is analogous to accessing the value of a map based on its key. The
219+ following example demonstrates how to _index_ into an object to retrieve a specific
220+ property.
221+
222+ [tabs]
223+ ======
224+ Java::
225+ +
226+ [source,java,indent=0,subs="verbatim,quotes",role="primary"]
227+ ----
228+ // Create an inventor to use as the root context object.
229+ Inventor tesla = new Inventor("Nikola Tesla");
230+
231+ // evaluates to "Nikola Tesla"
232+ String name = parser.parseExpression("#root['name']")
233+ .getValue(context, tesla, String.class);
234+ ----
141235
236+ Kotlin::
237+ +
238+ [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
239+ ----
240+ // Create an inventor to use as the root context object.
241+ val tesla = Inventor("Nikola Tesla")
242+
243+ // evaluates to "Nikola Tesla"
244+ val name = parser.parseExpression("#root['name']")
245+ .getValue(context, tesla, String::class.java)
246+ ----
247+ ======
142248
0 commit comments