提交 f23b55dc 编写于 作者: K Keith Donald

spring:eval tag initial commit

上级 16aa3990
......@@ -439,16 +439,17 @@ public class TypeDescriptor {
public String toString() {
if (this == TypeDescriptor.NULL) {
return "TypeDescriptor.NULL";
return "[TypeDescriptor.NULL]";
}
else {
StringBuilder builder = new StringBuilder();
builder.append("TypeDescriptor ");
builder.append("[TypeDescriptor ");
Annotation[] anns = getAnnotations();
for (Annotation ann : anns) {
builder.append("@").append(ann.annotationType().getName()).append(' ');
}
builder.append(ClassUtils.getQualifiedName(getType()));
builder.append("]");
return builder.toString();
}
}
......
......@@ -28,7 +28,6 @@ import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.GenericTypeResolver;
import org.springframework.core.convert.ConversionFailedException;
import org.springframework.core.convert.ConversionService;
......@@ -39,6 +38,7 @@ import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.converter.ConverterFactory;
import org.springframework.core.convert.converter.ConverterRegistry;
import org.springframework.core.convert.converter.GenericConverter;
import org.springframework.core.style.StylerUtils;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
......@@ -121,9 +121,12 @@ public class GenericConversionService implements ConversionService, ConverterReg
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
assertNotNull(sourceType, targetType);
if (logger.isDebugEnabled()) {
logger.debug("Converting value " + StylerUtils.style(source) +" of " + sourceType + " to " + targetType);
}
if (sourceType == TypeDescriptor.NULL) {
Assert.isTrue(source == null, "The source must be null if sourceType == TypeDescriptor.NULL");
return convertNullSource(sourceType, targetType);
return convertNullSource(sourceType, targetType);
}
if (targetType == TypeDescriptor.NULL) {
return null;
......
......@@ -50,5 +50,6 @@
<classpathentry kind="var" path="IVY_CACHE/javax.validation/com.springsource.javax.validation/1.0.0.GA/com.springsource.javax.validation-1.0.0.GA.jar" sourcepath="/IVY_CACHE/javax.validation/com.springsource.javax.validation/1.0.0/com.springsource.javax.validation-sources-1.0.0.GA.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.slf4j/com.springsource.slf4j.jcl/1.5.3/com.springsource.slf4j.jcl-1.5.3.jar" sourcepath="/IVY_CACHE/org.slf4j/com.springsource.slf4j.jcl/1.5.3/com.springsource.slf4j.jcl-sources-1.5.3.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.slf4j/com.springsource.slf4j.api/1.5.3/com.springsource.slf4j.api-1.5.3.jar" sourcepath="/IVY_CACHE/org.slf4j/com.springsource.slf4j.api/1.5.3/com.springsource.slf4j.api-sources-1.5.3.jar"/>
<classpathentry combineaccessrules="false" kind="src" path="/org.springframework.expression"/>
<classpathentry kind="output" path="target/classes"/>
</classpath>
......@@ -72,6 +72,8 @@
conf="optional, velocity, freemarker, jasper-reports->compile"/>
<dependency org="org.springframework" name="org.springframework.core" rev="latest.integration"
conf="compile->compile"/>
<dependency org="org.springframework" name="org.springframework.expression" rev="latest.integration"
conf="compile->compile"/>
<dependency org="org.springframework" name="org.springframework.oxm" rev="latest.integration"
conf="optional, oxm->compile"/>
<dependency org="org.springframework" name="org.springframework.web" rev="latest.integration"
......
/*
* 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();
}
}
}
\ No newline at end of file
......@@ -358,8 +358,8 @@
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<description>Specifies a remote application context. The default is the
current application context.</description>
<description>Specifies a remote application context path. The default is the
current application context path.</description>
<name>context</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
......@@ -414,4 +414,44 @@
</attribute>
</tag>
<tag>
<description>Evaluates a Spring expression (SpEL) and either prints the result or assigns it to a variable.</description>
<name>eval</name>
<tag-class>org.springframework.web.servlet.tags.EvalTag</tag-class>
<body-content>JSP</body-content>
<attribute>
<description>The expression to evaluate.</description>
<name>expression</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<description>The name of the variable to export the evaluation result to.</description>
<name>var</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<description>The scope for the var. 'application', 'session', 'request' and
'page' scopes are supported. Defaults to page scope. This attribute has no
effect unless the var attribute is also defined.</description>
<name>scope</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<description>Set HTML escaping for this tag, as boolean value. Overrides the
default HTML escaping setting for the current page.</description>
<name>htmlEscape</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<description>Set JavaScript escaping for this tag, as boolean value. Default is false.</description>
<name>javaScriptEscape</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
</taglib>
\ No newline at end of file
......@@ -16,17 +16,13 @@
package org.springframework.web.servlet.tags;
import java.io.StringWriter;
import javax.servlet.jsp.JspWriter;
import junit.framework.TestCase;
import org.springframework.mock.web.MockBodyContent;
import org.springframework.format.support.FormattingConversionServiceFactoryBean;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.mock.web.MockPageContext;
import org.springframework.mock.web.MockServletContext;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.LocaleResolver;
......@@ -48,6 +44,8 @@ public abstract class AbstractTagTests extends TestCase {
SimpleWebApplicationContext wac = new SimpleWebApplicationContext();
wac.setServletContext(sc);
wac.setNamespace("test");
// TODO this name index leads to brittle lookup by EvalTag
wac.registerSingleton("conversionService", FormattingConversionServiceFactoryBean.class);
wac.refresh();
MockHttpServletRequest request = new MockHttpServletRequest(sc);
......
/*
* 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");
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册