Skip to content

Commit 347d085

Browse files
committed
Polishing
1 parent f295def commit 347d085

File tree

8 files changed

+76
-30
lines changed

8 files changed

+76
-30
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ Java::
1313
+
1414
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
1515
----
16-
// evaluates to ["SmilJan", "Idvor"]
16+
// evaluates to ["Smiljan", "Idvor"]
1717
List placesOfBirth = parser.parseExpression("members.![placeOfBirth.city]")
1818
.getValue(societyContext, List.class);
1919
----
@@ -22,7 +22,7 @@ Kotlin::
2222
+
2323
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
2424
----
25-
// evaluates to ["SmilJan", "Idvor"]
25+
// evaluates to ["Smiljan", "Idvor"]
2626
val placesOfBirth = parser.parseExpression("members.![placeOfBirth.city]")
2727
.getValue(societyContext) as List<*>
2828
----

framework-docs/modules/ROOT/pages/core/expressions/language-ref/operator-safe-navigation.adoc

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
[[expressions-operator-safe-navigation]]
22
= Safe Navigation Operator
33

4-
The safe navigation operator is used to avoid a `NullPointerException` and comes from
5-
the https://www.groovy-lang.org/operators.html#_safe_navigation_operator[Groovy]
6-
language. Typically, when you have a reference to an object, you might need to verify that
7-
it is not null before accessing methods or properties of the object. To avoid this, the
8-
safe navigation operator returns null instead of throwing an exception. The following
9-
example shows how to use the safe navigation operator:
4+
The safe navigation operator (`?`) is used to avoid a `NullPointerException` and comes
5+
from the https://www.groovy-lang.org/operators.html#_safe_navigation_operator[Groovy]
6+
language. Typically, when you have a reference to an object, you might need to verify
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.
9+
10+
The following example shows how to use the safe navigation operator for property access
11+
(`?.`).
1012

1113
[tabs]
1214
======
@@ -20,13 +22,18 @@ Java::
2022
Inventor tesla = new Inventor("Nikola Tesla", "Serbian");
2123
tesla.setPlaceOfBirth(new PlaceOfBirth("Smiljan"));
2224
23-
String city = parser.parseExpression("placeOfBirth?.city").getValue(context, tesla, String.class);
24-
System.out.println(city); // Smiljan
25+
// evaluates to "Smiljan"
26+
String city = parser.parseExpression("placeOfBirth?.city") // <1>
27+
.getValue(context, tesla, String.class);
2528
2629
tesla.setPlaceOfBirth(null);
27-
city = parser.parseExpression("placeOfBirth?.city").getValue(context, tesla, String.class);
28-
System.out.println(city); // null - does not throw NullPointerException!!!
30+
31+
// evaluates to null - does not throw NullPointerException
32+
city = parser.parseExpression("placeOfBirth?.city") // <2>
33+
.getValue(context, tesla, String.class);
2934
----
35+
<1> Use safe navigation operator on non-null `placeOfBirth` property
36+
<2> Use safe navigation operator on null `placeOfBirth` property
3037
3138
Kotlin::
3239
+
@@ -38,14 +45,17 @@ Kotlin::
3845
val tesla = Inventor("Nikola Tesla", "Serbian")
3946
tesla.setPlaceOfBirth(PlaceOfBirth("Smiljan"))
4047
41-
var city = parser.parseExpression("placeOfBirth?.city").getValue(context, tesla, String::class.java)
42-
println(city) // Smiljan
48+
// evaluates to "Smiljan"
49+
var city = parser.parseExpression("placeOfBirth?.city") // <1>
50+
.getValue(context, tesla, String::class.java)
4351
4452
tesla.setPlaceOfBirth(null)
45-
city = parser.parseExpression("placeOfBirth?.city").getValue(context, tesla, String::class.java)
46-
println(city) // null - does not throw NullPointerException!!!
53+
54+
// evaluates to null - does not throw NullPointerException
55+
city = parser.parseExpression("placeOfBirth?.city") // <2>
56+
.getValue(context, tesla, String::class.java)
4757
----
58+
<1> Use safe navigation operator on non-null `placeOfBirth` property
59+
<2> Use safe navigation operator on null `placeOfBirth` property
4860
======
4961

50-
51-

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ void indexerError() {
234234

235235
@Test
236236
void stringType() {
237-
evaluateAndAskForReturnType("getPlaceOfBirth().getCity()", "SmilJan", String.class);
237+
evaluateAndAskForReturnType("getPlaceOfBirth().getCity()", "Smiljan", String.class);
238238
}
239239

240240
@Test
@@ -594,7 +594,7 @@ class NestedPropertiesTests {
594594
// nested properties
595595
@Test
596596
void propertiesNested01() {
597-
evaluate("placeOfBirth.city", "SmilJan", String.class, true);
597+
evaluate("placeOfBirth.city", "Smiljan", String.class, true);
598598
}
599599

600600
@Test

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ class MethodInvocationTests extends AbstractExpressionTests {
4949

5050
@Test
5151
void testSimpleAccess01() {
52-
evaluate("getPlaceOfBirth().getCity()", "SmilJan", String.class);
52+
evaluate("getPlaceOfBirth().getCity()", "Smiljan", String.class);
5353
}
5454

5555
@Test

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

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2023 the original author or authors.
2+
* Copyright 2002-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.expression.spel;
1818

19+
import java.lang.reflect.Method;
1920
import java.math.BigDecimal;
2021
import java.math.BigInteger;
2122

@@ -24,6 +25,8 @@
2425
import org.springframework.expression.Expression;
2526
import org.springframework.expression.spel.ast.Operator;
2627
import org.springframework.expression.spel.standard.SpelExpression;
28+
import org.springframework.expression.spel.standard.SpelExpressionParser;
29+
import org.springframework.expression.spel.support.StandardEvaluationContext;
2730

2831
import static org.assertj.core.api.Assertions.assertThat;
2932
import static org.springframework.expression.spel.SpelMessage.MAX_CONCATENATED_STRING_LENGTH_EXCEEDED;
@@ -670,6 +673,18 @@ void bigIntegers() {
670673
evaluate("new java.math.BigInteger('5') ^ 3", new BigInteger("125"), BigInteger.class);
671674
}
672675

676+
@Test
677+
void bigIntFunction() throws Exception {
678+
SpelExpressionParser parser = new SpelExpressionParser();
679+
StandardEvaluationContext context = new StandardEvaluationContext();
680+
Method method = BigInteger.class.getMethod("valueOf", long.class);
681+
context.registerFunction("bigInt", method);
682+
683+
Expression expression = parser.parseExpression("3 + #bigInt(5)");
684+
BigInteger result = expression.getValue(context, BigInteger.class);
685+
assertThat(result).isEqualTo(BigInteger.valueOf(8));
686+
}
687+
673688

674689
private Operator getOperatorNode(SpelExpression expr) {
675690
SpelNode node = expr.getAST();

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ void simpleAccess01() {
5858

5959
@Test
6060
void simpleAccess02() {
61-
evaluate("placeOfBirth.city", "SmilJan", String.class);
61+
evaluate("placeOfBirth.city", "Smiljan", String.class);
6262
}
6363

6464
@Test

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

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ class SpelDocumentationTests extends AbstractExpressionTests {
6565
GregorianCalendar c = new GregorianCalendar();
6666
c.set(1856, 7, 9);
6767
tesla = new Inventor("Nikola Tesla", c.getTime(), "Serbian");
68-
tesla.setPlaceOfBirth(new PlaceOfBirth("SmilJan"));
68+
tesla.setPlaceOfBirth(new PlaceOfBirth("Smiljan"));
6969
tesla.setInventions("Telephone repeater", "Rotating magnetic field principle",
7070
"Polyphase alternating-current system", "Induction motor", "Alternating-current power transmission",
7171
"Tesla coil transformer", "Wireless communication", "Radio", "Fluorescent lights");
@@ -167,7 +167,7 @@ void propertyAccess() {
167167
assertThat(year).isEqualTo(1856);
168168

169169
String city = (String) parser.parseExpression("placeOfBirth.City").getValue(context);
170-
assertThat(city).isEqualTo("SmilJan");
170+
assertThat(city).isEqualTo("Smiljan");
171171
}
172172

173173
@Test
@@ -616,11 +616,10 @@ void ternary() {
616616
StandardEvaluationContext societyContext = new StandardEvaluationContext();
617617
societyContext.setRootObject(new IEEE());
618618

619-
620619
parser.parseExpression("Name").setValue(societyContext, "IEEE");
621620
societyContext.setVariable("queryName", "Nikola Tesla");
622621

623-
String expression = "isMember(#queryName)? #queryName + ' is a member of the ' "
622+
String expression = "isMember(#queryName) ? #queryName + ' is a member of the ' "
624623
+ "+ Name + ' Society' : #queryName + ' is not a member of the ' + Name + ' Society'";
625624

626625
String queryResultString = parser.parseExpression(expression).getValue(societyContext, String.class);
@@ -629,6 +628,28 @@ void ternary() {
629628
}
630629
}
631630

631+
@Nested
632+
class SaveNavigationOperator {
633+
634+
@Test
635+
void nullSafePropertyAccess() {
636+
Inventor tesla = new Inventor("Nikola Tesla", "Serbian");
637+
tesla.setPlaceOfBirth(new PlaceOfBirth("Smiljan"));
638+
639+
// evaluates to "Smiljan"
640+
String city = parser.parseExpression("placeOfBirth?.city") // <1>
641+
.getValue(context, tesla, String.class);
642+
assertThat(city).isEqualTo("Smiljan");
643+
644+
tesla.setPlaceOfBirth(null);
645+
646+
// evaluates to null - does not throw a NullPointerException
647+
city = parser.parseExpression("placeOfBirth?.city") // <2>
648+
.getValue(context, tesla, String.class);
649+
assertThat(city).isNull();
650+
}
651+
}
652+
632653
@Nested
633654
class CollectionSelection {
634655

@@ -650,10 +671,10 @@ class CollectionProjection {
650671
@SuppressWarnings("unchecked")
651672
void projection() {
652673
StandardEvaluationContext societyContext = new StandardEvaluationContext(new IEEE());
653-
// evaluates to ["SmilJan", "Idvor"]
674+
// evaluates to ["Smiljan", "Idvor"]
654675
List placesOfBirth = parser.parseExpression("members.![placeOfBirth.city]")
655676
.getValue(societyContext, List.class);
656-
assertThat(placesOfBirth).containsExactly("SmilJan", "Idvor");
677+
assertThat(placesOfBirth).containsExactly("Smiljan", "Idvor");
657678
}
658679
}
659680

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ private static void setupRootContextObject(StandardEvaluationContext context) {
119119
GregorianCalendar c = new GregorianCalendar();
120120
c.set(1856, 7, 9);
121121
Inventor tesla = new Inventor("Nikola Tesla", c.getTime(), "Serbian");
122-
tesla.setPlaceOfBirth(new PlaceOfBirth("SmilJan"));
122+
tesla.setPlaceOfBirth(new PlaceOfBirth("Smiljan"));
123123
tesla.setInventions("Telephone repeater", "Rotating magnetic field principle",
124124
"Polyphase alternating-current system", "Induction motor", "Alternating-current power transmission",
125125
"Tesla coil transformer", "Wireless communication", "Radio", "Fluorescent lights");

0 commit comments

Comments
 (0)