@ -7,6 +7,9 @@ language. Typically, when you have a reference to an object, you might need to v
@@ -7,6 +7,9 @@ language. Typically, when you have a reference to an object, you might need to v
that it is not `null` before accessing methods or properties of the object. To avoid
this, the safe navigation operator returns `null` instead of throwing an exception.
[[expressions-operator-safe-navigation-property-access]]
== Safe Property and Method Access
The following example shows how to use the safe navigation operator for property access
(`?.`).
@ -59,3 +62,224 @@ Kotlin::
@@ -59,3 +62,224 @@ Kotlin::
<2> Use safe navigation operator on null `placeOfBirth` property
======
[NOTE]
====
The safe navigation operator also applies to method invocations on an object.
For example, the expression `#calculator?.max(4, 2)` evaluates to `null` if the
`#calculator` variable has not been configured in the context. Otherwise, the
`max(int, int)` method will be invoked on the `#calculator`.
====
[[expressions-operator-safe-navigation-selection-and-projection]]
== Safe Collection Selection and Projection
The Spring Expression Language supports safe navigation for
xref:core/expressions/language-ref/collection-selection.adoc[collection selection] and
xref:core/expressions/language-ref/collection-projection.adoc[collection projection] via
the following operators.
* null-safe selection: `?.?`
* null-safe select first: `?.^`
* null-safe select last: `?.$`
* null-safe projection: `?.!`
The following example shows how to use the safe navigation operator for collection
selection (`?.?`).
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
----
ExpressionParser parser = new SpelExpressionParser();
IEEE society = new IEEE();
StandardEvaluationContext context = new StandardEvaluationContext(society);
String expression = "members?.?[nationality == 'Serbian']"; // <1>
// evaluates to [Inventor("Nikola Tesla")]
List<Inventor> list = (List<Inventor>) parser.parseExpression(expression)
.getValue(context);
society.members = null;
// evaluates to null - does not throw a NullPointerException
list = (List<Inventor>) parser.parseExpression(expression)
.getValue(context);
----
<1> Use null-safe selection operator on potentially null `members` list
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
----
val parser = SpelExpressionParser()
val society = IEEE()
val context = StandardEvaluationContext(society)
val expression = "members?.?[nationality == 'Serbian']" // <1>
// evaluates to [Inventor("Nikola Tesla")]
var list = parser.parseExpression(expression)
.getValue(context) as List<Inventor>
society.members = null
// evaluates to null - does not throw a NullPointerException
list = parser.parseExpression(expression)
.getValue(context) as List<Inventor>
----
<1> Use null-safe selection operator on potentially null `members` list
======
The following example shows how to use the "null-safe select first" operator for
collections (`?.^`).
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
----
ExpressionParser parser = new SpelExpressionParser();
IEEE society = new IEEE();
StandardEvaluationContext context = new StandardEvaluationContext(society);
String expression =
"members?.^[nationality == 'Serbian' || nationality == 'Idvor']"; // <1>
// evaluates to Inventor("Nikola Tesla")
Inventor inventor = parser.parseExpression(expression)
.getValue(context, Inventor.class);
society.members = null;
// evaluates to null - does not throw a NullPointerException
inventor = parser.parseExpression(expression)
.getValue(context, Inventor.class);
----
<1> Use "null-safe select first" operator on potentially null `members` list
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
----
val parser = SpelExpressionParser()
val society = IEEE()
val context = StandardEvaluationContext(society)
val expression =
"members?.^[nationality == 'Serbian' || nationality == 'Idvor']" // <1>
// evaluates to Inventor("Nikola Tesla")
var inventor = parser.parseExpression(expression)
.getValue(context, Inventor::class.java)
society.members = null
// evaluates to null - does not throw a NullPointerException
inventor = parser.parseExpression(expression)
.getValue(context, Inventor::class.java)
----
<1> Use "null-safe select first" operator on potentially null `members` list
======
The following example shows how to use the "null-safe select last" operator for
collections (`?.$`).
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
----
ExpressionParser parser = new SpelExpressionParser();
IEEE society = new IEEE();
StandardEvaluationContext context = new StandardEvaluationContext(society);
String expression =
"members?.$[nationality == 'Serbian' || nationality == 'Idvor']"; // <1>
// evaluates to Inventor("Pupin")
Inventor inventor = parser.parseExpression(expression)
.getValue(context, Inventor.class);
society.members = null;
// evaluates to null - does not throw a NullPointerException
inventor = parser.parseExpression(expression)
.getValue(context, Inventor.class);
----
<1> Use "null-safe select last" operator on potentially null `members` list
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
----
val parser = SpelExpressionParser()
val society = IEEE()
val context = StandardEvaluationContext(society)
val expression =
"members?.$[nationality == 'Serbian' || nationality == 'Idvor']" // <1>
// evaluates to Inventor("Pupin")
var inventor = parser.parseExpression(expression)
.getValue(context, Inventor::class.java)
society.members = null
// evaluates to null - does not throw a NullPointerException
inventor = parser.parseExpression(expression)
.getValue(context, Inventor::class.java)
----
<1> Use "null-safe select last" operator on potentially null `members` list
======
The following example shows how to use the safe navigation operator for collection
projection (`?.!`).
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
----
ExpressionParser parser = new SpelExpressionParser();
IEEE society = new IEEE();
StandardEvaluationContext context = new StandardEvaluationContext(society);
// evaluates to ["Smiljan", "Idvor"]
List placesOfBirth = parser.parseExpression("members?.![placeOfBirth.city]") // <1>
.getValue(context, List.class);
society.members = null;
// evaluates to null - does not throw a NullPointerException
placesOfBirth = parser.parseExpression("members?.![placeOfBirth.city]") // <2>
.getValue(context, List.class);
----
<1> Use null-safe projection operator on non-null `members` list
<2> Use null-safe projection operator on null `members` list
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
----
val parser = SpelExpressionParser()
val society = IEEE()
val context = StandardEvaluationContext(society)
// evaluates to ["Smiljan", "Idvor"]
var placesOfBirth = parser.parseExpression("members?.![placeOfBirth.city]") // <1>
.getValue(context, List::class.java)
society.members = null
// evaluates to null - does not throw a NullPointerException
placesOfBirth = parser.parseExpression("members?.![placeOfBirth.city]") // <2>
.getValue(context, List::class.java)
----
<1> Use null-safe projection operator on non-null `members` list
<2> Use null-safe projection operator on null `members` list
======