@@ -5,7 +5,17 @@ The safe navigation operator (`?`) is used to avoid a `NullPointerException` and
5
5
from the https://www.groovy-lang.org/operators.html#_safe_navigation_operator[Groovy]
6
6
language. Typically, when you have a reference to an object, you might need to verify
7
7
that it is not `null` before accessing methods or properties of the object. To avoid
8
- this, the safe navigation operator returns `null` instead of throwing an exception.
8
+ this, the safe navigation operator returns `null` for the particular null-safe operation
9
+ instead of throwing an exception.
10
+
11
+ [WARNING]
12
+ ====
13
+ When the safe navigation operator evaluates to `null` for a particular null-safe
14
+ operation within a compound expression, the remainder of the compound expression will
15
+ still be evaluated.
16
+
17
+ See <<expressions-operator-safe-navigation-compound-expressions>> for details.
18
+ ====
9
19
10
20
[[expressions-operator-safe-navigation-property-access]]
11
21
== Safe Property and Method Access
@@ -283,3 +293,71 @@ Kotlin::
283
293
======
284
294
285
295
296
+ [[expressions-operator-safe-navigation-compound-expressions]]
297
+ == Null-safe Operations in Compound Expressions
298
+
299
+ As mentioned at the beginning of this section, when the safe navigation operator
300
+ evaluates to `null` for a particular null-safe operation within a compound expression,
301
+ the remainder of the compound expression will still be evaluated. This means that the
302
+ safe navigation operator must be applied throughout a compound expression in order to
303
+ avoid any unwanted `NullPointerException`.
304
+
305
+ Given the expression `#person?.address.city`, if `#person` is `null` the safe navigation
306
+ operator (`?.`) ensures that no exception will be thrown when attempting to access the
307
+ `address` property of `#person`. However, since `#person?.address` evaluates to `null`, a
308
+ `NullPointerException` will be thrown when attempting to access the `city` property of
309
+ `null`. To address that, you can apply null-safe navigation throughout the compound
310
+ expression as in `#person?.address?.city`. That expression will safely evaluate to `null`
311
+ if either `#person` or `#person?.address` evaluates to `null`.
312
+
313
+ The following example demonstrates how to use the "null-safe select first" operator
314
+ (`?.^`) on a collection combined with null-safe property access (`?.`) within a compound
315
+ expression. If `members` is `null`, the result of the "null-safe select first" operator
316
+ (`members?.^[nationality == 'Serbian']`) evaluates to `null`, and the additional use of
317
+ the safe navigation operator (`?.name`) ensures that the entire compound expression
318
+ evaluates to `null` instead of throwing an exception.
319
+
320
+ [tabs]
321
+ ======
322
+ Java::
323
+ +
324
+ [source,java,indent=0,subs="verbatim,quotes",role="primary"]
325
+ ----
326
+ ExpressionParser parser = new SpelExpressionParser();
327
+ IEEE society = new IEEE();
328
+ StandardEvaluationContext context = new StandardEvaluationContext(society);
329
+ String expression = "members?.^[nationality == 'Serbian']?.name"; // <1>
330
+
331
+ // evaluates to "Nikola Tesla"
332
+ String name = parser.parseExpression(expression)
333
+ .getValue(context, String.class);
334
+
335
+ society.members = null;
336
+
337
+ // evaluates to null - does not throw a NullPointerException
338
+ name = parser.parseExpression(expression)
339
+ .getValue(context, String.class);
340
+ ----
341
+ <1> Use "null-safe select first" and null-safe property access operators within compound expression.
342
+
343
+ Kotlin::
344
+ +
345
+ [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
346
+ ----
347
+ val parser = SpelExpressionParser()
348
+ val society = IEEE()
349
+ val context = StandardEvaluationContext(society)
350
+ val expression = "members?.^[nationality == 'Serbian']?.name" // <1>
351
+
352
+ // evaluates to "Nikola Tesla"
353
+ String name = parser.parseExpression(expression)
354
+ .getValue(context, String::class.java)
355
+
356
+ society.members = null
357
+
358
+ // evaluates to null - does not throw a NullPointerException
359
+ name = parser.parseExpression(expression)
360
+ .getValue(context, String::class.java)
361
+ ----
362
+ <1> Use "null-safe select first" and null-safe property access operators within compound expression.
363
+ ======
0 commit comments