8 changed files with 309 additions and 12 deletions
@ -0,0 +1,181 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2002-2009 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.web.servlet.tags; |
||||||
|
|
||||||
|
import java.io.IOException; |
||||||
|
|
||||||
|
import javax.servlet.jsp.JspException; |
||||||
|
import javax.servlet.jsp.PageContext; |
||||||
|
|
||||||
|
import org.springframework.beans.BeansException; |
||||||
|
import org.springframework.core.convert.ConversionService; |
||||||
|
import org.springframework.expression.AccessException; |
||||||
|
import org.springframework.expression.EvaluationContext; |
||||||
|
import org.springframework.expression.Expression; |
||||||
|
import org.springframework.expression.ExpressionParser; |
||||||
|
import org.springframework.expression.PropertyAccessor; |
||||||
|
import org.springframework.expression.TypedValue; |
||||||
|
import org.springframework.expression.spel.standard.SpelExpressionParser; |
||||||
|
import org.springframework.expression.spel.support.StandardEvaluationContext; |
||||||
|
import org.springframework.expression.spel.support.StandardTypeConverter; |
||||||
|
import org.springframework.web.util.ExpressionEvaluationUtils; |
||||||
|
import org.springframework.web.util.HtmlUtils; |
||||||
|
import org.springframework.web.util.JavaScriptUtils; |
||||||
|
import org.springframework.web.util.TagUtils; |
||||||
|
|
||||||
|
/** |
||||||
|
* JSP tag for evaluating expressions with the Spring Expression Language (SpEL). |
||||||
|
* Supports the standard JSP evaluation context consisting of implicit variables and scoped attributes. |
||||||
|
* |
||||||
|
* @author Keith Donald |
||||||
|
* @since 3.0.1 |
||||||
|
*/ |
||||||
|
public class EvalTag extends HtmlEscapingAwareTag { |
||||||
|
|
||||||
|
private ExpressionParser expressionParser; |
||||||
|
|
||||||
|
private String expression; |
||||||
|
|
||||||
|
private String var; |
||||||
|
|
||||||
|
private int scope = PageContext.PAGE_SCOPE; |
||||||
|
|
||||||
|
private boolean javaScriptEscape = false; |
||||||
|
|
||||||
|
/** |
||||||
|
* Set the expression to evaluate. |
||||||
|
*/ |
||||||
|
public void setExpression(String expression) { |
||||||
|
this.expression = expression; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set the variable name to expose the evaluation result under. |
||||||
|
* Defaults to rendering the result to the current JspWriter |
||||||
|
*/ |
||||||
|
public void setVar(String var) { |
||||||
|
this.var = var; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set the scope to export the evaluation result to. |
||||||
|
* This attribute has no meaning unless var is also defined. |
||||||
|
*/ |
||||||
|
public void setScope(String scope) { |
||||||
|
this.scope = TagUtils.getScope(scope); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set JavaScript escaping for this tag, as boolean value. |
||||||
|
* Default is "false". |
||||||
|
*/ |
||||||
|
public void setJavaScriptEscape(String javaScriptEscape) throws JspException { |
||||||
|
this.javaScriptEscape = |
||||||
|
ExpressionEvaluationUtils.evaluateBoolean("javaScriptEscape", javaScriptEscape, this.pageContext); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int doStartTagInternal() throws JspException { |
||||||
|
this.expressionParser = new SpelExpressionParser(); |
||||||
|
return EVAL_BODY_INCLUDE; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int doEndTag() throws JspException { |
||||||
|
Expression expression = this.expressionParser.parseExpression(this.expression); |
||||||
|
EvaluationContext context = createEvaluationContext(); |
||||||
|
if (this.var == null) { |
||||||
|
// print the url to the writer
|
||||||
|
try { |
||||||
|
String result = expression.getValue(context, String.class); |
||||||
|
result = isHtmlEscape() ? HtmlUtils.htmlEscape(result) : result; |
||||||
|
result = this.javaScriptEscape ? JavaScriptUtils.javaScriptEscape(result) : result; |
||||||
|
pageContext.getOut().print(result); |
||||||
|
} |
||||||
|
catch (IOException e) { |
||||||
|
throw new JspException(e); |
||||||
|
} |
||||||
|
} |
||||||
|
else { |
||||||
|
// store the url as a variable
|
||||||
|
pageContext.setAttribute(var, expression.getValue(context), scope); |
||||||
|
} |
||||||
|
return EVAL_PAGE; |
||||||
|
} |
||||||
|
|
||||||
|
private EvaluationContext createEvaluationContext() { |
||||||
|
StandardEvaluationContext context = new StandardEvaluationContext(); |
||||||
|
context.addPropertyAccessor(new JspPropertyAccessor(this.pageContext)); |
||||||
|
ConversionService conversionService = getConversionService(); |
||||||
|
if (conversionService != null) { |
||||||
|
context.setTypeConverter(new StandardTypeConverter()); |
||||||
|
} |
||||||
|
return context; |
||||||
|
} |
||||||
|
|
||||||
|
private ConversionService getConversionService() { |
||||||
|
try { |
||||||
|
// TODO replace this with a call to RequestContext that is not brittle
|
||||||
|
return getRequestContext().getWebApplicationContext().getBean("conversionService", ConversionService.class); |
||||||
|
} catch (BeansException e) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private static class JspPropertyAccessor implements PropertyAccessor { |
||||||
|
|
||||||
|
private PageContext pageContext; |
||||||
|
|
||||||
|
public JspPropertyAccessor(PageContext pageContext) { |
||||||
|
this.pageContext = pageContext; |
||||||
|
} |
||||||
|
|
||||||
|
public Class<?>[] getSpecificTargetClasses() { |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean canRead(EvaluationContext context, Object target, |
||||||
|
String name) throws AccessException { |
||||||
|
if (name.equals("pageContext")) { |
||||||
|
return true; |
||||||
|
} |
||||||
|
// TODO support all other JSP implicit variables defined at http://java.sun.com/javaee/6/docs/api/javax/servlet/jsp/el/ImplicitObjectELResolver.html
|
||||||
|
return this.pageContext.findAttribute(name) != null; |
||||||
|
} |
||||||
|
|
||||||
|
public TypedValue read(EvaluationContext context, Object target, |
||||||
|
String name) throws AccessException { |
||||||
|
if (name.equals("pageContext")) { |
||||||
|
return new TypedValue(this.pageContext); |
||||||
|
} |
||||||
|
// TODO support all other JSP implicit variables defined at http://java.sun.com/javaee/6/docs/api/javax/servlet/jsp/el/ImplicitObjectELResolver.html
|
||||||
|
return new TypedValue(this.pageContext.findAttribute(name)); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean canWrite(EvaluationContext context, Object target, |
||||||
|
String name) throws AccessException { |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
public void write(EvaluationContext context, Object target, |
||||||
|
String name, Object newValue) throws AccessException { |
||||||
|
throw new UnsupportedOperationException(); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,71 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2008 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.web.servlet.tags; |
||||||
|
|
||||||
|
import java.math.BigDecimal; |
||||||
|
|
||||||
|
import javax.servlet.jsp.tagext.Tag; |
||||||
|
|
||||||
|
import org.springframework.format.annotation.NumberFormat; |
||||||
|
import org.springframework.format.annotation.NumberFormat.Style; |
||||||
|
import org.springframework.mock.web.MockHttpServletResponse; |
||||||
|
import org.springframework.mock.web.MockPageContext; |
||||||
|
|
||||||
|
public class EvalTagTests extends AbstractTagTests { |
||||||
|
|
||||||
|
private EvalTag tag; |
||||||
|
|
||||||
|
private MockPageContext context; |
||||||
|
|
||||||
|
protected void setUp() throws Exception { |
||||||
|
context = createPageContext(); |
||||||
|
context.getRequest().setAttribute("bean", new Bean()); |
||||||
|
tag = new EvalTag(); |
||||||
|
tag.setPageContext(context); |
||||||
|
} |
||||||
|
|
||||||
|
public void testEndTagPrintScopedAttributeResult() throws Exception { |
||||||
|
tag.setExpression("bean.method()"); |
||||||
|
int action = tag.doStartTag(); |
||||||
|
assertEquals(Tag.EVAL_BODY_INCLUDE, action); |
||||||
|
action = tag.doEndTag(); |
||||||
|
assertEquals(Tag.EVAL_PAGE, action); |
||||||
|
assertEquals("foo", ((MockHttpServletResponse)context.getResponse()).getContentAsString()); |
||||||
|
} |
||||||
|
|
||||||
|
public void testEndTagPrintFormattedScopedAttributeResult() throws Exception { |
||||||
|
tag.setExpression("bean.formattable"); |
||||||
|
int action = tag.doStartTag(); |
||||||
|
assertEquals(Tag.EVAL_BODY_INCLUDE, action); |
||||||
|
action = tag.doEndTag(); |
||||||
|
assertEquals(Tag.EVAL_PAGE, action); |
||||||
|
// TODO - fails because EL does not consider annotations on getter/setter method or field for properties (just annotations on method parameters)
|
||||||
|
//assertEquals("25%", ((MockHttpServletResponse)context.getResponse()).getContentAsString());
|
||||||
|
} |
||||||
|
|
||||||
|
public static class Bean { |
||||||
|
|
||||||
|
public String method() { |
||||||
|
return "foo"; |
||||||
|
} |
||||||
|
|
||||||
|
@NumberFormat(style=Style.PERCENT) |
||||||
|
public BigDecimal getFormattable() { |
||||||
|
return new BigDecimal(".25"); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
Loading…
Reference in new issue