diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ExpressionState.java b/spring-expression/src/main/java/org/springframework/expression/spel/ExpressionState.java
index 85c1727c5c0..bf4866660a4 100644
--- a/spring-expression/src/main/java/org/springframework/expression/spel/ExpressionState.java
+++ b/spring-expression/src/main/java/org/springframework/expression/spel/ExpressionState.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2013 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.
@@ -30,14 +30,18 @@ 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 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.
+ * 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
+ * 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.
*
- *
It also acts as a place for to define common utility routines that the various Ast nodes might need.
+ *
It also acts as a place for to define common utility routines that the various AST
+ * nodes might need.
*
* @author Andy Clement
* @since 3.0
@@ -46,35 +50,33 @@ public class ExpressionState {
private final EvaluationContext relatedContext;
+ private final TypedValue rootObject;
+
+ private final SpelParserConfiguration configuration;
+
private Stack variableScopes;
private Stack contextObjects;
- private final TypedValue rootObject;
-
- private SpelParserConfiguration configuration;
-
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;
}
@@ -90,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();
+ if (this.contextObjects == null) {
+ this.contextObjects = new Stack();
}
this.contextObjects.push(obj);
}
public void popActiveContextObject() {
- if (this.contextObjects==null) {
- this.contextObjects = new Stack();
+ if (this.contextObjects == null) {
+ this.contextObjects = new Stack();
}
this.contextObjects.pop();
}
@@ -138,7 +139,8 @@ public class ExpressionState {
}
public Object convertValue(Object value, TypeDescriptor targetTypeDescriptor) throws EvaluationException {
- return this.relatedContext.getTypeConverter().convertValue(value, TypeDescriptor.forObject(value), targetTypeDescriptor);
+ return this.relatedContext.getTypeConverter().convertValue(value,
+ TypeDescriptor.forObject(value), targetTypeDescriptor);
}
public TypeConverter getTypeConverter() {
@@ -151,9 +153,8 @@ public class ExpressionState {
}
/*
- * A new scope is entered when a function is invoked
+ * A new scope is entered when a function is invoked.
*/
-
public void enterScope(Map argMap) {
ensureVariableScopesInitialized();
this.variableScopes.push(new VariableScope(argMap));
@@ -192,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);
}
}
@@ -210,16 +211,20 @@ public class ExpressionState {
return this.configuration;
}
+
/**
- * 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 vars = new HashMap();
- public VariableScope() { }
+ public VariableScope() {
+ }
public VariableScope(Map arguments) {
if (arguments != null) {
diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/SpelParserConfiguration.java b/spring-expression/src/main/java/org/springframework/expression/spel/SpelParserConfiguration.java
index ccadb93061b..8c26f883b28 100644
--- a/spring-expression/src/main/java/org/springframework/expression/spel/SpelParserConfiguration.java
+++ b/spring-expression/src/main/java/org/springframework/expression/spel/SpelParserConfiguration.java
@@ -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;
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 99e79ff5048..e1b8c34a3fe 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
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2013 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.
@@ -67,47 +67,20 @@ public class PropertyOrFieldReference extends SpelNodeImpl {
}
- static class AccessorLValue implements ValueRef {
- private PropertyOrFieldReference ref;
- private TypedValue contextObject;
- private EvaluationContext eContext;
- private boolean isAutoGrowNullReferences;
-
- public AccessorLValue(
- PropertyOrFieldReference propertyOrFieldReference,
- TypedValue activeContextObject,
- EvaluationContext evaluationContext, boolean isAutoGrowNullReferences) {
- this.ref = propertyOrFieldReference;
- this.contextObject = activeContextObject;
- this.eContext =evaluationContext;
- this.isAutoGrowNullReferences = isAutoGrowNullReferences;
- }
-
- public TypedValue getValue() {
- return ref.getValueInternal(contextObject,eContext,isAutoGrowNullReferences);
- }
-
- public void setValue(Object newValue) {
- ref.writeProperty(contextObject,eContext, ref.name, newValue);
- }
-
- 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);
@@ -139,7 +112,7 @@ public class PropertyOrFieldReference extends SpelNodeImpl {
try {
if (isWritableProperty(this.name,contextObject,eContext)) {
Map,?> newMap = HashMap.class.newInstance();
- writeProperty(contextObject, eContext, name, newMap);
+ writeProperty(contextObject, eContext, this.name, newMap);
result = readProperty(contextObject, eContext, this.name);
}
}
@@ -158,7 +131,7 @@ public class PropertyOrFieldReference extends SpelNodeImpl {
try {
if (isWritableProperty(this.name,contextObject,eContext)) {
Object newObject = result.getTypeDescriptor().getType().newInstance();
- writeProperty(contextObject, eContext, name, newObject);
+ writeProperty(contextObject, eContext, this.name, newObject);
result = readProperty(contextObject, eContext, this.name);
}
}
@@ -192,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;
}
@@ -249,8 +219,7 @@ public class PropertyOrFieldReference extends SpelNodeImpl {
}
private void writeProperty(TypedValue contextObject, EvaluationContext eContext, String name, Object newValue) throws SpelEvaluationException {
-
- if (contextObject.getValue() == null && nullSafe) {
+ if (contextObject.getValue() == null && this.nullSafe) {
return;
}
@@ -353,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;
+ }
+ }
+
}