parent
2a1abb5553
commit
9f4d46fe33
|
@ -103,12 +103,12 @@ public class Indexer extends SpelNodeImpl {
|
|||
private PropertyAccessor cachedWriteAccessor;
|
||||
|
||||
|
||||
/**
|
||||
* Create an {@code Indexer} with the given start position, end position, and
|
||||
* index expression.
|
||||
*/
|
||||
public Indexer(int startPos, int endPos, SpelNodeImpl indexExpression) {
|
||||
super(startPos, endPos, indexExpression);
|
||||
private final boolean nullSafe;
|
||||
|
||||
|
||||
public Indexer(boolean nullSafe, int startPos, int endPos, SpelNodeImpl expr) {
|
||||
super(startPos, endPos, expr);
|
||||
this.nullSafe = nullSafe;
|
||||
}
|
||||
|
||||
|
||||
|
@ -161,6 +161,9 @@ public class Indexer extends SpelNodeImpl {
|
|||
|
||||
// Raise a proper exception in case of a null target
|
||||
if (target == null) {
|
||||
if (this.nullSafe) {
|
||||
return ValueRef.NullValueRef.INSTANCE;
|
||||
}
|
||||
throw new SpelEvaluationException(getStartPosition(), SpelMessage.CANNOT_INDEX_INTO_NULL_VALUE);
|
||||
}
|
||||
|
||||
|
|
|
@ -399,7 +399,7 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
|||
@Nullable
|
||||
private SpelNodeImpl eatNonDottedNode() {
|
||||
if (peekToken(TokenKind.LSQUARE)) {
|
||||
if (maybeEatIndexer()) {
|
||||
if (maybeEatIndexer(false)) {
|
||||
return pop();
|
||||
}
|
||||
}
|
||||
|
@ -419,7 +419,8 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
|||
Token t = takeToken(); // it was a '.' or a '?.'
|
||||
boolean nullSafeNavigation = (t.kind == TokenKind.SAFE_NAVI);
|
||||
if (maybeEatMethodOrProperty(nullSafeNavigation) || maybeEatFunctionOrVar() ||
|
||||
maybeEatProjection(nullSafeNavigation) || maybeEatSelection(nullSafeNavigation)) {
|
||||
maybeEatProjection(nullSafeNavigation) || maybeEatSelection(nullSafeNavigation) ||
|
||||
maybeEatIndexer(nullSafeNavigation)) {
|
||||
return pop();
|
||||
}
|
||||
if (peekToken() == null) {
|
||||
|
@ -537,7 +538,8 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
|||
else if (maybeEatBeanReference()) {
|
||||
return pop();
|
||||
}
|
||||
else if (maybeEatProjection(false) || maybeEatSelection(false) || maybeEatIndexer()) {
|
||||
else if (maybeEatProjection(false) || maybeEatSelection(false) ||
|
||||
maybeEatIndexer(false)) {
|
||||
return pop();
|
||||
}
|
||||
else if (maybeEatInlineListOrMap()) {
|
||||
|
@ -699,7 +701,7 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
|||
return true;
|
||||
}
|
||||
|
||||
private boolean maybeEatIndexer() {
|
||||
private boolean maybeEatIndexer(boolean nullSafeNavigation) {
|
||||
Token t = peekToken();
|
||||
if (t == null || !peekToken(TokenKind.LSQUARE, true)) {
|
||||
return false;
|
||||
|
@ -709,7 +711,7 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
|||
throw internalException(t.startPos, SpelMessage.MISSING_SELECTION_EXPRESSION);
|
||||
}
|
||||
eatToken(TokenKind.RSQUARE);
|
||||
this.constructedNodes.push(new Indexer(t.startPos, t.endPos, expr));
|
||||
this.constructedNodes.push(new Indexer(nullSafeNavigation, t.startPos, t.endPos, expr));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -376,6 +376,20 @@ class IndexingTests {
|
|||
assertThat(expression.getValue(this, String.class)).isEqualTo("apple");
|
||||
}
|
||||
|
||||
@Test
|
||||
void nullSafeIndex() {
|
||||
ContextWithNullCollections testContext = new ContextWithNullCollections();
|
||||
StandardEvaluationContext context = new StandardEvaluationContext(testContext);
|
||||
Expression expr = new SpelExpressionParser().parseRaw("nullList?.[4]");
|
||||
assertThat(expr.getValue(context)).isNull();
|
||||
|
||||
expr = new SpelExpressionParser().parseRaw("nullArray?.[4]");
|
||||
assertThat(expr.getValue(context)).isNull();
|
||||
|
||||
expr = new SpelExpressionParser().parseRaw("nullMap:?.[4]");
|
||||
assertThat(expr.getValue(context)).isNull();
|
||||
}
|
||||
|
||||
|
||||
@Target({ElementType.FIELD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
|
@ -436,4 +450,11 @@ class IndexingTests {
|
|||
|
||||
}
|
||||
|
||||
|
||||
static class ContextWithNullCollections {
|
||||
public List nullList = null;
|
||||
public String[] nullArray = null;
|
||||
public Map nullMap = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue