Merge branch '6.1.x'

This commit is contained in:
Sam Brannen 2024-03-22 16:37:55 +01:00
commit b695dbc2bf
4 changed files with 22 additions and 12 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -24,7 +24,6 @@ import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.CodeFlow;
import org.springframework.expression.spel.ExpressionState;
import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.expression.spel.SpelNode;
/**
* Represents a DOT separated expression sequence, such as
@ -120,14 +119,13 @@ public class CompoundExpression extends SpelNodeImpl {
for (int i = 0; i < getChildCount(); i++) {
sb.append(getChild(i).toStringAST());
if (i < getChildCount() - 1) {
SpelNode nextChild = getChild(i + 1);
SpelNodeImpl nextChild = this.children[i + 1];
if (nextChild.isNullSafe()) {
sb.append("?.");
}
// 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('?');
}
else if (!(nextChild instanceof Indexer)) {
sb.append('.');
}
}

View File

@ -77,6 +77,7 @@ public class MethodReference extends SpelNodeImpl {
* Does this node represent a null-safe method reference?
* @since 6.0.13
*/
@Override
public final boolean isNullSafe() {
return this.nullSafe;
}

View File

@ -76,6 +76,7 @@ public class PropertyOrFieldReference extends SpelNodeImpl {
/**
* Does this node represent a null-safe property or field reference?
*/
@Override
public boolean isNullSafe() {
return this.nullSafe;
}
@ -181,7 +182,7 @@ public class PropertyOrFieldReference extends SpelNodeImpl {
throws EvaluationException {
Object targetObject = contextObject.getValue();
if (targetObject == null && this.nullSafe) {
if (targetObject == null && isNullSafe()) {
return TypedValue.NULL;
}
@ -233,7 +234,7 @@ public class PropertyOrFieldReference extends SpelNodeImpl {
TypedValue contextObject, EvaluationContext evalContext, String name, @Nullable Object newValue)
throws EvaluationException {
if (contextObject.getValue() == null && this.nullSafe) {
if (contextObject.getValue() == null && isNullSafe()) {
return;
}
if (contextObject.getValue() == null) {
@ -353,7 +354,7 @@ public class PropertyOrFieldReference extends SpelNodeImpl {
}
Label skipIfNull = null;
if (this.nullSafe) {
if (isNullSafe()) {
mv.visitInsn(DUP);
skipIfNull = new Label();
Label continueLabel = new Label();
@ -381,7 +382,7 @@ public class PropertyOrFieldReference extends SpelNodeImpl {
// If this property or field access would return a primitive - and yet
// it is also marked null safe - then the exit type descriptor must be
// promoted to the box type to allow a null value to be passed on
if (this.nullSafe && CodeFlow.isPrimitive(descriptor)) {
if (isNullSafe() && CodeFlow.isPrimitive(descriptor)) {
this.originalPrimitiveExitTypeDescriptor = descriptor;
this.exitTypeDescriptor = CodeFlow.toBoxedDescriptor(descriptor);
}

View File

@ -181,6 +181,16 @@ public abstract class SpelNodeImpl implements SpelNode, Opcodes {
return this.endPos;
}
/**
* Determine if this node is the target of a null-safe navigation operation.
* <p>The default implementation returns {@code false}.
* @return {@code true} if this node is the target of a null-safe operation
* @since 6.1.6
*/
public boolean isNullSafe() {
return false;
}
/**
* Check whether a node can be compiled to bytecode. The reasoning in each node may
* be different but will typically involve checking whether the exit type descriptor