You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by mb...@apache.org on 2007/08/10 17:48:14 UTC
svn commit: r564629 -
/commons/proper/el/trunk/src/java/org/apache/commons/el/ExpressionEvaluatorImpl.java
Author: mbenson
Date: Fri Aug 10 08:48:13 2007
New Revision: 564629
URL: http://svn.apache.org/viewvc?view=rev&rev=564629
Log:
format
Modified:
commons/proper/el/trunk/src/java/org/apache/commons/el/ExpressionEvaluatorImpl.java
Modified: commons/proper/el/trunk/src/java/org/apache/commons/el/ExpressionEvaluatorImpl.java
URL: http://svn.apache.org/viewvc/commons/proper/el/trunk/src/java/org/apache/commons/el/ExpressionEvaluatorImpl.java?view=diff&rev=564629&r1=564628&r2=564629
==============================================================================
--- commons/proper/el/trunk/src/java/org/apache/commons/el/ExpressionEvaluatorImpl.java (original)
+++ commons/proper/el/trunk/src/java/org/apache/commons/el/ExpressionEvaluatorImpl.java Fri Aug 10 08:48:13 2007
@@ -86,86 +86,81 @@
* @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author$
**/
-public class ExpressionEvaluatorImpl
- extends ExpressionEvaluator
-{
- //-------------------------------------
+public class ExpressionEvaluatorImpl extends ExpressionEvaluator {
+ // -------------------------------------
// Constants
- //-------------------------------------
+ // -------------------------------------
private static Log log = LogFactory.getLog(ExpressionEvaluatorImpl.class);
- //-------------------------------------
- // Member variables
- //-------------------------------------
-
- /** The mapping from expression String to its parsed form (String,
- Expression, or ExpressionString) **/
- static Map sCachedExpressionStrings =
- Collections.synchronizedMap (new HashMap ());
-
- /** The mapping from ExpectedType to Maps mapping literal String to
- parsed value **/
- static Map sCachedExpectedTypes = new HashMap ();
-
- /** Flag if the cache should be bypassed **/
- boolean mBypassCache;
-
- //-------------------------------------
- /**
- *
- * Constructor
- **/
- public ExpressionEvaluatorImpl () { }
-
- /**
- *
- * Constructor
- *
- * @param pBypassCache flag indicating if the cache should be
- * bypassed
- **/
- public ExpressionEvaluatorImpl (boolean pBypassCache)
- {
- mBypassCache = pBypassCache;
- }
-
- //-------------------------------------
-
- /**
- *
- * Prepare an expression for later evaluation. This method should perform
- * syntactic validation of the expression; if in doing so it detects
- * errors, it should raise an ELParseException.
- *
- * @param expression The expression to be evaluated.
- * @param expectedType The expected type of the result of the evaluation
- * @param fMapper A FunctionMapper to resolve functions found in
- * the expression. It can be null, in which case no functions
- * are supported for this invocation. The ExpressionEvaluator
- * must not hold on to the FunctionMapper reference after
- * returning from <code>parseExpression()</code>. The
- * <code>Expression</code> object returned must invoke the same
- * functions regardless of whether the mappings in the
- * provided <code>FunctionMapper</code> instance change between
- * calling <code>ExpressionEvaluator.parseExpression()</code>
- * and <code>Expression.evaluate()</code>.
- * @return The Expression object encapsulating the arguments.
- *
- * @exception ELException Thrown if parsing errors were found.
- **/
- public javax.servlet.jsp.el.Expression parseExpression(String expression,
- Class expectedType,
- FunctionMapper fMapper)
- throws ELException
- {
- // Validate and then create an Expression object.
- parseExpressionString(expression);
-
- // Create an Expression object that knows how to evaluate this.
- return new JSTLExpression(this, expression, expectedType, fMapper);
- }
+ // -------------------------------------
+ // Member variables
+ // -------------------------------------
+
+ /** The mapping from expression String to its parsed form (String,
+ Expression, or ExpressionString) **/
+ static Map sCachedExpressionStrings = Collections
+ .synchronizedMap(new HashMap());
+
+ /** The mapping from ExpectedType to Maps mapping literal String to
+ parsed value **/
+ static Map sCachedExpectedTypes = new HashMap();
+
+ /** Flag if the cache should be bypassed **/
+ boolean mBypassCache;
+
+ // -------------------------------------
+ /**
+ *
+ * Constructor
+ **/
+ public ExpressionEvaluatorImpl() {
+ }
+
+ /**
+ *
+ * Constructor
+ *
+ * @param pBypassCache flag indicating if the cache should be
+ * bypassed
+ **/
+ public ExpressionEvaluatorImpl(boolean pBypassCache) {
+ mBypassCache = pBypassCache;
+ }
+
+ // -------------------------------------
- //-------------------------------------
+ /**
+ *
+ * Prepare an expression for later evaluation. This method should perform
+ * syntactic validation of the expression; if in doing so it detects
+ * errors, it should raise an ELParseException.
+ *
+ * @param expression The expression to be evaluated.
+ * @param expectedType The expected type of the result of the evaluation
+ * @param fMapper A FunctionMapper to resolve functions found in
+ * the expression. It can be null, in which case no functions
+ * are supported for this invocation. The ExpressionEvaluator
+ * must not hold on to the FunctionMapper reference after
+ * returning from <code>parseExpression()</code>. The
+ * <code>Expression</code> object returned must invoke the same
+ * functions regardless of whether the mappings in the
+ * provided <code>FunctionMapper</code> instance change between
+ * calling <code>ExpressionEvaluator.parseExpression()</code>
+ * and <code>Expression.evaluate()</code>.
+ * @return The Expression object encapsulating the arguments.
+ *
+ * @exception ELException Thrown if parsing errors were found.
+ **/
+ public javax.servlet.jsp.el.Expression parseExpression(String expression,
+ Class expectedType, FunctionMapper fMapper) throws ELException {
+ // Validate and then create an Expression object.
+ parseExpressionString(expression);
+
+ // Create an Expression object that knows how to evaluate this.
+ return new JSTLExpression(this, expression, expectedType, fMapper);
+ }
+
+ // -------------------------------------
/**
*
* Evaluates the given expression String
@@ -180,312 +175,277 @@
* @return the expression String evaluated to the given expected
* type
**/
- public Object evaluate (String pExpressionString,
- Class pExpectedType,
- VariableResolver pResolver,
- FunctionMapper functions)
- throws ELException
- {
- // Check for null expression strings
- if (pExpressionString == null) {
- throw new ELException
- (Constants.NULL_EXPRESSION_STRING);
- }
-
- // Get the parsed version of the expression string
- Object parsedValue = parseExpressionString (pExpressionString);
-
- // Evaluate differently based on the parsed type
- if (parsedValue instanceof String) {
- // Convert the String, and cache the conversion
- String strValue = (String) parsedValue;
- return convertStaticValueToExpectedType (strValue, pExpectedType);
- }
-
- else if (parsedValue instanceof Expression) {
- // Evaluate the expression and convert
- Object value =
- ((Expression) parsedValue).evaluate (pResolver,
- functions);
- return convertToExpectedType (value, pExpectedType);
- }
-
- else if (parsedValue instanceof ExpressionString) {
- // Evaluate the expression/string list and convert
- String strValue =
- ((ExpressionString) parsedValue).evaluate (pResolver, functions);
- return convertToExpectedType (strValue, pExpectedType);
- }
-
- else {
- // This should never be reached
- return null;
- }
- }
-
- //-------------------------------------
- /**
- *
- * Gets the parsed form of the given expression string. If the
- * parsed form is cached (and caching is not bypassed), return the
- * cached form, otherwise parse and cache the value. Returns either
- * a String, Expression, or ExpressionString.
- **/
- public Object parseExpressionString (String pExpressionString)
- throws ELException
- {
- // See if it's an empty String
- if (pExpressionString.length () == 0) {
- return "";
- }
-
- // See if it's in the cache
- Object ret =
- mBypassCache ?
- null :
- sCachedExpressionStrings.get (pExpressionString);
-
- if (ret == null) {
- // Parse the expression
- Reader r = new StringReader (pExpressionString);
- ELParser parser = new ELParser (r);
- try {
- ret = parser.ExpressionString ();
- sCachedExpressionStrings.put (pExpressionString, ret);
- }
- catch (ParseException exc) {
- throw new ELException
- (formatParseException (pExpressionString,
- exc));
- }
- catch (TokenMgrError exc) {
- // Note - this should never be reached, since the parser is
- // constructed to tokenize any input (illegal inputs get
- // parsed to <BADLY_ESCAPED_STRING_LITERAL> or
- // <ILLEGAL_CHARACTER>
- throw new ELException (exc.getMessage ());
- }
- }
- return ret;
- }
-
- //-------------------------------------
- /**
- *
- * Converts the given value to the specified expected type.
- **/
- Object convertToExpectedType (Object pValue,
- Class pExpectedType)
- throws ELException
- {
- return Coercions.coerce (pValue, pExpectedType);
- }
-
- //-------------------------------------
- /**
- *
- * Converts the given String, specified as a static expression
- * string, to the given expected type. The conversion is cached.
- **/
- Object convertStaticValueToExpectedType (String pValue, Class pExpectedType)
- throws ELException
- {
- // See if the value is already of the expected type
- if (pExpectedType == String.class ||
- pExpectedType == Object.class) {
- return pValue;
- }
-
- // Find the cached value
- Map valueByString = getOrCreateExpectedTypeMap (pExpectedType);
- if (!mBypassCache &&
- valueByString.containsKey (pValue)) {
- return valueByString.get (pValue);
- }
- else {
- // Convert from a String
- Object ret = Coercions.coerce (pValue, pExpectedType);
- valueByString.put (pValue, ret);
- return ret;
- }
- }
-
- //-------------------------------------
- /**
- *
- * Creates or returns the Map that maps string literals to parsed
- * values for the specified expected type.
- **/
- static Map getOrCreateExpectedTypeMap (Class pExpectedType)
- {
- synchronized (sCachedExpectedTypes) {
- Map ret = (Map) sCachedExpectedTypes.get (pExpectedType);
- if (ret == null) {
- ret = Collections.synchronizedMap (new HashMap ());
- sCachedExpectedTypes.put (pExpectedType, ret);
- }
- return ret;
- }
- }
-
- //-------------------------------------
- // Formatting ParseException
- //-------------------------------------
- /**
- *
- * Formats a ParseException into an error message suitable for
- * displaying on a web page
- **/
- static String formatParseException (String pExpressionString,
- ParseException pExc)
- {
- // Generate the String of expected tokens
- StringBuffer expectedBuf = new StringBuffer ();
- int maxSize = 0;
- boolean printedOne = false;
-
- if (pExc.expectedTokenSequences == null)
- return pExc.toString();
-
- for (int i = 0; i < pExc.expectedTokenSequences.length; i++) {
- if (maxSize < pExc.expectedTokenSequences [i].length) {
- maxSize = pExc.expectedTokenSequences [i].length;
- }
- for (int j = 0; j < pExc.expectedTokenSequences [i].length; j++) {
- if (printedOne) {
- expectedBuf.append (", ");
- }
- expectedBuf.append
- (pExc.tokenImage [pExc.expectedTokenSequences [i] [j]]);
- printedOne = true;
- }
- }
- String expected = expectedBuf.toString ();
-
- // Generate the String of encountered tokens
- StringBuffer encounteredBuf = new StringBuffer ();
- Token tok = pExc.currentToken.next;
- for (int i = 0; i < maxSize; i++) {
- if (i != 0) encounteredBuf.append (" ");
- if (tok.kind == 0) {
- encounteredBuf.append (pExc.tokenImage [0]);
- break;
- }
- encounteredBuf.append (addEscapes (tok.image));
- tok = tok.next;
- }
- String encountered = encounteredBuf.toString ();
-
- // Format the error message
- return MessageFormat.format
- (Constants.PARSE_EXCEPTION,
- new Object [] {
- expected,
- encountered,
- });
- }
-
- //-------------------------------------
- /**
- *
- * Used to convert raw characters to their escaped version when
- * these raw version cannot be used as part of an ASCII string
- * literal.
- **/
- static String addEscapes (String str)
- {
- StringBuffer retval = new StringBuffer ();
- char ch;
- for (int i = 0, length = str.length(); i < length; i++) {
- switch (str.charAt (i)) {
- case 0 :
- continue;
- case '\b':
- retval.append ("\\b");
- continue;
- case '\t':
- retval.append ("\\t");
- continue;
- case '\n':
- retval.append ("\\n");
- continue;
- case '\f':
- retval.append ("\\f");
- continue;
- case '\r':
- retval.append ("\\r");
- continue;
- default:
- if ((ch = str.charAt (i)) < 0x20 || ch > 0x7e) {
- String s = "0000" + Integer.toString (ch, 16);
- retval.append ("\\u" + s.substring (s.length () - 4, s.length ()));
- }
- else {
- retval.append (ch);
- }
- continue;
- }
- }
- return retval.toString ();
- }
-
- //-------------------------------------
- // Testing methods
- //-------------------------------------
- /**
- *
- * Parses the given expression string, then converts it back to a
- * String in its canonical form. This is used to test parsing.
- **/
- public String parseAndRender (String pExpressionString)
- throws ELException
- {
- Object val = parseExpressionString (pExpressionString);
- if (val instanceof String) {
- return (String) val;
- }
- else if (val instanceof Expression) {
- return "${" + ((Expression) val).getExpressionString () + "}";
- }
- else if (val instanceof ExpressionString) {
- return ((ExpressionString) val).getExpressionString ();
- }
- else {
- return "";
- }
- }
-
- /**
- * An object that encapsulates an expression to be evaluated by
- * the JSTL evaluator.
- */
- private class JSTLExpression
- extends javax.servlet.jsp.el.Expression
- {
- private ExpressionEvaluatorImpl evaluator;
- private String expression;
- private Class expectedType;
- private FunctionMapper fMapper;
-
- public JSTLExpression(ExpressionEvaluatorImpl evaluator, String expression,
- Class expectedType, FunctionMapper fMapper)
- {
- this.evaluator = evaluator;
- this.expression = expression;
- this.expectedType = expectedType;
- this.fMapper = fMapper;
- }
-
- public Object evaluate( VariableResolver vResolver )
- throws ELException
- {
- return evaluator.evaluate(this.expression,
- this.expectedType,
- vResolver,
- this.fMapper);
+ public Object evaluate(String pExpressionString, Class pExpectedType,
+ VariableResolver pResolver, FunctionMapper functions)
+ throws ELException {
+ // Check for null expression strings
+ if (pExpressionString == null) {
+ throw new ELException(Constants.NULL_EXPRESSION_STRING);
+ }
+
+ // Get the parsed version of the expression string
+ Object parsedValue = parseExpressionString(pExpressionString);
+
+ // Evaluate differently based on the parsed type
+ if (parsedValue instanceof String) {
+ // Convert the String, and cache the conversion
+ String strValue = (String) parsedValue;
+ return convertStaticValueToExpectedType(strValue, pExpectedType);
+ }
+
+ else if (parsedValue instanceof Expression) {
+ // Evaluate the expression and convert
+ Object value = ((Expression) parsedValue).evaluate(pResolver,
+ functions);
+ return convertToExpectedType(value, pExpectedType);
+ }
+
+ else if (parsedValue instanceof ExpressionString) {
+ // Evaluate the expression/string list and convert
+ String strValue = ((ExpressionString) parsedValue).evaluate(
+ pResolver, functions);
+ return convertToExpectedType(strValue, pExpectedType);
+ }
+
+ else {
+ // This should never be reached
+ return null;
+ }
+ }
+
+ // -------------------------------------
+ /**
+ *
+ * Gets the parsed form of the given expression string. If the
+ * parsed form is cached (and caching is not bypassed), return the
+ * cached form, otherwise parse and cache the value. Returns either
+ * a String, Expression, or ExpressionString.
+ **/
+ public Object parseExpressionString(String pExpressionString)
+ throws ELException {
+ // See if it's an empty String
+ if (pExpressionString.length() == 0) {
+ return "";
+ }
+
+ // See if it's in the cache
+ Object ret = mBypassCache ? null : sCachedExpressionStrings
+ .get(pExpressionString);
+
+ if (ret == null) {
+ // Parse the expression
+ Reader r = new StringReader(pExpressionString);
+ ELParser parser = new ELParser(r);
+ try {
+ ret = parser.ExpressionString();
+ sCachedExpressionStrings.put(pExpressionString, ret);
+ } catch (ParseException exc) {
+ throw new ELException(formatParseException(pExpressionString,
+ exc));
+ } catch (TokenMgrError exc) {
+ // Note - this should never be reached, since the parser is
+ // constructed to tokenize any input (illegal inputs get
+ // parsed to <BADLY_ESCAPED_STRING_LITERAL> or
+ // <ILLEGAL_CHARACTER>
+ throw new ELException(exc.getMessage());
+ }
+ }
+ return ret;
+ }
+
+ // -------------------------------------
+ /**
+ *
+ * Converts the given value to the specified expected type.
+ **/
+ Object convertToExpectedType(Object pValue, Class pExpectedType)
+ throws ELException {
+ return Coercions.coerce(pValue, pExpectedType);
+ }
+
+ // -------------------------------------
+ /**
+ *
+ * Converts the given String, specified as a static expression
+ * string, to the given expected type. The conversion is cached.
+ **/
+ Object convertStaticValueToExpectedType(String pValue, Class pExpectedType)
+ throws ELException {
+ // See if the value is already of the expected type
+ if (pExpectedType == String.class || pExpectedType == Object.class) {
+ return pValue;
+ }
+
+ // Find the cached value
+ Map valueByString = getOrCreateExpectedTypeMap(pExpectedType);
+ if (!mBypassCache && valueByString.containsKey(pValue)) {
+ return valueByString.get(pValue);
+ } else {
+ // Convert from a String
+ Object ret = Coercions.coerce(pValue, pExpectedType);
+ valueByString.put(pValue, ret);
+ return ret;
+ }
+ }
+
+ // -------------------------------------
+ /**
+ *
+ * Creates or returns the Map that maps string literals to parsed
+ * values for the specified expected type.
+ **/
+ static Map getOrCreateExpectedTypeMap(Class pExpectedType) {
+ synchronized (sCachedExpectedTypes) {
+ Map ret = (Map) sCachedExpectedTypes.get(pExpectedType);
+ if (ret == null) {
+ ret = Collections.synchronizedMap(new HashMap());
+ sCachedExpectedTypes.put(pExpectedType, ret);
+ }
+ return ret;
+ }
+ }
+
+ // -------------------------------------
+ // Formatting ParseException
+ // -------------------------------------
+ /**
+ *
+ * Formats a ParseException into an error message suitable for
+ * displaying on a web page
+ **/
+ static String formatParseException(String pExpressionString,
+ ParseException pExc) {
+ // Generate the String of expected tokens
+ StringBuffer expectedBuf = new StringBuffer();
+ int maxSize = 0;
+ boolean printedOne = false;
+
+ if (pExc.expectedTokenSequences == null)
+ return pExc.toString();
+
+ for (int i = 0; i < pExc.expectedTokenSequences.length; i++) {
+ if (maxSize < pExc.expectedTokenSequences[i].length) {
+ maxSize = pExc.expectedTokenSequences[i].length;
+ }
+ for (int j = 0; j < pExc.expectedTokenSequences[i].length; j++) {
+ if (printedOne) {
+ expectedBuf.append(", ");
+ }
+ expectedBuf
+ .append(pExc.tokenImage[pExc.expectedTokenSequences[i][j]]);
+ printedOne = true;
+ }
+ }
+ String expected = expectedBuf.toString();
+
+ // Generate the String of encountered tokens
+ StringBuffer encounteredBuf = new StringBuffer();
+ Token tok = pExc.currentToken.next;
+ for (int i = 0; i < maxSize; i++) {
+ if (i != 0)
+ encounteredBuf.append(" ");
+ if (tok.kind == 0) {
+ encounteredBuf.append(pExc.tokenImage[0]);
+ break;
+ }
+ encounteredBuf.append(addEscapes(tok.image));
+ tok = tok.next;
+ }
+ String encountered = encounteredBuf.toString();
+
+ // Format the error message
+ return MessageFormat.format(Constants.PARSE_EXCEPTION, new Object[] {
+ expected, encountered, });
+ }
+
+ // -------------------------------------
+ /**
+ *
+ * Used to convert raw characters to their escaped version when
+ * these raw version cannot be used as part of an ASCII string
+ * literal.
+ **/
+ static String addEscapes(String str) {
+ StringBuffer retval = new StringBuffer();
+ char ch;
+ for (int i = 0, length = str.length(); i < length; i++) {
+ switch (str.charAt(i)) {
+ case 0:
+ continue;
+ case '\b':
+ retval.append("\\b");
+ continue;
+ case '\t':
+ retval.append("\\t");
+ continue;
+ case '\n':
+ retval.append("\\n");
+ continue;
+ case '\f':
+ retval.append("\\f");
+ continue;
+ case '\r':
+ retval.append("\\r");
+ continue;
+ default:
+ if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) {
+ String s = "0000" + Integer.toString(ch, 16);
+ retval.append("\\u"
+ + s.substring(s.length() - 4, s.length()));
+ } else {
+ retval.append(ch);
+ }
+ continue;
+ }
+ }
+ return retval.toString();
+ }
+
+ // -------------------------------------
+ // Testing methods
+ // -------------------------------------
+ /**
+ *
+ * Parses the given expression string, then converts it back to a
+ * String in its canonical form. This is used to test parsing.
+ **/
+ public String parseAndRender(String pExpressionString) throws ELException {
+ Object val = parseExpressionString(pExpressionString);
+ if (val instanceof String) {
+ return (String) val;
+ } else if (val instanceof Expression) {
+ return "${" + ((Expression) val).getExpressionString() + "}";
+ } else if (val instanceof ExpressionString) {
+ return ((ExpressionString) val).getExpressionString();
+ } else {
+ return "";
+ }
+ }
+
+ /**
+ * An object that encapsulates an expression to be evaluated by
+ * the JSTL evaluator.
+ */
+ private class JSTLExpression extends javax.servlet.jsp.el.Expression {
+ private ExpressionEvaluatorImpl evaluator;
+ private String expression;
+ private Class expectedType;
+ private FunctionMapper fMapper;
+
+ public JSTLExpression(ExpressionEvaluatorImpl evaluator,
+ String expression, Class expectedType, FunctionMapper fMapper) {
+ this.evaluator = evaluator;
+ this.expression = expression;
+ this.expectedType = expectedType;
+ this.fMapper = fMapper;
+ }
+
+ public Object evaluate(VariableResolver vResolver) throws ELException {
+ return evaluator.evaluate(this.expression, this.expectedType,
+ vResolver, this.fMapper);
+ }
}
- }
- //-------------------------------------
+ // -------------------------------------
}