expression parser improvements from andy's feedback
This commit is contained in:
@@ -60,6 +60,6 @@ public class TextToExpression extends AbstractConverter {
|
||||
|
||||
protected Object doConvert(Object source, Class targetClass, ConversionContext context) throws Exception {
|
||||
String expressionString = (String) source;
|
||||
return expressionParser.parseExpression(expressionString, Object.class, Object.class, null);
|
||||
return expressionParser.parseExpression(expressionString, null);
|
||||
}
|
||||
}
|
||||
@@ -18,44 +18,37 @@ package org.springframework.binding.expression;
|
||||
import org.springframework.core.style.ToStringCreator;
|
||||
|
||||
/**
|
||||
* A simple holder for information about an evaluation attempt.
|
||||
* A simple holder for information about an expression evaluation attempt.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public class EvaluationAttempt {
|
||||
|
||||
/**
|
||||
* The expression that attempted to evaluate.
|
||||
*/
|
||||
private Expression expression;
|
||||
|
||||
/**
|
||||
* The target object being evaluated.
|
||||
*/
|
||||
private Object target;
|
||||
private Object context;
|
||||
|
||||
/**
|
||||
* Create an evaluation attempt.
|
||||
* @param expression the expression that failed to evaluate
|
||||
* @param target the target of the expression
|
||||
* @param context the context of the expression evaluation
|
||||
*/
|
||||
public EvaluationAttempt(Expression expression, Object target) {
|
||||
public EvaluationAttempt(Expression expression, Object context) {
|
||||
this.expression = expression;
|
||||
this.target = target;
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the expression that attempted to evaluate.
|
||||
* Returns the expression that attempted an evaluation.
|
||||
*/
|
||||
public Expression getExpression() {
|
||||
return expression;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the target object upon which evaluation was attempted.
|
||||
* Returns the context object in which expression evaluation was attempted.
|
||||
*/
|
||||
public Object getTarget() {
|
||||
return target;
|
||||
public Object getContext() {
|
||||
return context;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
@@ -63,6 +56,6 @@ public class EvaluationAttempt {
|
||||
}
|
||||
|
||||
protected ToStringCreator createToString(ToStringCreator creator) {
|
||||
return creator.append("expression", expression).append("target", target);
|
||||
return creator.append("expression", expression).append("context", context);
|
||||
}
|
||||
}
|
||||
@@ -36,7 +36,7 @@ public class EvaluationException extends NestedRuntimeException {
|
||||
*/
|
||||
public EvaluationException(EvaluationAttempt evaluationAttempt, Throwable cause) {
|
||||
super("Expression " + evaluationAttempt
|
||||
+ " failed - make sure the expression is evaluatable on the target object", cause);
|
||||
+ " failed - make sure the expression is evaluatable in the context provided", cause);
|
||||
this.evaluationAttempt = evaluationAttempt;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,19 +24,18 @@ package org.springframework.binding.expression;
|
||||
public interface Expression {
|
||||
|
||||
/**
|
||||
* Evaluate the expression encapsulated by this evaluator against the provided target object and return the result
|
||||
* of the evaluation.
|
||||
* @param target the target of the expression
|
||||
* Evaluate this expression in the provided context and return the result of evaluation.
|
||||
* @param context the context to evaluate this expression in
|
||||
* @return the evaluation result
|
||||
* @throws EvaluationException an exception occured during evaluation
|
||||
*/
|
||||
public Object getValue(Object target) throws EvaluationException;
|
||||
public Object getValue(Object context) throws EvaluationException;
|
||||
|
||||
/**
|
||||
* Evaluate this expression against the target object to set its value to the value provided.
|
||||
* @param target the target object
|
||||
* Set this expression in the provided context to the value provided.
|
||||
* @param context the context to apply this value to
|
||||
* @param value the new value to be set
|
||||
* @throws EvaluationException an exception occurred during evaluation
|
||||
*/
|
||||
public void setValue(Object target, Object value) throws EvaluationException;
|
||||
public void setValue(Object context, Object value) throws EvaluationException;
|
||||
}
|
||||
@@ -24,30 +24,20 @@ package org.springframework.binding.expression;
|
||||
public interface ExpressionParser {
|
||||
|
||||
/**
|
||||
* Is the provided expression string an "eval" expression: meaning an expression that validates to a dynamic value,
|
||||
* and not a literal expression? "Eval" expressions are normally enclosed in delimiters like #{}, where literal
|
||||
* expressions are not delimited.
|
||||
*
|
||||
* TODO - candidate for removal in a future milestone: is this really needed?
|
||||
* Is the provided string an explicitly delimited expression this parser knows how to parse? For example, this
|
||||
* method might return true if the string provided is enclosed in ${}.
|
||||
* @param string the string
|
||||
* @return true if the expression is an eval expression string, false otherwise.
|
||||
* @return true if the string is a delimited expression, false otherwise.
|
||||
*/
|
||||
public boolean isEvalExpressionString(String string);
|
||||
|
||||
public boolean isDelimitedExpression(String string);
|
||||
|
||||
/**
|
||||
* Parse the provided expression string, returning an expression evaluator capable of evaluating it.
|
||||
* @param expressionString the parseable expression string; cannot be null
|
||||
* @param expressionTargetType the class of target object this expression can successfully evaluate; for example,
|
||||
* <code>Map.class</code> for an expression that is expected to evaluate against Maps.
|
||||
* @param expectedEvaluationResultType the class of object this expression is expected to return or set: for
|
||||
* example, <code>Boolean.class</code> for an expression that is expected to get or set a boolean value. Typically
|
||||
* used to facilitate type conversion by the expression evaluator; for example, if a evaluated expression equates to
|
||||
* a String value 'true', with an expected Boolean result the string value could be converted to a typed Boolean
|
||||
* value (required). If the type of the evaluation result cannot be determined, use Object.class.
|
||||
* @param expressionVariables variables providing aliases for this expression during evaluation (optional).
|
||||
* @param expressionString the parseable expression string; cannot be null (required)
|
||||
* @param context a context used to set attributes that influence expression parsing routine (optional)
|
||||
* @return the evaluator for the parsed expression
|
||||
* @throws ParserException an exception occurred during parsing
|
||||
*/
|
||||
public Expression parseExpression(String expressionString, Class expressionTargetType,
|
||||
Class expectedEvaluationResultType, ExpressionVariable[] expressionVariables) throws ParserException;
|
||||
public Expression parseExpression(String expressionString, ParserContext context) throws ParserException;
|
||||
|
||||
}
|
||||
@@ -9,17 +9,15 @@ import org.springframework.util.Assert;
|
||||
public class ExpressionVariable {
|
||||
|
||||
private String name;
|
||||
|
||||
private String value;
|
||||
private Object value;
|
||||
|
||||
/**
|
||||
* Creates a new expression variable
|
||||
* @param name the name of the variable, acting as an convenient alias
|
||||
* @param value the initial value of the variable
|
||||
*/
|
||||
public ExpressionVariable(String name, String value) {
|
||||
public ExpressionVariable(String name, Object value) {
|
||||
Assert.hasText(name, "The expression variable must be named");
|
||||
Assert.hasText(value, "The expression variable value is required");
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
}
|
||||
@@ -36,7 +34,7 @@ public class ExpressionVariable {
|
||||
* Returns the expression that will be evaluated when the variable is referenced by its name in another expression.
|
||||
* @return the expression value.
|
||||
*/
|
||||
public String getValue() {
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package org.springframework.binding.expression;
|
||||
|
||||
/**
|
||||
* Input provided to an expression parser that can influence an expression parsing/compilation routine.
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public interface ParserContext {
|
||||
|
||||
/**
|
||||
* Returns the type of context object the parsed expression will evaluate in. An expression parser may use this
|
||||
* value to install custom variable resolves for that particular type of context.
|
||||
* @return the evaluation context type
|
||||
*/
|
||||
public Class getEvaluationContextType();
|
||||
|
||||
/**
|
||||
* Returns the expected type of object returned from evaluating the parsed expression. An expression parser may use
|
||||
* this value to coerce an raw evaluation result before it is returned.
|
||||
* @return the expected evaluation result type
|
||||
*/
|
||||
public Class getExpectedEvaluationResultType();
|
||||
|
||||
/**
|
||||
* Returns additional expression variables or aliases that can be referenced during expression evaluation. An
|
||||
* expression parser will register these variables for reference during evaluation.
|
||||
*/
|
||||
public ExpressionVariable[] getExpressionVariables();
|
||||
}
|
||||
@@ -32,11 +32,11 @@ public class SetValueAttempt extends EvaluationAttempt {
|
||||
/**
|
||||
* Creates a new set attempt.
|
||||
* @param expression the settable expression
|
||||
* @param target the target of the expression
|
||||
* @param context the target of the expression
|
||||
* @param value the value that was attempted to be set
|
||||
*/
|
||||
public SetValueAttempt(Expression expression, Object target, Object value) {
|
||||
super(expression, target);
|
||||
public SetValueAttempt(Expression expression, Object context, Object value) {
|
||||
super(expression, context);
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
package org.springframework.binding.expression.el;
|
||||
|
||||
import javax.el.ELContext;
|
||||
import javax.el.ELResolver;
|
||||
import javax.el.FunctionMapper;
|
||||
import javax.el.VariableMapper;
|
||||
|
||||
public class DefaultELContext extends ELContext {
|
||||
|
||||
private VariableMapper variableMapper;
|
||||
|
||||
private ELResolver resolver;
|
||||
|
||||
private FunctionMapper functionMapper;
|
||||
|
||||
public DefaultELContext(ELResolver resolver, VariableMapper variableMapper, FunctionMapper functionMapper) {
|
||||
this.resolver = resolver;
|
||||
this.variableMapper = variableMapper;
|
||||
this.functionMapper = functionMapper;
|
||||
}
|
||||
|
||||
public static ELContext createDefaultELContext() {
|
||||
return new DefaultELContext(new DefaultELResolver(null, null), null, null);
|
||||
}
|
||||
|
||||
public ELResolver getELResolver() {
|
||||
return resolver;
|
||||
}
|
||||
|
||||
public VariableMapper getVariableMapper() {
|
||||
return variableMapper;
|
||||
}
|
||||
|
||||
public FunctionMapper getFunctionMapper() {
|
||||
return functionMapper;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package org.springframework.binding.expression.el;
|
||||
|
||||
import javax.el.ELContext;
|
||||
import javax.el.VariableMapper;
|
||||
|
||||
public class DefaultElContextFactory implements ELContextFactory {
|
||||
public ELContext getELContext(Object target, VariableMapper variableMapper) {
|
||||
return new DefaultELContext(new DefaultELResolver(target, null), variableMapper, null);
|
||||
}
|
||||
}
|
||||
@@ -37,21 +37,21 @@ public class ELExpression implements Expression {
|
||||
this.variableMapper = variableMapper;
|
||||
}
|
||||
|
||||
public Object getValue(Object target) throws EvaluationException {
|
||||
ELContext ctx = elContextFactory.getELContext(target, variableMapper);
|
||||
public Object getValue(Object context) throws EvaluationException {
|
||||
ELContext ctx = elContextFactory.getELContext(context, variableMapper);
|
||||
try {
|
||||
return valueExpression.getValue(ctx);
|
||||
} catch (ELException ex) {
|
||||
throw new EvaluationException(new EvaluationAttempt(this, target), ex);
|
||||
throw new EvaluationException(new EvaluationAttempt(this, context), ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void setValue(Object target, Object value) throws EvaluationException {
|
||||
ELContext ctx = elContextFactory.getELContext(target, variableMapper);
|
||||
public void setValue(Object context, Object value) throws EvaluationException {
|
||||
ELContext ctx = elContextFactory.getELContext(context, variableMapper);
|
||||
try {
|
||||
valueExpression.setValue(ctx, value);
|
||||
} catch (ELException ex) {
|
||||
throw new EvaluationException(new EvaluationAttempt(this, target), ex);
|
||||
throw new EvaluationException(new EvaluationAttempt(this, context), ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,18 +14,27 @@ import javax.el.VariableMapper;
|
||||
import org.springframework.binding.expression.Expression;
|
||||
import org.springframework.binding.expression.ExpressionParser;
|
||||
import org.springframework.binding.expression.ExpressionVariable;
|
||||
import org.springframework.binding.expression.ParserContext;
|
||||
import org.springframework.binding.expression.ParserException;
|
||||
import org.springframework.binding.expression.support.NullParserContext;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* An expression parser that parses EL expressions.
|
||||
* @author Jeremy Grelle
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public class ELExpressionParser implements ExpressionParser {
|
||||
|
||||
/**
|
||||
* The expression prefix.
|
||||
*/
|
||||
private static final String EXPRESSION_PREFIX = "#{";
|
||||
private static final String EXPRESSION_PREFIX_IMMEDIATE = "${";
|
||||
|
||||
/**
|
||||
* The expression prefix.
|
||||
*/
|
||||
private static final String EXPRESSION_PREFIX_DEFERRED = "#{";
|
||||
|
||||
/**
|
||||
* The expression suffix.
|
||||
@@ -43,47 +52,63 @@ public class ELExpressionParser implements ExpressionParser {
|
||||
* Creates a new EL expression parser for standalone usage.
|
||||
*/
|
||||
public ELExpressionParser(ExpressionFactory expressionFactory) {
|
||||
this.expressionFactory = expressionFactory;
|
||||
init(expressionFactory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the ELContextFactory for expressions that evaluate the given class of target object.
|
||||
* @param expressionTargetType the expression target class
|
||||
* @param contextFactory the context factory to use for expressions that evaluate those types of targets
|
||||
* Register the ELContextFactory for expressions that evaluate the given class of context object.
|
||||
* @param contextType the expression context class
|
||||
* @param contextFactory the context factory to use for expressions that evaluate those types of contexts
|
||||
*/
|
||||
public void putContextFactory(Class expressionTargetType, ELContextFactory contextFactory) {
|
||||
this.contextFactories.put(expressionTargetType, contextFactory);
|
||||
public void putContextFactory(Class contextType, ELContextFactory contextFactory) {
|
||||
Assert.notNull(contextFactory, "The EL context factory cannot be null");
|
||||
contextFactories.put(contextType, contextFactory);
|
||||
}
|
||||
|
||||
public boolean isEvalExpressionString(String expressionString) {
|
||||
return expressionString.startsWith(EXPRESSION_PREFIX) && expressionString.endsWith(EXPRESSION_SUFFIX);
|
||||
public boolean isDelimitedExpression(String expressionString) {
|
||||
return (expressionString.startsWith(EXPRESSION_PREFIX_DEFERRED) && expressionString.endsWith(EXPRESSION_SUFFIX))
|
||||
|| (expressionString.startsWith(EXPRESSION_PREFIX_IMMEDIATE) && expressionString
|
||||
.endsWith(EXPRESSION_SUFFIX));
|
||||
}
|
||||
|
||||
public Expression parseExpression(String expressionString, Class expressionTargetType,
|
||||
Class expectedEvaluationResultType, ExpressionVariable[] expressionVariables) throws ParserException {
|
||||
if (expectedEvaluationResultType == null) {
|
||||
throw new ParserException(expressionString, "The 'expectedEvaluationResultType' argument is required; "
|
||||
+ "specify Object.class if the type is unknown", new NullPointerException());
|
||||
public Expression parseExpression(String expressionString, ParserContext context) throws ParserException {
|
||||
if (context == null) {
|
||||
context = NullParserContext.INSTANCE;
|
||||
}
|
||||
try {
|
||||
ParserELContext context = new ParserELContext();
|
||||
context.mapVariables(expressionVariables, expressionFactory);
|
||||
ValueExpression expression = expressionFactory.createValueExpression(context, expressionString,
|
||||
expectedEvaluationResultType);
|
||||
ELContextFactory contextFactory = getContextFactory(expressionTargetType, expressionString);
|
||||
return new ELExpression(contextFactory, expression, context.getVariableMapper());
|
||||
} catch (ELException ex) {
|
||||
throw new ParserException(expressionString, ex);
|
||||
ParserELContext elContext = new ParserELContext();
|
||||
elContext.mapVariables(context.getExpressionVariables(), expressionFactory);
|
||||
ValueExpression expression = expressionFactory.createValueExpression(elContext, expressionString,
|
||||
getExpectedType(context));
|
||||
ELContextFactory contextFactory = getContextFactory(context.getEvaluationContextType(), expressionString);
|
||||
return new ELExpression(contextFactory, expression, elContext.getVariableMapper());
|
||||
} catch (ELException e) {
|
||||
throw new ParserException(expressionString, e);
|
||||
}
|
||||
}
|
||||
|
||||
private Class getExpectedType(ParserContext context) {
|
||||
Class expectedType = context.getExpectedEvaluationResultType();
|
||||
if (expectedType != null) {
|
||||
return expectedType;
|
||||
} else {
|
||||
return Object.class;
|
||||
}
|
||||
}
|
||||
|
||||
private ELContextFactory getContextFactory(Class expressionTargetType, String expressionString) {
|
||||
if (!contextFactories.containsKey(expressionTargetType)) {
|
||||
throw new ParserException(expressionString, new IllegalArgumentException(
|
||||
"No ELContextFactory registered for expressionTargetType [" + expressionTargetType + "]; "
|
||||
+ "Please ensure a factory is registered for this type."));
|
||||
if (contextFactories.containsKey(expressionTargetType)) {
|
||||
return (ELContextFactory) contextFactories.get(expressionTargetType);
|
||||
} else {
|
||||
return (ELContextFactory) contextFactories.get(Object.class);
|
||||
}
|
||||
return (ELContextFactory) contextFactories.get(expressionTargetType);
|
||||
}
|
||||
|
||||
private void init(ExpressionFactory expressionFactory) {
|
||||
this.expressionFactory = expressionFactory;
|
||||
DefaultElContextFactory defaultContextFactory = new DefaultElContextFactory();
|
||||
putContextFactory(null, defaultContextFactory);
|
||||
putContextFactory(Object.class, defaultContextFactory);
|
||||
}
|
||||
|
||||
private static class ParserELContext extends ELContext {
|
||||
@@ -106,7 +131,8 @@ public class ELExpressionParser implements ExpressionParser {
|
||||
variableMapper = new VariableMapperImpl();
|
||||
for (int i = 0; i < variables.length; i++) {
|
||||
ExpressionVariable var = variables[i];
|
||||
ValueExpression expr = expressionFactory.createValueExpression(this, var.getValue(), Object.class);
|
||||
ValueExpression expr = expressionFactory.createValueExpression(this,
|
||||
String.valueOf(var.getValue()), Object.class);
|
||||
variableMapper.setVariable(var.getName(), expr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,15 +47,14 @@ class OgnlExpression implements Expression {
|
||||
/**
|
||||
* Expression variable initial values.
|
||||
*/
|
||||
private ExpressionVariable[] variables;
|
||||
private Map variableMap;;
|
||||
|
||||
/**
|
||||
* Creates a new OGNL expression.
|
||||
* @param expression the parsed expression
|
||||
*/
|
||||
public OgnlExpression(Object expression, ExpressionVariable[] variables) {
|
||||
this.expression = expression;
|
||||
this.variables = variables;
|
||||
init(expression, variables);
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
@@ -72,34 +71,43 @@ class OgnlExpression implements Expression {
|
||||
return expression.equals(other.expression);
|
||||
}
|
||||
|
||||
public Object getValue(Object target) throws EvaluationException {
|
||||
Assert.notNull(target, "The target object to evaluate is required");
|
||||
public Object getValue(Object context) throws EvaluationException {
|
||||
try {
|
||||
return Ognl.getValue(expression, getContext(), target);
|
||||
return Ognl.getValue(expression, variableMap, context);
|
||||
} catch (OgnlException e) {
|
||||
if (e.getReason() != null && e.getReason() != e) {
|
||||
// unwrap the OgnlException since the actual exception is wrapped inside it
|
||||
// and there is not generic (getCause) way to get to it later on
|
||||
throw new EvaluationException(new EvaluationAttempt(this, target), e.getReason());
|
||||
throw new EvaluationException(new EvaluationAttempt(this, context), e.getReason());
|
||||
} else {
|
||||
throw new EvaluationException(new EvaluationAttempt(this, target), e);
|
||||
throw new EvaluationException(new EvaluationAttempt(this, context), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setValue(Object target, Object value) {
|
||||
Assert.notNull(target, "The target object to evaluate is required");
|
||||
public void setValue(Object context, Object value) {
|
||||
Assert.notNull(context, "The context to set the provided value in is required");
|
||||
try {
|
||||
// TODO context map
|
||||
Ognl.setValue(expression, getContext(), target, value);
|
||||
Ognl.setValue(expression, variableMap, context, value);
|
||||
} catch (OgnlException e) {
|
||||
throw new EvaluationException(new SetValueAttempt(this, target, value), e);
|
||||
throw new EvaluationException(new SetValueAttempt(this, context, value), e);
|
||||
}
|
||||
}
|
||||
|
||||
private Map getContext() {
|
||||
private void init(Object expression, ExpressionVariable[] variables) {
|
||||
this.expression = expression;
|
||||
variableMap = createVariableMap(variables);
|
||||
}
|
||||
|
||||
private Map createVariableMap(ExpressionVariable[] variables) {
|
||||
if (variables != null && variables.length > 0) {
|
||||
return new HashMap(variables.length);
|
||||
Map variableMap = new HashMap(variables.length);
|
||||
for (int i = 0; i < variables.length; i++) {
|
||||
ExpressionVariable var = variables[i];
|
||||
variableMap.put(var.getName(), var.getValue());
|
||||
}
|
||||
System.out.println(variableMap);
|
||||
return variableMap;
|
||||
} else {
|
||||
return Collections.EMPTY_MAP;
|
||||
}
|
||||
|
||||
@@ -21,9 +21,10 @@ import ognl.OgnlRuntime;
|
||||
import ognl.PropertyAccessor;
|
||||
|
||||
import org.springframework.binding.expression.Expression;
|
||||
import org.springframework.binding.expression.ExpressionVariable;
|
||||
import org.springframework.binding.expression.ParserContext;
|
||||
import org.springframework.binding.expression.ParserException;
|
||||
import org.springframework.binding.expression.support.AbstractExpressionParser;
|
||||
import org.springframework.binding.expression.support.NullParserContext;
|
||||
|
||||
/**
|
||||
* An expression parser that parses Ognl expressions.
|
||||
@@ -32,10 +33,12 @@ import org.springframework.binding.expression.support.AbstractExpressionParser;
|
||||
*/
|
||||
public class OgnlExpressionParser extends AbstractExpressionParser {
|
||||
|
||||
protected Expression doParseExpression(String expressionString, Class expressionTargetType,
|
||||
Class expectedEvaluationResultType, ExpressionVariable[] expressionVariables) throws ParserException {
|
||||
public Expression doParseExpression(String expressionString, ParserContext context) throws ParserException {
|
||||
if (context == null) {
|
||||
context = NullParserContext.INSTANCE;
|
||||
}
|
||||
try {
|
||||
return new OgnlExpression(Ognl.parseExpression(expressionString), expressionVariables);
|
||||
return new OgnlExpression(Ognl.parseExpression(expressionString), context.getExpressionVariables());
|
||||
} catch (OgnlException e) {
|
||||
throw new ParserException(expressionString, e);
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ import java.util.List;
|
||||
|
||||
import org.springframework.binding.expression.Expression;
|
||||
import org.springframework.binding.expression.ExpressionParser;
|
||||
import org.springframework.binding.expression.ExpressionVariable;
|
||||
import org.springframework.binding.expression.ParserContext;
|
||||
import org.springframework.binding.expression.ParserException;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -80,15 +80,13 @@ public abstract class AbstractExpressionParser implements ExpressionParser {
|
||||
this.expressionSuffix = expressionSuffix;
|
||||
}
|
||||
|
||||
public boolean isEvalExpressionString(String string) {
|
||||
public boolean isDelimitedExpression(String string) {
|
||||
return string.startsWith(expressionPrefix) && string.endsWith(expressionSuffix);
|
||||
}
|
||||
|
||||
public Expression parseExpression(String expressionString, Class expressionTargetType,
|
||||
Class expectedEvaluationResultType, ExpressionVariable[] expressionVariables) throws ParserException {
|
||||
public Expression parseExpression(String expressionString, ParserContext context) throws ParserException {
|
||||
Assert.notNull(expressionString, "The expression string to parse is required");
|
||||
Expression[] expressions = parseExpressions(expressionString, expressionTargetType,
|
||||
expectedEvaluationResultType, expressionVariables);
|
||||
Expression[] expressions = parseExpressions(expressionString, context);
|
||||
if (expressions.length == 1) {
|
||||
return expressions[0];
|
||||
} else {
|
||||
@@ -105,8 +103,7 @@ public abstract class AbstractExpressionParser implements ExpressionParser {
|
||||
* @return the parsed expressions
|
||||
* @throws ParserException when the expressions cannot be parsed
|
||||
*/
|
||||
private Expression[] parseExpressions(String expressionString, Class expressionTargetType,
|
||||
Class expectedEvaluationResultType, ExpressionVariable[] expressionVariables) throws ParserException {
|
||||
private Expression[] parseExpressions(String expressionString, ParserContext context) throws ParserException {
|
||||
List expressions = new LinkedList();
|
||||
int startIdx = 0;
|
||||
while (startIdx < expressionString.length()) {
|
||||
@@ -136,8 +133,7 @@ public abstract class AbstractExpressionParser implements ExpressionParser {
|
||||
+ getExpressionPrefix() + getExpressionSuffix() + "' at character " + prefixIndex, null);
|
||||
} else {
|
||||
String expr = expressionString.substring(prefixIndex + getExpressionPrefix().length(), suffixIndex);
|
||||
expressions.add(doParseExpression(expr, expressionTargetType, expectedEvaluationResultType,
|
||||
expressionVariables));
|
||||
expressions.add(doParseExpression(expr, context));
|
||||
startIdx = suffixIndex + 1;
|
||||
}
|
||||
} else {
|
||||
@@ -157,7 +153,7 @@ public abstract class AbstractExpressionParser implements ExpressionParser {
|
||||
* @return the parsed expression
|
||||
* @throws ParserException an exception occurred during parsing
|
||||
*/
|
||||
protected abstract Expression doParseExpression(String expressionString, Class expressionTargetType,
|
||||
Class expectedEvaluationResultType, ExpressionVariable[] expressionVariables) throws ParserException;
|
||||
protected abstract Expression doParseExpression(String expressionString, ParserContext context)
|
||||
throws ParserException;
|
||||
|
||||
}
|
||||
@@ -43,14 +43,14 @@ public class CollectionAddingExpression implements Expression {
|
||||
this.collectionExpression = collectionExpression;
|
||||
}
|
||||
|
||||
public Object getValue(Object target) throws EvaluationException {
|
||||
return collectionExpression.getValue(target);
|
||||
public Object getValue(Object context) throws EvaluationException {
|
||||
return collectionExpression.getValue(context);
|
||||
}
|
||||
|
||||
public void setValue(Object target, Object value) throws EvaluationException {
|
||||
Object result = getValue(target);
|
||||
public void setValue(Object context, Object value) throws EvaluationException {
|
||||
Object result = getValue(context);
|
||||
if (result == null) {
|
||||
throw new EvaluationException(new SetValueAttempt(this, target, value), new IllegalArgumentException(
|
||||
throw new EvaluationException(new SetValueAttempt(this, context, value), new IllegalArgumentException(
|
||||
"The collection expression evaluated to a [null] reference"));
|
||||
}
|
||||
Assert.isInstanceOf(Collection.class, result, "Not a collection: ");
|
||||
|
||||
@@ -40,15 +40,15 @@ public class CompositeStringExpression implements Expression {
|
||||
this.expressions = expressions;
|
||||
}
|
||||
|
||||
public Object getValue(Object target) throws EvaluationException {
|
||||
public Object getValue(Object context) throws EvaluationException {
|
||||
StringBuffer buffer = new StringBuffer(128);
|
||||
for (int i = 0; i < expressions.length; i++) {
|
||||
buffer.append(expressions[i].getValue(target));
|
||||
buffer.append(expressions[i].getValue(context));
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
public void setValue(Object target, Object value) throws EvaluationException {
|
||||
public void setValue(Object context, Object value) throws EvaluationException {
|
||||
throw new UnsupportedOperationException("Cannot set a composite string expression value");
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2004-2007 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.binding.expression.support;
|
||||
|
||||
import org.springframework.binding.expression.ExpressionVariable;
|
||||
import org.springframework.binding.expression.ParserContext;
|
||||
|
||||
public final class NullParserContext implements ParserContext {
|
||||
|
||||
public static final ParserContext INSTANCE = new NullParserContext();
|
||||
|
||||
private NullParserContext() {
|
||||
}
|
||||
|
||||
public Class getEvaluationContextType() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Class getExpectedEvaluationResultType() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public ExpressionVariable[] getExpressionVariables() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package org.springframework.binding.expression.support;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.binding.expression.ExpressionVariable;
|
||||
import org.springframework.binding.expression.ParserContext;
|
||||
|
||||
public class ParserContextImpl implements ParserContext {
|
||||
|
||||
private Class evaluationContextType;
|
||||
|
||||
private Class evaluationResultType;
|
||||
|
||||
private List expressionVariables;
|
||||
|
||||
public ParserContextImpl() {
|
||||
init();
|
||||
}
|
||||
|
||||
public Class getEvaluationContextType() {
|
||||
return evaluationContextType;
|
||||
}
|
||||
|
||||
public Class getExpectedEvaluationResultType() {
|
||||
return evaluationResultType;
|
||||
}
|
||||
|
||||
public ExpressionVariable[] getExpressionVariables() {
|
||||
return (ExpressionVariable[]) expressionVariables.toArray(new ExpressionVariable[expressionVariables.size()]);
|
||||
}
|
||||
|
||||
public ParserContextImpl context(Class contextType) {
|
||||
evaluationContextType = contextType;
|
||||
return ParserContextImpl.this;
|
||||
}
|
||||
|
||||
public ParserContextImpl expect(Class resultType) {
|
||||
evaluationResultType = resultType;
|
||||
return ParserContextImpl.this;
|
||||
}
|
||||
|
||||
public ParserContextImpl variable(ExpressionVariable variable) {
|
||||
expressionVariables.add(variable);
|
||||
return ParserContextImpl.this;
|
||||
}
|
||||
|
||||
public ParserContextImpl variables(ExpressionVariable[] variables) {
|
||||
expressionVariables.addAll(Arrays.asList(variables));
|
||||
return ParserContextImpl.this;
|
||||
}
|
||||
|
||||
private void init() {
|
||||
expressionVariables = new ArrayList();
|
||||
}
|
||||
}
|
||||
@@ -101,7 +101,7 @@ public class MappingBuilder {
|
||||
* @return this, to support call-chaining
|
||||
*/
|
||||
public MappingBuilder source(String expressionString) {
|
||||
sourceExpression = expressionParser.parseExpression(expressionString, Object.class, Object.class, null);
|
||||
sourceExpression = expressionParser.parseExpression(expressionString, null);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@ public class MappingBuilder {
|
||||
* @return this, to support call-chaining
|
||||
*/
|
||||
public MappingBuilder target(String expressionString) {
|
||||
targetExpression = expressionParser.parseExpression(expressionString, Object.class, Object.class, null);
|
||||
targetExpression = expressionParser.parseExpression(expressionString, null);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -121,8 +121,7 @@ public class MappingBuilder {
|
||||
* @return this, to support call-chaining
|
||||
*/
|
||||
public MappingBuilder targetCollection(String expressionString) {
|
||||
targetExpression = new CollectionAddingExpression(expressionParser.parseExpression(expressionString,
|
||||
Object.class, Object.class, null));
|
||||
targetExpression = new CollectionAddingExpression(expressionParser.parseExpression(expressionString, null));
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user