Disable variable assignment in SimpleEvaluationContext
This commit introduces infrastructure to differentiate between programmatic setting of a variable in an EvaluationContext versus the assignment of a variable within a SpEL expression using the assignment operator (=). In addition, this commit disables variable assignment within expressions when using the SimpleEvaluationContext. Closes gh-30326
This commit is contained in:
parent
b73f5fcac2
commit
be17c8d85f
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2023 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.
|
||||
|
|
@ -17,6 +17,7 @@
|
|||
package org.springframework.expression;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
|
|
@ -24,12 +25,21 @@ import org.springframework.lang.Nullable;
|
|||
* Expressions are executed in an evaluation context. It is in this context that
|
||||
* references are resolved when encountered during expression evaluation.
|
||||
*
|
||||
* <p>There is a default implementation of this EvaluationContext interface:
|
||||
* {@link org.springframework.expression.spel.support.StandardEvaluationContext}
|
||||
* which can be extended, rather than having to implement everything manually.
|
||||
* <p>There are two default implementations of this interface.
|
||||
* <ul>
|
||||
* <li>{@link org.springframework.expression.spel.support.SimpleEvaluationContext
|
||||
* SimpleEvaluationContext}: a simpler builder-style {@code EvaluationContext}
|
||||
* variant for data-binding purposes, which allows for opting into several SpEL
|
||||
* features as needed.</li>
|
||||
* <li>{@link org.springframework.expression.spel.support.StandardEvaluationContext
|
||||
* StandardEvaluationContext}: a powerful and highly configurable {@code EvaluationContext}
|
||||
* implementation, which can be extended, rather than having to implement everything
|
||||
* manually.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @author Juergen Hoeller
|
||||
* @author Sam Brannen
|
||||
* @since 3.0
|
||||
*/
|
||||
public interface EvaluationContext {
|
||||
|
|
@ -85,7 +95,30 @@ public interface EvaluationContext {
|
|||
OperatorOverloader getOperatorOverloader();
|
||||
|
||||
/**
|
||||
* Set a named variable within this evaluation context to a specified value.
|
||||
* Assign the value created by the specified {@link Supplier} to a named variable
|
||||
* within this evaluation context.
|
||||
* <p>In contrast to {@link #setVariable(String, Object)}, this method should only
|
||||
* be invoked to support the assignment operator ({@code =}) within an expression.
|
||||
* <p>By default, this method delegates to {@code setVariable(String, Object)},
|
||||
* providing the value created by the {@code valueSupplier}. Concrete implementations
|
||||
* may override this <em>default</em> method to provide different semantics.
|
||||
* @param name the name of the variable to assign
|
||||
* @param valueSupplier the supplier of the value to be assigned to the variable
|
||||
* @return a {@link TypedValue} wrapping the assigned value
|
||||
* @since 5.2.24
|
||||
*/
|
||||
default TypedValue assignVariable(String name, Supplier<TypedValue> valueSupplier) {
|
||||
TypedValue typedValue = valueSupplier.get();
|
||||
setVariable(name, typedValue.getValue());
|
||||
return typedValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a named variable in this evaluation context to a specified value.
|
||||
* <p>In contrast to {@link #assignVariable(String, Supplier)}, this method
|
||||
* should only be invoked programmatically when interacting directly with the
|
||||
* {@code EvaluationContext} — for example, to provide initial
|
||||
* configuration for the context.
|
||||
* @param name the name of the variable to set
|
||||
* @param value the value to be placed in the variable
|
||||
*/
|
||||
|
|
@ -93,7 +126,7 @@ public interface EvaluationContext {
|
|||
|
||||
/**
|
||||
* Look up a named variable within this evaluation context.
|
||||
* @param name variable to lookup
|
||||
* @param name the name of the variable to look up
|
||||
* @return the value of the variable, or {@code null} if not found
|
||||
*/
|
||||
@Nullable
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2023 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.
|
||||
|
|
@ -23,6 +23,7 @@ import java.util.HashMap;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
|
|
@ -38,18 +39,19 @@ import org.springframework.util.Assert;
|
|||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
/**
|
||||
* An ExpressionState is for maintaining per-expression-evaluation state, any changes to
|
||||
* it are not seen by other expressions but it gives a place to hold local variables and
|
||||
* ExpressionState is for maintaining per-expression-evaluation state: any changes to
|
||||
* it are not seen by other expressions, but it gives a place to hold local variables and
|
||||
* for component expressions in a compound expression to communicate state. This is in
|
||||
* contrast to the EvaluationContext, which is shared amongst expression evaluations, and
|
||||
* any changes to it will be seen by other expressions or any code that chooses to ask
|
||||
* questions of the context.
|
||||
*
|
||||
* <p>It also acts as a place for to define common utility routines that the various AST
|
||||
* <p>It also acts as a place to define common utility routines that the various AST
|
||||
* nodes might need.
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @author Juergen Hoeller
|
||||
* @author Sam Brannen
|
||||
* @since 3.0
|
||||
*/
|
||||
public class ExpressionState {
|
||||
|
|
@ -138,6 +140,29 @@ public class ExpressionState {
|
|||
return this.scopeRootObjects.element();
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign the value created by the specified {@link Supplier} to a named variable
|
||||
* within the evaluation context.
|
||||
* <p>In contrast to {@link #setVariable(String, Object)}, this method should
|
||||
* only be invoked to support assignment within an expression.
|
||||
* @param name the name of the variable to assign
|
||||
* @param valueSupplier the supplier of the value to be assigned to the variable
|
||||
* @return a {@link TypedValue} wrapping the assigned value
|
||||
* @since 5.2.24
|
||||
* @see EvaluationContext#assignVariable(String, Supplier)
|
||||
*/
|
||||
public TypedValue assignVariable(String name, Supplier<TypedValue> valueSupplier) {
|
||||
return this.relatedContext.assignVariable(name, valueSupplier);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a named variable in the evaluation context to a specified value.
|
||||
* <p>In contrast to {@link #assignVariable(String, Supplier)}, this method
|
||||
* should only be invoked programmatically.
|
||||
* @param name the name of the variable to set
|
||||
* @param value the value to be placed in the variable
|
||||
* @see EvaluationContext#setVariable(String, Object)
|
||||
*/
|
||||
public void setVariable(String name, @Nullable Object value) {
|
||||
this.relatedContext.setVariable(name, value);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -280,7 +280,11 @@ public enum SpelMessage {
|
|||
|
||||
/** @since 5.2.24 */
|
||||
MAX_EXPRESSION_LENGTH_EXCEEDED(Kind.ERROR, 1079,
|
||||
"SpEL expression is too long, exceeding the threshold of ''{0}'' characters");
|
||||
"SpEL expression is too long, exceeding the threshold of ''{0}'' characters"),
|
||||
|
||||
/** @since 5.2.24 */
|
||||
VARIABLE_ASSIGNMENT_NOT_SUPPORTED(Kind.ERROR, 1080,
|
||||
"Assignment to variable ''{0}'' is not supported");
|
||||
|
||||
|
||||
private final Kind kind;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2023 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.
|
||||
|
|
@ -27,6 +27,7 @@ import org.springframework.expression.spel.ExpressionState;
|
|||
* <p>Example: 'someNumberProperty=42'
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @author Sam Brannen
|
||||
* @since 3.0
|
||||
*/
|
||||
public class Assign extends SpelNodeImpl {
|
||||
|
|
@ -38,9 +39,7 @@ public class Assign extends SpelNodeImpl {
|
|||
|
||||
@Override
|
||||
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
TypedValue newValue = this.children[1].getValueInternal(state);
|
||||
getChild(0).setValue(state, newValue.getValue());
|
||||
return newValue;
|
||||
return this.children[0].setValueInternal(state, () -> this.children[1].getValueInternal(state));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2023 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.
|
||||
|
|
@ -17,6 +17,7 @@
|
|||
package org.springframework.expression.spel.ast;
|
||||
|
||||
import java.util.StringJoiner;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.springframework.asm.MethodVisitor;
|
||||
import org.springframework.expression.EvaluationException;
|
||||
|
|
@ -24,13 +25,13 @@ 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.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Represents a DOT separated expression sequence, such as
|
||||
* {@code 'property1.property2.methodOne()'}.
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @author Sam Brannen
|
||||
* @since 3.0
|
||||
*/
|
||||
public class CompoundExpression extends SpelNodeImpl {
|
||||
|
|
@ -95,8 +96,12 @@ public class CompoundExpression extends SpelNodeImpl {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void setValue(ExpressionState state, @Nullable Object value) throws EvaluationException {
|
||||
getValueRef(state).setValue(value);
|
||||
public TypedValue setValueInternal(ExpressionState state, Supplier<TypedValue> valueSupplier)
|
||||
throws EvaluationException {
|
||||
|
||||
TypedValue typedValue = valueSupplier.get();
|
||||
getValueRef(state).setValue(typedValue.getValue());
|
||||
return typedValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2023 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.
|
||||
|
|
@ -25,6 +25,7 @@ import java.util.Collection;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.StringJoiner;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.springframework.asm.MethodVisitor;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
|
|
@ -45,7 +46,7 @@ import org.springframework.util.ReflectionUtils;
|
|||
|
||||
/**
|
||||
* An Indexer can index into some proceeding structure to access a particular piece of it.
|
||||
* Supported structures are: strings / collections (lists/sets) / arrays.
|
||||
* <p>Supported structures are: strings / collections (lists/sets) / arrays.
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @author Phillip Webb
|
||||
|
|
@ -103,8 +104,12 @@ public class Indexer extends SpelNodeImpl {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void setValue(ExpressionState state, @Nullable Object newValue) throws EvaluationException {
|
||||
getValueRef(state).setValue(newValue);
|
||||
public TypedValue setValueInternal(ExpressionState state, Supplier<TypedValue> valueSupplier)
|
||||
throws EvaluationException {
|
||||
|
||||
TypedValue typedValue = valueSupplier.get();
|
||||
getValueRef(state).setValue(typedValue.getValue());
|
||||
return typedValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import java.util.ArrayList;
|
|||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.springframework.asm.Label;
|
||||
import org.springframework.asm.MethodVisitor;
|
||||
|
|
@ -147,8 +148,12 @@ public class PropertyOrFieldReference extends SpelNodeImpl {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void setValue(ExpressionState state, @Nullable Object newValue) throws EvaluationException {
|
||||
writeProperty(state.getActiveContextObject(), state.getEvaluationContext(), this.name, newValue);
|
||||
public TypedValue setValueInternal(ExpressionState state, Supplier<TypedValue> valueSupplier)
|
||||
throws EvaluationException {
|
||||
|
||||
TypedValue typedValue = valueSupplier.get();
|
||||
writeProperty(state.getActiveContextObject(), state.getEvaluationContext(), this.name, typedValue.getValue());
|
||||
return typedValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2023 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.
|
||||
|
|
@ -19,6 +19,7 @@ package org.springframework.expression.spel.ast;
|
|||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Member;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.springframework.asm.MethodVisitor;
|
||||
import org.springframework.asm.Opcodes;
|
||||
|
|
@ -40,6 +41,7 @@ import org.springframework.util.ObjectUtils;
|
|||
*
|
||||
* @author Andy Clement
|
||||
* @author Juergen Hoeller
|
||||
* @author Sam Brannen
|
||||
* @since 3.0
|
||||
*/
|
||||
public abstract class SpelNodeImpl implements SpelNode, Opcodes {
|
||||
|
|
@ -64,7 +66,7 @@ public abstract class SpelNodeImpl implements SpelNode, Opcodes {
|
|||
* <p>The descriptor is like the bytecode form but is slightly easier to work with.
|
||||
* It does not include the trailing semicolon (for non array reference types).
|
||||
* Some examples: Ljava/lang/String, I, [I
|
||||
*/
|
||||
*/
|
||||
@Nullable
|
||||
protected volatile String exitTypeDescriptor;
|
||||
|
||||
|
|
@ -83,8 +85,8 @@ public abstract class SpelNodeImpl implements SpelNode, Opcodes {
|
|||
|
||||
|
||||
/**
|
||||
* Return {@code true} if the next child is one of the specified classes.
|
||||
*/
|
||||
* Return {@code true} if the next child is one of the specified classes.
|
||||
*/
|
||||
protected boolean nextChildIs(Class<?>... classes) {
|
||||
if (this.parent != null) {
|
||||
SpelNodeImpl[] peers = this.parent.children;
|
||||
|
|
@ -125,6 +127,28 @@ public abstract class SpelNodeImpl implements SpelNode, Opcodes {
|
|||
|
||||
@Override
|
||||
public void setValue(ExpressionState expressionState, @Nullable Object newValue) throws EvaluationException {
|
||||
setValueInternal(expressionState, () -> new TypedValue(newValue));
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate the expression to a node and then set the new value created by the
|
||||
* specified {@link Supplier} on that node.
|
||||
* <p>For example, if the expression evaluates to a property reference, then the
|
||||
* property will be set to the new value.
|
||||
* <p>Favor this method over {@link #setValue(ExpressionState, Object)} when
|
||||
* the value should be lazily computed.
|
||||
* <p>By default, this method throws a {@link SpelEvaluationException},
|
||||
* effectively disabling this feature. Subclasses may override this method to
|
||||
* provide an actual implementation.
|
||||
* @param expressionState the current expression state (includes the context)
|
||||
* @param valueSupplier a supplier of the new value
|
||||
* @throws EvaluationException if any problem occurs evaluating the expression or
|
||||
* setting the new value
|
||||
* @since 5.2.24
|
||||
*/
|
||||
public TypedValue setValueInternal(ExpressionState expressionState, Supplier<TypedValue> valueSupplier)
|
||||
throws EvaluationException {
|
||||
|
||||
throw new SpelEvaluationException(getStartPosition(), SpelMessage.SETVALUE_NOT_SUPPORTED, getClass());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2023 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.
|
||||
|
|
@ -17,9 +17,11 @@
|
|||
package org.springframework.expression.spel.ast;
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.springframework.asm.MethodVisitor;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.EvaluationException;
|
||||
import org.springframework.expression.TypedValue;
|
||||
import org.springframework.expression.spel.CodeFlow;
|
||||
import org.springframework.expression.spel.ExpressionState;
|
||||
|
|
@ -27,10 +29,11 @@ import org.springframework.expression.spel.SpelEvaluationException;
|
|||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Represents a variable reference, eg. #someVar. Note this is different to a *local*
|
||||
* variable like $someVar
|
||||
* Represents a variable reference — for example, {@code #someVar}. Note
|
||||
* that this is different than a <em>local</em> variable like {@code $someVar}.
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @author Sam Brannen
|
||||
* @since 3.0
|
||||
*/
|
||||
public class VariableReference extends SpelNodeImpl {
|
||||
|
|
@ -53,14 +56,14 @@ public class VariableReference extends SpelNodeImpl {
|
|||
@Override
|
||||
public ValueRef getValueRef(ExpressionState state) throws SpelEvaluationException {
|
||||
if (this.name.equals(THIS)) {
|
||||
return new ValueRef.TypedValueHolderValueRef(state.getActiveContextObject(),this);
|
||||
return new ValueRef.TypedValueHolderValueRef(state.getActiveContextObject(), this);
|
||||
}
|
||||
if (this.name.equals(ROOT)) {
|
||||
return new ValueRef.TypedValueHolderValueRef(state.getRootContextObject(),this);
|
||||
return new ValueRef.TypedValueHolderValueRef(state.getRootContextObject(), this);
|
||||
}
|
||||
TypedValue result = state.lookupVariable(this.name);
|
||||
// a null value will mean either the value was null or the variable was not found
|
||||
return new VariableRef(this.name,result,state.getEvaluationContext());
|
||||
return new VariableRef(this.name, result, state.getEvaluationContext());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -90,8 +93,10 @@ public class VariableReference extends SpelNodeImpl {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void setValue(ExpressionState state, @Nullable Object value) throws SpelEvaluationException {
|
||||
state.setVariable(this.name, value);
|
||||
public TypedValue setValueInternal(ExpressionState state, Supplier<TypedValue> valueSupplier)
|
||||
throws EvaluationException {
|
||||
|
||||
return state.assignVariable(this.name, valueSupplier);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2023 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.
|
||||
|
|
@ -21,6 +21,7 @@ import java.util.Collections;
|
|||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
|
|
@ -78,6 +79,7 @@ import org.springframework.lang.Nullable;
|
|||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @author Juergen Hoeller
|
||||
* @author Sam Brannen
|
||||
* @since 4.3.15
|
||||
* @see #forPropertyAccessors
|
||||
* @see #forReadOnlyDataBinding()
|
||||
|
|
@ -200,6 +202,17 @@ public final class SimpleEvaluationContext implements EvaluationContext {
|
|||
return this.operatorOverloader;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code SimpleEvaluationContext} does not support variable assignment within
|
||||
* expressions.
|
||||
* @throws SpelEvaluationException with {@link SpelMessage#VARIABLE_ASSIGNMENT_NOT_SUPPORTED}
|
||||
* @since 5.2.24
|
||||
*/
|
||||
@Override
|
||||
public TypedValue assignVariable(String name, Supplier<TypedValue> valueSupplier) {
|
||||
throw new SpelEvaluationException(SpelMessage.VARIABLE_ASSIGNMENT_NOT_SUPPORTED, "#" + name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVariable(String name, @Nullable Object value) {
|
||||
this.variables.put(name, value);
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@ import java.util.Map;
|
|||
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.CsvSource;
|
||||
|
||||
import org.springframework.expression.AccessException;
|
||||
import org.springframework.expression.BeanResolver;
|
||||
|
|
@ -36,6 +38,7 @@ import org.springframework.expression.MethodFilter;
|
|||
import org.springframework.expression.ParseException;
|
||||
import org.springframework.expression.spel.standard.SpelExpression;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.expression.spel.support.SimpleEvaluationContext;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
import org.springframework.expression.spel.support.StandardTypeLocator;
|
||||
import org.springframework.expression.spel.testresources.TestPerson;
|
||||
|
|
@ -149,8 +152,24 @@ class EvaluationTests extends AbstractExpressionTests {
|
|||
|
||||
// assignment
|
||||
@Test
|
||||
void assignmentToVariables() {
|
||||
evaluate("#var1='value1'", "value1", String.class);
|
||||
void assignmentToVariableWithStandardEvaluationContext() {
|
||||
evaluate("#var1 = 'value1'", "value1", String.class);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@CsvSource(quoteCharacter = '"', delimiterString = "->", textBlock = """
|
||||
"#var1 = 'value1'" -> #var1
|
||||
"true ? #myVar = 4 : 0" -> #myVar
|
||||
""")
|
||||
void assignmentToVariableWithSimpleEvaluationContext(String expression, String varName) {
|
||||
EvaluationContext context = SimpleEvaluationContext.forReadWriteDataBinding().build();
|
||||
Expression expr = parser.parseExpression(expression);
|
||||
assertThatExceptionOfType(SpelEvaluationException.class)
|
||||
.isThrownBy(() -> expr.getValue(context))
|
||||
.satisfies(ex -> {
|
||||
assertThat(ex.getMessageCode()).isEqualTo(SpelMessage.VARIABLE_ASSIGNMENT_NOT_SUPPORTED);
|
||||
assertThat(ex.getInserts()).as("inserts").containsExactly(varName);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
|||
Loading…
Reference in New Issue