From 1be0fd33054570086e11e98debb71f762b5a423b Mon Sep 17 00:00:00 2001 From: Jeff Scott Brown Date: Mon, 16 Sep 2013 11:39:47 -0500 Subject: [PATCH] GRAILS-10448 - introduce our own ExpressionEvaluationUtils for now --- .../taglib/jsp/ExpressionEvaluationUtils.java | 203 ++++++++++++++++++ .../taglib/jsp/JspInvokeGrailsTagLibTag.java | 24 +-- 2 files changed, 214 insertions(+), 13 deletions(-) create mode 100644 grails-web/src/main/groovy/org/codehaus/groovy/grails/web/taglib/jsp/ExpressionEvaluationUtils.java diff --git a/grails-web/src/main/groovy/org/codehaus/groovy/grails/web/taglib/jsp/ExpressionEvaluationUtils.java b/grails-web/src/main/groovy/org/codehaus/groovy/grails/web/taglib/jsp/ExpressionEvaluationUtils.java new file mode 100644 index 00000000000..da8396c8bab --- /dev/null +++ b/grails-web/src/main/groovy/org/codehaus/groovy/grails/web/taglib/jsp/ExpressionEvaluationUtils.java @@ -0,0 +1,203 @@ +/* + * Copyright 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. + * 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.codehaus.groovy.grails.web.taglib.jsp; + +import javax.servlet.ServletContext; +import javax.servlet.jsp.JspException; +import javax.servlet.jsp.PageContext; +import javax.servlet.jsp.el.ELException; + +import org.spockframework.util.Assert; + +/** + * IMPORTANT: This source code has been copied from org.springframework.web.util.ExpressionEvaluationUtils + * which was removed in Spring 4. This is here as a placeholder and will likely be removed + * before Grails 2.4 is released, never being included in a release. + * + * Convenience methods for accessing JSP 2.0's + * {@link javax.servlet.jsp.el.ExpressionEvaluator}. + * + *

The evaluation methods check if the value contains "${" before + * invoking the EL evaluator, treating the value as "normal" expression + * (i.e. a literal String value) else. + * + *

See {@link #isSpringJspExpressionSupportActive} for guidelines + * on when to use Spring's JSP expression support as opposed to the + * built-in expression support in JSP 2.0+ containers. + * + * @author Juergen Hoeller + * @author Alef Arendsen + * @since 11.07.2003 + * @see javax.servlet.jsp.el.ExpressionEvaluator#evaluate + * @deprecated as of Spring 3.2, in favor of the JSP 2.0+ native support + * for embedded expressions in JSP pages (also applying to tag attributes) + */ +public class ExpressionEvaluationUtils { + + /** + * Evaluate the given expression (be it EL or a literal String value) + * to an Object of a given type, + * @param attrName name of the attribute (typically a JSP tag attribute) + * @param attrValue value of the attribute + * @param resultClass class that the result should have (String, Integer, Boolean) + * @param pageContext current JSP PageContext + * @return the result of the evaluation + * @throws JspException in case of parsing errors, also in case of type mismatch + * if the passed-in literal value is not an EL expression and not assignable to + * the result class + */ + public static Object evaluate(String attrName, String attrValue, Class resultClass, PageContext pageContext) + throws JspException { + + if (ExpressionEvaluationUtils.isSpringJspExpressionSupportActive(pageContext) && ExpressionEvaluationUtils.isExpressionLanguage(attrValue)) { + return ExpressionEvaluationUtils.doEvaluate(attrName, attrValue, resultClass, pageContext); + } + else if (attrValue != null && resultClass != null && !resultClass.isInstance(attrValue)) { + throw new JspException("Attribute value \"" + attrValue + "\" is neither a JSP EL expression nor " + + "assignable to result class [" + resultClass.getName() + "]"); + } + else { + return attrValue; + } + } + + public static final String EXPRESSION_PREFIX = "${"; + public static final String EXPRESSION_SUFFIX = "}"; + /** + * Expression support parameter at the servlet context level + * (i.e. a context-param in {@code web.xml}): "springJspExpressionSupport". + */ + public static final String EXPRESSION_SUPPORT_CONTEXT_PARAM = "springJspExpressionSupport"; + /** + * Check if the given expression value is an EL expression. + * @param value the expression to check + * @return {@code true} if the expression is an EL expression, + * {@code false} otherwise + */ + public static boolean isExpressionLanguage(String value) { + return (value != null && value.contains(EXPRESSION_PREFIX)); + } + /** + * Check whether Spring's JSP expression support is actually active. + *

Note that JSP 2.0+ containers come with expression support themselves: + * However, it will only be active for web applications declaring Servlet 2.4 + * or higher in their {@code web.xml} deployment descriptor. + *

If a {@code web.xml} context-param named "springJspExpressionSupport" is + * found, its boolean value will be taken to decide whether this support is active. + * If not found, the default is for expression support to be inactive on Servlet 3.0 + * containers with web applications declaring Servlet 2.4 or higher in their + * {@code web.xml}. For backwards compatibility, Spring's expression support + * will remain active for applications declaring Servlet 2.3 or earlier. However, + * on Servlet 2.4/2.5 containers, we can't find out what the application has declared; + * as of Spring 3.2, we won't activate Spring's expression support at all then since + * it got deprecated and will be removed in the next iteration of the framework. + * @param pageContext current JSP PageContext + * @return {@code true} if active (ExpressionEvaluationUtils will actually evaluate expressions); + * {@code false} if not active (ExpressionEvaluationUtils will return given values as-is, + * relying on the JSP container pre-evaluating values before passing them to JSP tag attributes) + */ + public static boolean isSpringJspExpressionSupportActive(PageContext pageContext) { + ServletContext sc = pageContext.getServletContext(); + String springJspExpressionSupport = sc.getInitParameter(EXPRESSION_SUPPORT_CONTEXT_PARAM); + if (springJspExpressionSupport != null) { + return Boolean.valueOf(springJspExpressionSupport); + } + if (sc.getMajorVersion() >= 3) { + // We're on a Servlet 3.0+ container: Let's check what the application declares... + if (sc.getEffectiveMajorVersion() == 2 && sc.getEffectiveMinorVersion() < 4) { + // Application declares Servlet 2.3- in its web.xml: JSP 2.0 expressions not active. + // Activate our own expression support. + return true; + } + } + return false; + } + /** + * Actually evaluate the given expression (be it EL or a literal String value) + * to an Object of a given type. Supports concatenated expressions, + * for example: "${var1}text${var2}" + * @param attrName name of the attribute + * @param attrValue value of the attribute + * @param resultClass class that the result should have + * @param pageContext current JSP PageContext + * @return the result of the evaluation + * @throws JspException in case of parsing errors + */ + static Object doEvaluate(String attrName, String attrValue, Class resultClass, PageContext pageContext) + throws JspException { + + Assert.notNull(attrValue, "Attribute value must not be null"); + Assert.notNull(resultClass, "Result class must not be null"); + Assert.notNull(pageContext, "PageContext must not be null"); + + try { + if (resultClass.isAssignableFrom(String.class)) { + StringBuilder resultValue = null; + int exprPrefixIndex; + int exprSuffixIndex = 0; + do { + exprPrefixIndex = attrValue.indexOf(EXPRESSION_PREFIX, exprSuffixIndex); + if (exprPrefixIndex != -1) { + int prevExprSuffixIndex = exprSuffixIndex; + exprSuffixIndex = attrValue.indexOf(EXPRESSION_SUFFIX, exprPrefixIndex + EXPRESSION_PREFIX.length()); + String expr; + if (exprSuffixIndex != -1) { + exprSuffixIndex += EXPRESSION_SUFFIX.length(); + expr = attrValue.substring(exprPrefixIndex, exprSuffixIndex); + } + else { + expr = attrValue.substring(exprPrefixIndex); + } + if (expr.length() == attrValue.length()) { + // A single expression without static prefix or suffix -> + // parse it with the specified result class rather than String. + return ExpressionEvaluationUtils.evaluateExpression(attrValue, resultClass, pageContext); + } + else { + // We actually need to concatenate partial expressions into a String. + if (resultValue == null) { + resultValue = new StringBuilder(); + } + resultValue.append(attrValue.substring(prevExprSuffixIndex, exprPrefixIndex)); + resultValue.append(ExpressionEvaluationUtils.evaluateExpression(expr, String.class, pageContext)); + } + } + else { + if (resultValue == null) { + resultValue = new StringBuilder(); + } + resultValue.append(attrValue.substring(exprSuffixIndex)); + } + } + while (exprPrefixIndex != -1 && exprSuffixIndex != -1); + return resultValue.toString(); + } + else { + return ExpressionEvaluationUtils.evaluateExpression(attrValue, resultClass, pageContext); + } + } + catch (ELException ex) { + throw new JspException("Parsing of JSP EL expression failed for attribute '" + attrName + "'", ex); + } + } + static Object evaluateExpression(String exprValue, Class resultClass, PageContext pageContext) + throws ELException { + + return pageContext.getExpressionEvaluator().evaluate( + exprValue, resultClass, pageContext.getVariableResolver(), null); + } + +} diff --git a/grails-web/src/main/groovy/org/codehaus/groovy/grails/web/taglib/jsp/JspInvokeGrailsTagLibTag.java b/grails-web/src/main/groovy/org/codehaus/groovy/grails/web/taglib/jsp/JspInvokeGrailsTagLibTag.java index 53e5ff8aad2..83b0c244c64 100644 --- a/grails-web/src/main/groovy/org/codehaus/groovy/grails/web/taglib/jsp/JspInvokeGrailsTagLibTag.java +++ b/grails-web/src/main/groovy/org/codehaus/groovy/grails/web/taglib/jsp/JspInvokeGrailsTagLibTag.java @@ -48,7 +48,6 @@ import org.springframework.beans.BeanWrapper; import org.springframework.beans.BeanWrapperImpl; import org.springframework.context.ApplicationContext; -//import org.springframework.web.util.ExpressionEvaluationUtils; /** * A tag that invokes a tag defined in a the Grails dynamic tag library. Authors of Grails tags @@ -65,7 +64,6 @@ * @since 16-Jan-2006 */ public class JspInvokeGrailsTagLibTag extends BodyTagSupport implements DynamicAttributes { - private static final long serialVersionUID = 4688821761801666631L; private static final String ZERO_ARGUMENTS = "zeroArgumentsFlag"; private static final String GROOVY_DEFAULT_ARGUMENT = "it"; @@ -112,9 +110,9 @@ public final int doStartTag() throws JspException { while (m.find()) { String attributeName = m.group(1); String attributeValue = m.group(2); - if (false /*ExpressionEvaluationUtils.isExpressionLanguage(attributeValue)*/) { -// attributeMap.put(attributeName, ExpressionEvaluationUtils.evaluate( -// attributeName, attributeValue, Object.class, pageContext)); + if (ExpressionEvaluationUtils.isExpressionLanguage(attributeValue)) { + attributeMap.put(attributeName, ExpressionEvaluationUtils.evaluate( + attributeName, attributeValue, Object.class, pageContext)); } else { attributeMap.put(attributeName, attributeValue); @@ -123,9 +121,9 @@ public final int doStartTag() throws JspException { attributes.put(pd.getName(), attributeMap); } else { - if (false /*ExpressionEvaluationUtils.isExpressionLanguage(propertyValue)*/) { -// attributes.put(pd.getName(), ExpressionEvaluationUtils.evaluate( -// pd.getName(), propertyValue, Object.class, pageContext)); + if (ExpressionEvaluationUtils.isExpressionLanguage(propertyValue)) { + attributes.put(pd.getName(), ExpressionEvaluationUtils.evaluate( + pd.getName(), propertyValue, Object.class, pageContext)); } else { attributes.put(pd.getName(), propertyValue); @@ -339,9 +337,9 @@ public final void setDynamicAttribute(String uri, String localName, Object value while (m.find()) { String attributeName = m.group(1); String attributeValue = m.group(2); - if (false /*ExpressionEvaluationUtils.isExpressionLanguage(attributeValue)*/) { -// attributeMap.put(attributeName, ExpressionEvaluationUtils.evaluate( -// attributeName, attributeValue, Object.class, pageContext)); + if (ExpressionEvaluationUtils.isExpressionLanguage(attributeValue)) { + attributeMap.put(attributeName, ExpressionEvaluationUtils.evaluate( + attributeName, attributeValue, Object.class, pageContext)); } else { attributeMap.put(attributeName, attributeValue); @@ -350,8 +348,8 @@ public final void setDynamicAttribute(String uri, String localName, Object value attributes.put(localName, attributeMap); } else { - if (false /*ExpressionEvaluationUtils.isExpressionLanguage(stringValue)*/) { -// attributes.put(localName,ExpressionEvaluationUtils.evaluate(localName,stringValue,Object.class,pageContext)); + if (ExpressionEvaluationUtils.isExpressionLanguage(stringValue)) { + attributes.put(localName,ExpressionEvaluationUtils.evaluate(localName,stringValue,Object.class,pageContext)); } else { attributes.put(localName,value);