spring:eval tag initial commit
This commit is contained in:
parent
16aa399040
commit
f23b55dc13
|
|
@ -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,6 +121,9 @@ 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);
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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>
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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