further EL improvements - OGNL behavior for variable handling is now correct, EL impl simplfiied.
This commit is contained in:
@@ -23,16 +23,6 @@ package org.springframework.binding.expression;
|
||||
*/
|
||||
public interface ExpressionParser {
|
||||
|
||||
/**
|
||||
* Is the provided string an explicitly delimited expression this parser knows how to parse? For example, this
|
||||
* method may return true if the string provided is enclosed in "${}". It may also return true if the string
|
||||
* provided is a mix of literal text and delimited expression syntax, for example "hello world ${name}!" The exact
|
||||
* semantics are determined by the parser implementation.
|
||||
* @param string the string
|
||||
* @return true if the string is a delimited expression, false otherwise.
|
||||
*/
|
||||
public boolean hasDelimitedExpression(String string);
|
||||
|
||||
/**
|
||||
* Parse the provided expression string, returning an expression evaluator capable of evaluating it.
|
||||
* @param expressionString the parseable expression string; cannot be null (required)
|
||||
|
||||
@@ -9,21 +9,22 @@ import org.springframework.util.Assert;
|
||||
public class ExpressionVariable {
|
||||
|
||||
private String name;
|
||||
private Object value;
|
||||
private String valueExpression;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @param value the value expression
|
||||
*/
|
||||
public ExpressionVariable(String name, Object value) {
|
||||
public ExpressionVariable(String name, String value) {
|
||||
Assert.hasText(name, "The expression variable must be named");
|
||||
Assert.hasText(value, "The expression variable's value expression is required");
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
this.valueExpression = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the variable name, typically vary simple like "index".
|
||||
* Returns the variable name.
|
||||
* @return the variable name
|
||||
*/
|
||||
public String getName() {
|
||||
@@ -34,8 +35,8 @@ 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 Object getValue() {
|
||||
return value;
|
||||
public String getValueExpression() {
|
||||
return valueExpression;
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
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);
|
||||
public ELContext getELContext(Object target) {
|
||||
return new DefaultELContext(new DefaultELResolver(target, null), null, null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package org.springframework.binding.expression.el;
|
||||
|
||||
import javax.el.ELContext;
|
||||
import javax.el.ELResolver;
|
||||
import javax.el.VariableMapper;
|
||||
|
||||
/**
|
||||
* A factory for creating a EL context object that will be used to evaluate a target object of an EL expression.
|
||||
@@ -16,9 +15,8 @@ public interface ELContextFactory {
|
||||
* object. In certain environments the target will be null and the base object of the expression is expected to be
|
||||
* resolved via the ELContext's {@link ELResolver} chain.
|
||||
* @param target The base object for the expression evaluation
|
||||
* @param variableMapper The mapping storing variables needed during expression evaluation
|
||||
* @return ELContext The configured ELContext instance for evaluating expressions.
|
||||
*/
|
||||
public ELContext getELContext(Object target, VariableMapper variableMapper);
|
||||
public ELContext getELContext(Object target);
|
||||
|
||||
}
|
||||
@@ -3,7 +3,6 @@ package org.springframework.binding.expression.el;
|
||||
import javax.el.ELContext;
|
||||
import javax.el.ELException;
|
||||
import javax.el.ValueExpression;
|
||||
import javax.el.VariableMapper;
|
||||
|
||||
import org.springframework.binding.expression.EvaluationAttempt;
|
||||
import org.springframework.binding.expression.EvaluationException;
|
||||
@@ -21,24 +20,20 @@ public class ELExpression implements Expression {
|
||||
|
||||
private ValueExpression valueExpression;
|
||||
|
||||
private VariableMapper variableMapper;
|
||||
|
||||
/**
|
||||
* Creates a new el expression
|
||||
* @param factory the el context factory for creating the EL context that will be used during expression evaluation
|
||||
* @param valueExpression the value expression to evaluate
|
||||
* @param variableMapper the variable mapper containing variables needed during expression evaluation
|
||||
*/
|
||||
public ELExpression(ELContextFactory factory, ValueExpression valueExpression, VariableMapper variableMapper) {
|
||||
public ELExpression(ELContextFactory factory, ValueExpression valueExpression) {
|
||||
Assert.notNull(factory, "The ELContextFactory is required to evaluate EL expressions");
|
||||
Assert.notNull(valueExpression, "The EL value expression is required for evaluation");
|
||||
this.elContextFactory = factory;
|
||||
this.valueExpression = valueExpression;
|
||||
this.variableMapper = variableMapper;
|
||||
}
|
||||
|
||||
public Object getValue(Object context) throws EvaluationException {
|
||||
ELContext ctx = elContextFactory.getELContext(context, variableMapper);
|
||||
ELContext ctx = elContextFactory.getELContext(context);
|
||||
try {
|
||||
return valueExpression.getValue(ctx);
|
||||
} catch (ELException ex) {
|
||||
@@ -47,7 +42,7 @@ public class ELExpression implements Expression {
|
||||
}
|
||||
|
||||
public void setValue(Object context, Object value) throws EvaluationException {
|
||||
ELContext ctx = elContextFactory.getELContext(context, variableMapper);
|
||||
ELContext ctx = elContextFactory.getELContext(context);
|
||||
try {
|
||||
valueExpression.setValue(ctx, value);
|
||||
} catch (ELException ex) {
|
||||
|
||||
@@ -26,21 +26,6 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
public class ELExpressionParser implements ExpressionParser {
|
||||
|
||||
/**
|
||||
* The expression prefix.
|
||||
*/
|
||||
private static final String EXPRESSION_PREFIX_IMMEDIATE = "${";
|
||||
|
||||
/**
|
||||
* The expression prefix.
|
||||
*/
|
||||
private static final String EXPRESSION_PREFIX_DEFERRED = "#{";
|
||||
|
||||
/**
|
||||
* The expression suffix.
|
||||
*/
|
||||
private static final String EXPRESSION_SUFFIX = "}";
|
||||
|
||||
/**
|
||||
* The ExpressionFactory for constructing EL expressions
|
||||
*/
|
||||
@@ -65,12 +50,6 @@ public class ELExpressionParser implements ExpressionParser {
|
||||
contextFactories.put(contextType, contextFactory);
|
||||
}
|
||||
|
||||
public boolean hasDelimitedExpression(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, ParserContext context) throws ParserException {
|
||||
Assert.notNull(expressionString, "The expression string to parse is required");
|
||||
if (context == null) {
|
||||
@@ -82,7 +61,7 @@ public class ELExpressionParser implements ExpressionParser {
|
||||
ValueExpression expression = expressionFactory.createValueExpression(elContext, expressionString,
|
||||
getExpectedType(context));
|
||||
ELContextFactory contextFactory = getContextFactory(context.getEvaluationContextType(), expressionString);
|
||||
return new ELExpression(contextFactory, expression, elContext.getVariableMapper());
|
||||
return new ELExpression(contextFactory, expression);
|
||||
} catch (ELException e) {
|
||||
throw new ParserException(expressionString, e);
|
||||
}
|
||||
@@ -132,8 +111,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,
|
||||
String.valueOf(var.getValue()), Object.class);
|
||||
ValueExpression expr = expressionFactory.createValueExpression(this, var.getValueExpression(),
|
||||
Object.class);
|
||||
variableMapper.setVariable(var.getName(), expr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ package org.springframework.binding.expression.ognl;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import ognl.Ognl;
|
||||
@@ -25,7 +26,6 @@ import ognl.OgnlException;
|
||||
import org.springframework.binding.expression.EvaluationAttempt;
|
||||
import org.springframework.binding.expression.EvaluationException;
|
||||
import org.springframework.binding.expression.Expression;
|
||||
import org.springframework.binding.expression.ExpressionVariable;
|
||||
import org.springframework.binding.expression.SetValueAttempt;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -44,14 +44,21 @@ class OgnlExpression implements Expression {
|
||||
/**
|
||||
* Expression variable initial values.
|
||||
*/
|
||||
private Map variableMap;;
|
||||
private Map variableExpressions;
|
||||
|
||||
/**
|
||||
* The expected type of object returned from evaluating the expression.
|
||||
*/
|
||||
private Class expectedResultType;
|
||||
|
||||
/**
|
||||
* Creates a new OGNL expression.
|
||||
* @param expression the parsed expression
|
||||
*/
|
||||
public OgnlExpression(Object expression, ExpressionVariable[] variables) {
|
||||
init(expression, variables);
|
||||
public OgnlExpression(Object expression, Map variableExpressions, Class expectedResultType) {
|
||||
this.expression = expression;
|
||||
this.variableExpressions = variableExpressions;
|
||||
this.expectedResultType = expectedResultType;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
@@ -68,7 +75,7 @@ class OgnlExpression implements Expression {
|
||||
|
||||
public Object getValue(Object context) throws EvaluationException {
|
||||
try {
|
||||
return Ognl.getValue(expression, variableMap, context);
|
||||
return Ognl.getValue(expression, getVariables(context), context, expectedResultType);
|
||||
} catch (OgnlException e) {
|
||||
if (e.getReason() != null && e.getReason() != e) {
|
||||
// unwrap the OgnlException since the actual exception is wrapped inside it
|
||||
@@ -83,28 +90,23 @@ class OgnlExpression implements Expression {
|
||||
public void setValue(Object context, Object value) {
|
||||
Assert.notNull(context, "The context to set the provided value in is required");
|
||||
try {
|
||||
Ognl.setValue(expression, variableMap, context, value);
|
||||
Ognl.setValue(expression, getVariables(context), context, value);
|
||||
} catch (OgnlException e) {
|
||||
throw new EvaluationException(new SetValueAttempt(this, context, value), e);
|
||||
}
|
||||
}
|
||||
|
||||
private void init(Object expression, ExpressionVariable[] variables) {
|
||||
this.expression = expression;
|
||||
variableMap = createVariableMap(variables);
|
||||
}
|
||||
|
||||
private Map createVariableMap(ExpressionVariable[] variables) {
|
||||
if (variables != null && variables.length > 0) {
|
||||
Map variableMap = new HashMap(variables.length);
|
||||
for (int i = 0; i < variables.length; i++) {
|
||||
ExpressionVariable var = variables[i];
|
||||
variableMap.put(var.getName(), var.getValue());
|
||||
}
|
||||
return variableMap;
|
||||
} else {
|
||||
private Map getVariables(Object context) {
|
||||
if (variableExpressions == null) {
|
||||
return Collections.EMPTY_MAP;
|
||||
}
|
||||
Map variables = new HashMap(variableExpressions.size(), 1);
|
||||
for (Iterator it = variableExpressions.entrySet().iterator(); it.hasNext();) {
|
||||
Map.Entry var = (Map.Entry) it.next();
|
||||
Expression valueExpression = (Expression) var.getValue();
|
||||
variables.put(var.getKey(), valueExpression.getValue(context));
|
||||
}
|
||||
return variables;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
|
||||
@@ -15,33 +15,109 @@
|
||||
*/
|
||||
package org.springframework.binding.expression.ognl;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import ognl.Ognl;
|
||||
import ognl.OgnlException;
|
||||
import ognl.OgnlRuntime;
|
||||
import ognl.PropertyAccessor;
|
||||
|
||||
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.AbstractExpressionParser;
|
||||
import org.springframework.binding.expression.support.CompositeStringExpression;
|
||||
import org.springframework.binding.expression.support.NullParserContext;
|
||||
import org.springframework.binding.expression.support.StaticExpression;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* An expression parser that parses Ognl expressions.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public class OgnlExpressionParser extends AbstractExpressionParser {
|
||||
public class OgnlExpressionParser implements ExpressionParser {
|
||||
|
||||
public Expression doParseExpression(String expressionString, ParserContext context) throws ParserException {
|
||||
if (context == null) {
|
||||
context = NullParserContext.INSTANCE;
|
||||
}
|
||||
try {
|
||||
return new OgnlExpression(Ognl.parseExpression(expressionString), context.getExpressionVariables());
|
||||
} catch (OgnlException e) {
|
||||
throw new ParserException(expressionString, e);
|
||||
}
|
||||
/**
|
||||
* The expression prefix.
|
||||
*/
|
||||
private static final String DEFAULT_EXPRESSION_PREFIX = "${";
|
||||
|
||||
/**
|
||||
* The expression suffix.
|
||||
*/
|
||||
private static final String DEFAULT_EXPRESSION_SUFFIX = "}";
|
||||
|
||||
/**
|
||||
* The marked expression delimter prefix.
|
||||
*/
|
||||
private String expressionPrefix = DEFAULT_EXPRESSION_PREFIX;
|
||||
|
||||
/**
|
||||
* The marked expression delimiter suffix.
|
||||
*/
|
||||
private String expressionSuffix = DEFAULT_EXPRESSION_SUFFIX;
|
||||
|
||||
/**
|
||||
* Should we allow undelimited OGNL eval expressions like "foo.bar"? If not, evalutable OGNL expressions must be
|
||||
* enclosed in delimiters like ${foo.bar} else they are treated as literal expressions. Mainly here for
|
||||
* compatability reasons, as Web Flow 1.0 allows undelimited OGNL eval expressions by default.
|
||||
*/
|
||||
private boolean allowUndelimitedEvalExpressions;
|
||||
|
||||
/**
|
||||
* Returns the configured expression delimiter prefix. Defaults to "${".
|
||||
*/
|
||||
public String getExpressionPrefix() {
|
||||
return expressionPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the expression delimiter prefix.
|
||||
*/
|
||||
public void setExpressionPrefix(String expressionPrefix) {
|
||||
this.expressionPrefix = expressionPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the expression delimiter suffix. Defaults to "}".
|
||||
*/
|
||||
public String getExpressionSuffix() {
|
||||
return expressionSuffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the expression delimiter suffix.
|
||||
*/
|
||||
public void setExpressionSuffix(String expressionSuffix) {
|
||||
this.expressionSuffix = expressionSuffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if this parser should we allow undelimited OGNL eval expressions like <code>foo.bar</code>.
|
||||
*/
|
||||
public boolean getAllowUndelimitedEvalExpressions() {
|
||||
return allowUndelimitedEvalExpressions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets if this parser should allow undelimited OGNL eval expressions like "foo.bar"? If not, evalutable OGNL
|
||||
* expressions must be enclosed in delimiters like ${foo.bar}, else they are treated as literal expressions.
|
||||
*/
|
||||
public void setAllowUndelimitedEvalExpressions(boolean allowUndelmitedEvalExpressions) {
|
||||
this.allowUndelimitedEvalExpressions = allowUndelmitedEvalExpressions;
|
||||
}
|
||||
|
||||
public static String getDEFAULT_EXPRESSION_PREFIX() {
|
||||
return DEFAULT_EXPRESSION_PREFIX;
|
||||
}
|
||||
|
||||
public static String getDEFAULT_EXPRESSION_SUFFIX() {
|
||||
return DEFAULT_EXPRESSION_SUFFIX;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -52,4 +128,152 @@ public class OgnlExpressionParser extends AbstractExpressionParser {
|
||||
public void addPropertyAccessor(Class clazz, PropertyAccessor propertyAccessor) {
|
||||
OgnlRuntime.setPropertyAccessor(clazz, propertyAccessor);
|
||||
}
|
||||
|
||||
// expression parser
|
||||
|
||||
public Expression parseExpression(String expressionString, ParserContext context) throws ParserException {
|
||||
Assert.notNull(expressionString, "The expression string to parse is required");
|
||||
Expression[] expressions = parseExpressions(expressionString, context);
|
||||
if (expressions.length == 1) {
|
||||
return expressions[0];
|
||||
} else {
|
||||
return new CompositeStringExpression(expressions);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the provided string a template expression this parser can parse? Always returns <code>true</code> if this
|
||||
* OGNL expression parser is configured to <b>not</b> allow undelimited OGNL expressions. If undelimited OGNL
|
||||
* expressions are allowed like "foo.bar", this method only returns true if an explicitly delimited expression is
|
||||
* present in the string like "hello my name is ${name}" or "${foo.bar}".
|
||||
*
|
||||
* In general, a template expression is either:
|
||||
* <ol>
|
||||
* <li>static literal text like "hello world". In this case, evaluating the expression simply returns the literal
|
||||
* text.
|
||||
* <li>a single eval expression like ${requestParameters.foo}. In this case, evaluating the expression returns the
|
||||
* evaluated value.
|
||||
* <li>a mix of literal text with one or more eval expressions like "hello #{name}". In this case, evaluating the
|
||||
* expression returns a string with the result of #{name} evaluated (often called a composite expression).
|
||||
* </ol>
|
||||
*
|
||||
* This method and the {@link #getAllowUndelimitedEvalExpressions()} flag primarily exist for compatibility reasons.
|
||||
* The OgnlExpressionParser in SWF 1.0 does not treat literal text like "hello world" as a template expression, but
|
||||
* rather a standard, evaluatable OGNL expression. Therefore, callers expecting standard template evaluation
|
||||
* semantics are expected to work with these literal string values themselves, and not pass those strings to
|
||||
* {@link #parseExpression(String, ParserContext)}.
|
||||
*
|
||||
* @param string the string
|
||||
* @return true if the string is a template expression, false otherwise.
|
||||
*/
|
||||
public boolean isTemplateExpression(String string) {
|
||||
if (!allowUndelimitedEvalExpressions) {
|
||||
// every string provided is a "template" style expression - return true
|
||||
return true;
|
||||
}
|
||||
// only returns true when there is ${} somewhere in the string
|
||||
// this is version 1.0 semantics, there for compatability reasons
|
||||
int prefixIndex = string.indexOf(getExpressionPrefix());
|
||||
if (prefixIndex == -1) {
|
||||
return false;
|
||||
}
|
||||
int suffixIndex = string.indexOf(getExpressionSuffix(), prefixIndex);
|
||||
if (suffixIndex == -1) {
|
||||
return false;
|
||||
} else {
|
||||
// make sure there is actually something inside the ${}
|
||||
if (suffixIndex == prefixIndex + getExpressionPrefix().length()) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// helper methods
|
||||
|
||||
/**
|
||||
* Helper that parses given expression string using the configured parser. The expression string can contain any
|
||||
* number of expressions all contained in "${...}" markers. For instance: "foo${expr0}bar${expr1}". The static
|
||||
* pieces of text will also be returned as Expressions that just return that static piece of text. As a result,
|
||||
* evaluating all returned expressions and concatenating the results produces the complete evaluated string.
|
||||
* @param expressionString the expression string
|
||||
* @return the parsed expressions
|
||||
* @throws ParserException when the expressions cannot be parsed
|
||||
*/
|
||||
private Expression[] parseExpressions(String expressionString, ParserContext context) throws ParserException {
|
||||
List expressions = new LinkedList();
|
||||
int startIdx = 0;
|
||||
while (startIdx < expressionString.length()) {
|
||||
int prefixIndex = expressionString.indexOf(getExpressionPrefix(), startIdx);
|
||||
if (prefixIndex >= startIdx) {
|
||||
// a inner expression was found - this is a composite
|
||||
if (prefixIndex > startIdx) {
|
||||
expressions.add(new StaticExpression(expressionString.substring(startIdx, prefixIndex)));
|
||||
startIdx = prefixIndex;
|
||||
}
|
||||
int nextPrefixIndex = expressionString.indexOf(getExpressionPrefix(), prefixIndex
|
||||
+ getExpressionPrefix().length());
|
||||
int suffixIndex;
|
||||
if (nextPrefixIndex == -1) {
|
||||
// this is the last expression in the expression string
|
||||
suffixIndex = expressionString.lastIndexOf(getExpressionSuffix());
|
||||
} else {
|
||||
// another expression exists after this one in the expression string
|
||||
suffixIndex = expressionString.lastIndexOf(getExpressionSuffix(), nextPrefixIndex);
|
||||
}
|
||||
if (suffixIndex < (prefixIndex + getExpressionPrefix().length())) {
|
||||
throw new ParserException(expressionString, "No ending suffix '" + getExpressionSuffix()
|
||||
+ "' for expression starting at character " + prefixIndex + ": "
|
||||
+ expressionString.substring(prefixIndex), null);
|
||||
} else if (suffixIndex == prefixIndex + getExpressionPrefix().length()) {
|
||||
throw new ParserException(expressionString, "No expression defined within delimiter '"
|
||||
+ getExpressionPrefix() + getExpressionSuffix() + "' at character " + prefixIndex, null);
|
||||
} else {
|
||||
String expr = expressionString.substring(prefixIndex + getExpressionPrefix().length(), suffixIndex);
|
||||
expressions.add(doParseExpression(expr, context));
|
||||
startIdx = suffixIndex + 1;
|
||||
}
|
||||
} else {
|
||||
if (startIdx == 0) {
|
||||
// treat the entire string as one expression
|
||||
if (allowUndelimitedEvalExpressions) {
|
||||
expressions.add(doParseExpression(expressionString, context));
|
||||
} else {
|
||||
// treat entire string as a literal
|
||||
expressions.add(new StaticExpression(expressionString));
|
||||
}
|
||||
} else {
|
||||
// no more ${expressions} found in string, add rest as static text
|
||||
expressions.add(new StaticExpression(expressionString.substring(startIdx)));
|
||||
}
|
||||
startIdx = expressionString.length();
|
||||
}
|
||||
}
|
||||
return (Expression[]) expressions.toArray(new Expression[expressions.size()]);
|
||||
}
|
||||
|
||||
private Expression doParseExpression(String expressionString, ParserContext context) throws ParserException {
|
||||
if (context == null) {
|
||||
context = NullParserContext.INSTANCE;
|
||||
}
|
||||
try {
|
||||
return new OgnlExpression(Ognl.parseExpression(expressionString), parseVariableExpressions(context
|
||||
.getExpressionVariables()), context.getExpectedEvaluationResultType());
|
||||
} catch (OgnlException e) {
|
||||
throw new ParserException(expressionString, e);
|
||||
}
|
||||
}
|
||||
|
||||
private Map parseVariableExpressions(ExpressionVariable[] variables) throws OgnlException {
|
||||
if (variables == null || variables.length == 0) {
|
||||
return null;
|
||||
}
|
||||
Map variableExpressions = new HashMap(variables.length, 1);
|
||||
for (int i = 0; i < variables.length; i++) {
|
||||
ExpressionVariable var = variables[i];
|
||||
variableExpressions.put(var.getName(), parseExpression(var.getValueExpression(), null));
|
||||
}
|
||||
return variableExpressions;
|
||||
}
|
||||
}
|
||||
@@ -1,178 +0,0 @@
|
||||
/*
|
||||
* 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 java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.binding.expression.Expression;
|
||||
import org.springframework.binding.expression.ExpressionParser;
|
||||
import org.springframework.binding.expression.ParserContext;
|
||||
import org.springframework.binding.expression.ParserException;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Abstract base class for expression parsers.
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @author Erwin Vervaet
|
||||
*/
|
||||
public abstract class AbstractExpressionParser implements ExpressionParser {
|
||||
|
||||
/**
|
||||
* The expression prefix.
|
||||
*/
|
||||
private static final String DEFAULT_EXPRESSION_PREFIX = "${";
|
||||
|
||||
/**
|
||||
* The expression suffix.
|
||||
*/
|
||||
private static final String DEFAULT_EXPRESSION_SUFFIX = "}";
|
||||
|
||||
/**
|
||||
* The marked expression delimter prefix.
|
||||
*/
|
||||
private String expressionPrefix = DEFAULT_EXPRESSION_PREFIX;
|
||||
|
||||
/**
|
||||
* The marked expression delimiter suffix.
|
||||
*/
|
||||
private String expressionSuffix = DEFAULT_EXPRESSION_SUFFIX;
|
||||
|
||||
/**
|
||||
* Returns the configured expression delimiter prefix. Defaults to "${".
|
||||
*/
|
||||
public String getExpressionPrefix() {
|
||||
return expressionPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the expression delimiter prefix.
|
||||
*/
|
||||
public void setExpressionPrefix(String expressionPrefix) {
|
||||
this.expressionPrefix = expressionPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the expression delimiter suffix. Defaults to "}".
|
||||
*/
|
||||
public String getExpressionSuffix() {
|
||||
return expressionSuffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the expression delimiter suffix.
|
||||
*/
|
||||
public void setExpressionSuffix(String expressionSuffix) {
|
||||
this.expressionSuffix = expressionSuffix;
|
||||
}
|
||||
|
||||
public boolean hasDelimitedExpression(String string) {
|
||||
int prefixIndex = string.indexOf(getExpressionPrefix());
|
||||
if (prefixIndex == -1) {
|
||||
return false;
|
||||
}
|
||||
int suffixIndex = string.indexOf(getExpressionSuffix(), prefixIndex);
|
||||
if (suffixIndex == -1) {
|
||||
return false;
|
||||
} else {
|
||||
// make sure there is actually something inside the ${}
|
||||
if (suffixIndex == prefixIndex + getExpressionPrefix().length()) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Expression parseExpression(String expressionString, ParserContext context) throws ParserException {
|
||||
Assert.notNull(expressionString, "The expression string to parse is required");
|
||||
Expression[] expressions = parseExpressions(expressionString, context);
|
||||
if (expressions.length == 1) {
|
||||
return expressions[0];
|
||||
} else {
|
||||
return new CompositeStringExpression(expressions);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper that parses given expression string using the configured parser. The expression string can contain any
|
||||
* number of expressions all contained in "${...}" markers. For instance: "foo${expr0}bar${expr1}". The static
|
||||
* pieces of text will also be returned as Expressions that just return that static piece of text. As a result,
|
||||
* evaluating all returned expressions and concatenating the results produces the complete evaluated string.
|
||||
* @param expressionString the expression string
|
||||
* @return the parsed expressions
|
||||
* @throws ParserException when the expressions cannot be parsed
|
||||
*/
|
||||
private Expression[] parseExpressions(String expressionString, ParserContext context) throws ParserException {
|
||||
List expressions = new LinkedList();
|
||||
int startIdx = 0;
|
||||
while (startIdx < expressionString.length()) {
|
||||
int prefixIndex = expressionString.indexOf(getExpressionPrefix(), startIdx);
|
||||
if (prefixIndex >= startIdx) {
|
||||
// a inner expression was found - this is a composite
|
||||
if (prefixIndex > startIdx) {
|
||||
expressions.add(new StaticExpression(expressionString.substring(startIdx, prefixIndex)));
|
||||
startIdx = prefixIndex;
|
||||
}
|
||||
int nextPrefixIndex = expressionString.indexOf(getExpressionPrefix(), prefixIndex
|
||||
+ getExpressionPrefix().length());
|
||||
int suffixIndex;
|
||||
if (nextPrefixIndex == -1) {
|
||||
// this is the last expression in the expression string
|
||||
suffixIndex = expressionString.lastIndexOf(getExpressionSuffix());
|
||||
} else {
|
||||
// another expression exists after this one in the expression string
|
||||
suffixIndex = expressionString.lastIndexOf(getExpressionSuffix(), nextPrefixIndex);
|
||||
}
|
||||
if (suffixIndex < (prefixIndex + getExpressionPrefix().length())) {
|
||||
throw new ParserException(expressionString, "No ending suffix '" + getExpressionSuffix()
|
||||
+ "' for expression starting at character " + prefixIndex + ": "
|
||||
+ expressionString.substring(prefixIndex), null);
|
||||
} else if (suffixIndex == prefixIndex + getExpressionPrefix().length()) {
|
||||
throw new ParserException(expressionString, "No expression defined within delimiter '"
|
||||
+ getExpressionPrefix() + getExpressionSuffix() + "' at character " + prefixIndex, null);
|
||||
} else {
|
||||
String expr = expressionString.substring(prefixIndex + getExpressionPrefix().length(), suffixIndex);
|
||||
expressions.add(doParseExpression(expr, context));
|
||||
startIdx = suffixIndex + 1;
|
||||
}
|
||||
} else {
|
||||
if (startIdx == 0) {
|
||||
// treat the entire string as one expression
|
||||
expressions.add(doParseExpression(expressionString, context));
|
||||
} else {
|
||||
// no more ${expressions} found in string, add rest as static text
|
||||
expressions.add(new StaticExpression(expressionString.substring(startIdx)));
|
||||
}
|
||||
startIdx = expressionString.length();
|
||||
}
|
||||
}
|
||||
return (Expression[]) expressions.toArray(new Expression[expressions.size()]);
|
||||
}
|
||||
|
||||
// template methods
|
||||
|
||||
/**
|
||||
* Template method for parsing a filtered expression string. Subclasses should override.
|
||||
* @param expressionString the expression string
|
||||
* @return the parsed expression
|
||||
* @throws ParserException an exception occurred during parsing
|
||||
*/
|
||||
protected abstract Expression doParseExpression(String expressionString, ParserContext context)
|
||||
throws ParserException;
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user