提交 4aab3153 编写于 作者: J Juergen Hoeller

ExpressionState.getConfiguration() should never return null

Issue: SPR-11031
上级 08517667
......@@ -30,6 +30,7 @@ import org.springframework.expression.PropertyAccessor;
import org.springframework.expression.TypeComparator;
import org.springframework.expression.TypeConverter;
import org.springframework.expression.TypedValue;
import org.springframework.util.Assert;
/**
* An ExpressionState is for maintaining per-expression-evaluation state, any changes to
......@@ -49,35 +50,33 @@ public class ExpressionState {
private final EvaluationContext relatedContext;
private Stack<VariableScope> variableScopes;
private final TypedValue rootObject;
private Stack<TypedValue> contextObjects;
private final SpelParserConfiguration configuration;
private final TypedValue rootObject;
private Stack<VariableScope> variableScopes;
private SpelParserConfiguration configuration;
private Stack<TypedValue> contextObjects;
public ExpressionState(EvaluationContext context) {
this.relatedContext = context;
this.rootObject = context.getRootObject();
this(context, context.getRootObject(), new SpelParserConfiguration(false, false));
}
public ExpressionState(EvaluationContext context, SpelParserConfiguration configuration) {
this.relatedContext = context;
this.configuration = configuration;
this.rootObject = context.getRootObject();
this(context, context.getRootObject(), configuration);
}
public ExpressionState(EvaluationContext context, TypedValue rootObject) {
this.relatedContext = context;
this.rootObject = rootObject;
this(context, rootObject, new SpelParserConfiguration(false, false));
}
public ExpressionState(EvaluationContext context, TypedValue rootObject, SpelParserConfiguration configuration) {
Assert.notNull(context, "EvaluationContext must not be null");
Assert.notNull(configuration, "SpelParserConfiguration must not be null");
this.relatedContext = context;
this.configuration = configuration;
this.rootObject = rootObject;
this.configuration = configuration;
}
......@@ -93,23 +92,22 @@ public class ExpressionState {
* The active context object is what unqualified references to properties/etc are resolved against.
*/
public TypedValue getActiveContextObject() {
if (this.contextObjects==null || this.contextObjects.isEmpty()) {
if (this.contextObjects == null || this.contextObjects.isEmpty()) {
return this.rootObject;
}
return this.contextObjects.peek();
}
public void pushActiveContextObject(TypedValue obj) {
if (this.contextObjects==null) {
this.contextObjects = new Stack<TypedValue>();
if (this.contextObjects == null) {
this.contextObjects = new Stack<TypedValue>();
}
this.contextObjects.push(obj);
}
public void popActiveContextObject() {
if (this.contextObjects==null) {
this.contextObjects = new Stack<TypedValue>();
if (this.contextObjects == null) {
this.contextObjects = new Stack<TypedValue>();
}
this.contextObjects.pop();
}
......@@ -151,14 +149,12 @@ public class ExpressionState {
public Object convertValue(TypedValue value, TypeDescriptor targetTypeDescriptor) throws EvaluationException {
Object val = value.getValue();
return this.relatedContext.getTypeConverter().convertValue(val,
TypeDescriptor.forObject(val), targetTypeDescriptor);
return this.relatedContext.getTypeConverter().convertValue(val, TypeDescriptor.forObject(val), targetTypeDescriptor);
}
/*
* A new scope is entered when a function is invoked
* A new scope is entered when a function is invoked.
*/
public void enterScope(Map<String, Object> argMap) {
ensureVariableScopesInitialized();
this.variableScopes.push(new VariableScope(argMap));
......@@ -197,8 +193,8 @@ public class ExpressionState {
return new TypedValue(returnValue);
}
else {
String leftType = (left==null?"null":left.getClass().getName());
String rightType = (right==null?"null":right.getClass().getName());
String leftType = (left == null ? "null" : left.getClass().getName());
String rightType = (right == null? "null" : right.getClass().getName());
throw new SpelEvaluationException(SpelMessage.OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES, op, leftType, rightType);
}
}
......@@ -217,16 +213,18 @@ public class ExpressionState {
/**
* A new scope is entered when a function is called and it is used to hold the parameters to the function call. If the names
* of the parameters clash with those in a higher level scope, those in the higher level scope will not be accessible whilst
* the function is executing. When the function returns the scope is exited.
* A new scope is entered when a function is called and it is used to hold the
* parameters to the function call. If the names of the parameters clash with
* those in a higher level scope, those in the higher level scope will not be
* accessible whilst the function is executing. When the function returns,
* the scope is exited.
*/
private static class VariableScope {
private final Map<String, Object> vars = new HashMap<String, Object>();
public VariableScope() { }
public VariableScope() {
}
public VariableScope(Map<String, Object> arguments) {
if (arguments != null) {
......@@ -238,7 +236,6 @@ public class ExpressionState {
this.vars.put(name,value);
}
public Object lookupVariable(String name) {
return this.vars.get(name);
}
......
......@@ -49,8 +49,7 @@ public class SpelParserConfiguration {
* @param autoGrowCollections if collections should automatically grow
* @param maximumAutoGrowSize the maximum size that the collection can auto grow
*/
public SpelParserConfiguration(boolean autoGrowNullReferences,
boolean autoGrowCollections, int maximumAutoGrowSize) {
public SpelParserConfiguration(boolean autoGrowNullReferences, boolean autoGrowCollections, int maximumAutoGrowSize) {
this.autoGrowNullReferences = autoGrowNullReferences;
this.autoGrowCollections = autoGrowCollections;
this.maximumAutoGrowSize = maximumAutoGrowSize;
......
......@@ -67,50 +67,20 @@ public class PropertyOrFieldReference extends SpelNodeImpl {
}
static class AccessorLValue implements ValueRef {
private final PropertyOrFieldReference ref;
private final TypedValue contextObject;
private final EvaluationContext eContext;
private final boolean isAutoGrowNullReferences;
public AccessorLValue(
PropertyOrFieldReference propertyOrFieldReference,
TypedValue activeContextObject,
EvaluationContext evaluationContext, boolean isAutoGrowNullReferences) {
this.ref = propertyOrFieldReference;
this.contextObject = activeContextObject;
this.eContext =evaluationContext;
this.isAutoGrowNullReferences = isAutoGrowNullReferences;
}
@Override
public TypedValue getValue() {
return this.ref.getValueInternal(this.contextObject,this.eContext,this.isAutoGrowNullReferences);
}
@Override
public void setValue(Object newValue) {
this.ref.writeProperty(this.contextObject,this.eContext, this.ref.name, newValue);
}
@Override
public boolean isWritable() {
return true;
}
}
@Override
public ValueRef getValueRef(ExpressionState state) throws EvaluationException {
return new AccessorLValue(this,state.getActiveContextObject(),state.getEvaluationContext(),state.getConfiguration().isAutoGrowNullReferences());
return new AccessorLValue(this, state.getActiveContextObject(), state.getEvaluationContext(),
state.getConfiguration().isAutoGrowNullReferences());
}
@Override
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
return getValueInternal(state.getActiveContextObject(), state.getEvaluationContext(), state.getConfiguration().isAutoGrowNullReferences());
return getValueInternal(state.getActiveContextObject(), state.getEvaluationContext(),
state.getConfiguration().isAutoGrowNullReferences());
}
private TypedValue getValueInternal(TypedValue contextObject, EvaluationContext eContext, boolean isAutoGrowNullReferences) throws EvaluationException {
private TypedValue getValueInternal(TypedValue contextObject, EvaluationContext eContext,
boolean isAutoGrowNullReferences) throws EvaluationException {
TypedValue result = readProperty(contextObject, eContext, this.name);
......@@ -195,14 +165,11 @@ public class PropertyOrFieldReference extends SpelNodeImpl {
/**
* Attempt to read the named property from the current context object.
* @param state the evaluation state
* @param name the name of the property
* @return the value of the property
* @throws SpelEvaluationException if any problem accessing the property or it cannot be found
*/
private TypedValue readProperty(TypedValue contextObject, EvaluationContext eContext, String name) throws EvaluationException {
Object targetObject = contextObject.getValue();
if (targetObject == null && this.nullSafe) {
return TypedValue.NULL;
}
......@@ -252,7 +219,6 @@ public class PropertyOrFieldReference extends SpelNodeImpl {
}
private void writeProperty(TypedValue contextObject, EvaluationContext eContext, String name, Object newValue) throws SpelEvaluationException {
if (contextObject.getValue() == null && this.nullSafe) {
return;
}
......@@ -356,4 +322,39 @@ public class PropertyOrFieldReference extends SpelNodeImpl {
return resolvers;
}
private static class AccessorLValue implements ValueRef {
private final PropertyOrFieldReference ref;
private final TypedValue contextObject;
private final EvaluationContext eContext;
private final boolean autoGrowNullReferences;
public AccessorLValue(PropertyOrFieldReference propertyOrFieldReference, TypedValue activeContextObject,
EvaluationContext evaluationContext, boolean autoGrowNullReferences) {
this.ref = propertyOrFieldReference;
this.contextObject = activeContextObject;
this.eContext = evaluationContext;
this.autoGrowNullReferences = autoGrowNullReferences;
}
@Override
public TypedValue getValue() {
return this.ref.getValueInternal(this.contextObject, this.eContext, this.autoGrowNullReferences);
}
@Override
public void setValue(Object newValue) {
this.ref.writeProperty(this.contextObject, this.eContext, this.ref.name, newValue);
}
@Override
public boolean isWritable() {
return true;
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册