From 0d225694220b8880f8d1f6fa1fbc8125340e02b5 Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Wed, 27 Sep 2023 16:34:18 +0200 Subject: [PATCH 1/2] Polishing --- .../expression/spel/ast/MethodReference.java | 7 +++++-- .../expression/spel/ast/PropertyOrFieldReference.java | 6 ++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/MethodReference.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/MethodReference.java index ad8c8b69648..33756cab0e7 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/MethodReference.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/MethodReference.java @@ -54,10 +54,10 @@ import org.springframework.util.ObjectUtils; */ public class MethodReference extends SpelNodeImpl { - private final String name; - private final boolean nullSafe; + private final String name; + @Nullable private String originalPrimitiveExitTypeDescriptor; @@ -72,6 +72,9 @@ public class MethodReference extends SpelNodeImpl { } + /** + * Get the name of the referenced method. + */ public final String getName() { return this.name; } diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/PropertyOrFieldReference.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/PropertyOrFieldReference.java index 28762153950..dc891da4a4f 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/PropertyOrFieldReference.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/PropertyOrFieldReference.java @@ -73,10 +73,16 @@ public class PropertyOrFieldReference extends SpelNodeImpl { } + /** + * Does this node represent a null-safe property or field reference? + */ public boolean isNullSafe() { return this.nullSafe; } + /** + * Get the name of the referenced property or field. + */ public String getName() { return this.name; } From 6300fb37adf7ce81fa2fe2b23e6e8cf40ff9c3c1 Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Wed, 27 Sep 2023 16:35:31 +0200 Subject: [PATCH 2/2] Include '?' for null-safe navigation in SpEL AST representations Prior to this commit, if a Spring Expression Language (SpEL) expression contained property, field, or method references using the null-safe navigation operator (?.), the generated AST String representation incorrectly omitted the '?' characters. For example, 'myProperty?.myMethod()' had a generated AST string representation of 'myProperty.myMethod()'. This commit addresses this by introducing isNullSafe() in MethodReference and reworking the logic in CompoundExpression.toStringAST(). Closes gh-31326 --- .../expression/spel/ast/CompoundExpression.java | 8 +++++++- .../expression/spel/ast/MethodReference.java | 9 +++++++++ .../springframework/expression/spel/ParsingTests.java | 1 + 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/CompoundExpression.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/CompoundExpression.java index 01745e65cfc..8a540a908dc 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/CompoundExpression.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/CompoundExpression.java @@ -28,7 +28,9 @@ import org.springframework.expression.spel.SpelNode; /** * Represents a DOT separated expression sequence, such as - * {@code property1.property2.methodOne()}. + * {@code property1.property2.methodOne()} or + * {@code property1?.property2?.methodOne()} when the null-safe navigation + * operator is used. * *

May also contain array/collection/map indexers, such as * {@code property1[0].property2['key']}. @@ -122,6 +124,10 @@ public class CompoundExpression extends SpelNodeImpl { // Don't append a '.' if the next child is an Indexer. // For example, we want 'myVar[0]' instead of 'myVar.[0]'. if (!(nextChild instanceof Indexer)) { + if ((nextChild instanceof MethodReference methodRef && methodRef.isNullSafe()) || + (nextChild instanceof PropertyOrFieldReference pofRef && pofRef.isNullSafe())) { + sb.append('?'); + } sb.append('.'); } } diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/MethodReference.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/MethodReference.java index 33756cab0e7..e79e6a9affe 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/MethodReference.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/MethodReference.java @@ -50,6 +50,7 @@ import org.springframework.util.ObjectUtils; * * @author Andy Clement * @author Juergen Hoeller + * @author Sam Brannen * @since 3.0 */ public class MethodReference extends SpelNodeImpl { @@ -72,6 +73,14 @@ public class MethodReference extends SpelNodeImpl { } + /** + * Does this node represent a null-safe method reference? + * @since 6.0.13 + */ + public final boolean isNullSafe() { + return this.nullSafe; + } + /** * Get the name of the referenced method. */ diff --git a/spring-expression/src/test/java/org/springframework/expression/spel/ParsingTests.java b/spring-expression/src/test/java/org/springframework/expression/spel/ParsingTests.java index eea5e2e3333..6eeab7d6180 100644 --- a/spring-expression/src/test/java/org/springframework/expression/spel/ParsingTests.java +++ b/spring-expression/src/test/java/org/springframework/expression/spel/ParsingTests.java @@ -47,6 +47,7 @@ class ParsingTests { void compoundExpressions() { parseCheck("property1.property2.methodOne()"); parseCheck("property1[0].property2['key'].methodOne()"); + parseCheck("property1?.methodOne()?.property2?.methodTwo()"); } @Test