eval tag tidying

This commit is contained in:
Keith Donald 2010-02-12 17:42:41 +00:00
parent 117b138233
commit 6390e897b8
6 changed files with 205 additions and 50 deletions

View File

@ -38,6 +38,8 @@ import org.springframework.util.ClassUtils;
import org.springframework.validation.Validator;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import org.springframework.web.bind.support.ConfigurableWebBindingInitializer;
import org.springframework.web.servlet.handler.ConversionServiceHandlerInterceptor;
import org.springframework.web.servlet.handler.MappedInterceptor;
import org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter;
import org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping;
@ -94,28 +96,42 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
annMappingDef.getPropertyValues().add("order", 0);
String annMappingName = parserContext.getReaderContext().registerWithGeneratedName(annMappingDef);
RuntimeBeanReference conversionService = getConversionService(element, source, parserContext);
RuntimeBeanReference validator = getValidator(element, source, parserContext);
RootBeanDefinition bindingDef = new RootBeanDefinition(ConfigurableWebBindingInitializer.class);
bindingDef.setSource(source);
bindingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
bindingDef.getPropertyValues().add("conversionService", getConversionService(element, source, parserContext));
bindingDef.getPropertyValues().add("validator", getValidator(element, source, parserContext));
bindingDef.getPropertyValues().add("conversionService", conversionService);
bindingDef.getPropertyValues().add("validator", validator);
RootBeanDefinition annAdapterDef = new RootBeanDefinition(AnnotationMethodHandlerAdapter.class);
annAdapterDef.setSource(source);
annAdapterDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
annAdapterDef.getPropertyValues().add("webBindingInitializer", bindingDef);
annAdapterDef.getPropertyValues().add("messageConverters", getMessageConverters(source));
String adapterName = parserContext.getReaderContext().registerWithGeneratedName(annAdapterDef);
String annAdapterName = parserContext.getReaderContext().registerWithGeneratedName(annAdapterDef);
RootBeanDefinition csInterceptorDef = new RootBeanDefinition(ConversionServiceHandlerInterceptor.class);
csInterceptorDef.setSource(source);
csInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(0, conversionService);
RootBeanDefinition mappedCsInterceptorDef = new RootBeanDefinition(MappedInterceptor.class);
mappedCsInterceptorDef.setSource(source);
mappedCsInterceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
mappedCsInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(0, (Object) null);
mappedCsInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(1, csInterceptorDef);
String mappedInterceptorName = parserContext.getReaderContext().registerWithGeneratedName(mappedCsInterceptorDef);
parserContext.registerComponent(new BeanComponentDefinition(annMappingDef, annMappingName));
parserContext.registerComponent(new BeanComponentDefinition(annAdapterDef, adapterName));
parserContext.registerComponent(new BeanComponentDefinition(annAdapterDef, annAdapterName));
parserContext.registerComponent(new BeanComponentDefinition(mappedCsInterceptorDef, mappedInterceptorName));
parserContext.popAndRegisterContainingComponent();
return null;
}
private Object getConversionService(Element element, Object source, ParserContext parserContext) {
private RuntimeBeanReference getConversionService(Element element, Object source, ParserContext parserContext) {
if (element.hasAttribute("conversion-service")) {
return new RuntimeBeanReference(element.getAttribute("conversion-service"));
}
@ -129,7 +145,7 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
}
}
private Object getValidator(Element element, Object source, ParserContext parserContext) {
private RuntimeBeanReference getValidator(Element element, Object source, ParserContext parserContext) {
if (element.hasAttribute("validator")) {
return new RuntimeBeanReference(element.getAttribute("validator"));
}

View File

@ -0,0 +1,55 @@
/*
* Copyright 2002-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.handler;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.core.convert.ConversionService;
import org.springframework.util.Assert;
/**
* Interceptor that places the configured {@link ConversionService} in request scope so it's available during request processing.
* Mainly for use within JSP tags such as the spring:eval tag.
* The request attribute name is "org.springframework.core.convert.ConversionService", the value of ConversionService.class.getName();
* @author Keith Donald
* @since 3.0.1
*/
public class ConversionServiceHandlerInterceptor extends HandlerInterceptorAdapter {
private final ConversionService conversionService;
/**
* Creates a new {@link ConversionServiceHandlerInterceptor}.
* @param conversionService the conversion service to export to request scope when this interceptor is invoked.
*/
public ConversionServiceHandlerInterceptor(ConversionService conversionService) {
Assert.notNull(conversionService, "The ConversionService may not be null");
this.conversionService = conversionService;
}
@Override
public final boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws ServletException, IOException {
request.setAttribute(ConversionService.class.getName(), this.conversionService);
return true;
}
}

View File

@ -20,6 +20,7 @@ import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.el.ELException;
import org.springframework.beans.BeansException;
import org.springframework.core.convert.ConversionService;
@ -110,7 +111,8 @@ public class EvalTag extends HtmlEscapingAwareTag {
}
}
else {
pageContext.setAttribute(var, expression.getValue(context), scope);
Object result = expression.getValue(context);
pageContext.setAttribute(var, result, scope);
}
return EVAL_PAGE;
}
@ -127,7 +129,7 @@ public class EvalTag extends HtmlEscapingAwareTag {
private ConversionService getConversionService() {
try {
return (ConversionService) this.pageContext.getRequest().getAttribute("org.springframework.core.convert.ConversionService");
return (ConversionService) this.pageContext.getRequest().getAttribute(ConversionService.class.getName());
} catch (BeansException e) {
return null;
}
@ -147,19 +149,19 @@ public class EvalTag extends HtmlEscapingAwareTag {
public boolean canRead(EvaluationContext context, Object target,
String name) throws AccessException {
if (name.equals("pageContext")) {
Object implicitVar = resolveImplicitVariable(name);
if (implicitVar != null) {
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);
Object implicitVar = resolveImplicitVariable(name);
if (implicitVar != null) {
return new TypedValue(implicitVar);
}
// 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));
}
@ -173,6 +175,14 @@ public class EvalTag extends HtmlEscapingAwareTag {
throw new UnsupportedOperationException();
}
private Object resolveImplicitVariable(String name) throws AccessException {
try {
return this.pageContext.getVariableResolver().resolveVariable(name);
} catch (ELException e) {
throw new AccessException("Unexpected exception occurred accessing '" + name + "' as an implicit variable", e);
}
}
}
}

View File

@ -294,7 +294,15 @@ public class MockPageContext extends PageContext {
}
public VariableResolver getVariableResolver() {
return null;
return new VariableResolver() {
public Object resolveVariable(String pName) throws ELException {
if (pName.equals("pageContext")) {
return this;
} else {
return null;
}
}
};
}
public HttpSession getSession() {

View File

@ -53,6 +53,7 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.context.support.GenericWebApplicationContext;
import org.springframework.web.servlet.HandlerExecutionChain;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.ConversionServiceHandlerInterceptor;
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
import org.springframework.web.servlet.handler.WebRequestHandlerInterceptorAdapter;
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
@ -80,17 +81,19 @@ public class MvcNamespaceTests {
public void testDefaultConfig() throws Exception {
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(appContext);
reader.loadBeanDefinitions(new ClassPathResource("mvc-config.xml", getClass()));
assertEquals(4, appContext.getBeanDefinitionCount());
assertEquals(5, appContext.getBeanDefinitionCount());
appContext.refresh();
DefaultAnnotationHandlerMapping mapping = appContext.getBean(DefaultAnnotationHandlerMapping.class);
assertNotNull(mapping);
assertEquals(0, mapping.getOrder());
TestController handler = new TestController();
mapping.setDefaultHandler(handler);
AnnotationMethodHandlerAdapter adapter = appContext.getBean(AnnotationMethodHandlerAdapter.class);
assertNotNull(adapter);
HttpMessageConverter[] messageConverters = adapter.getMessageConverters();
HttpMessageConverter<?>[] messageConverters = adapter.getMessageConverters();
assertNotNull(messageConverters);
assertEquals(6, messageConverters.length);
assertTrue(ByteArrayHttpMessageConverter.class.equals(messageConverters[0].getClass()));
@ -105,12 +108,18 @@ public class MvcNamespaceTests {
assertNotNull(appContext.getBean(LocalValidatorFactoryBean.class));
assertNotNull(appContext.getBean(Validator.class));
TestController handler = new TestController();
// default web binding initializer behavior test
MockHttpServletRequest request = new MockHttpServletRequest();
request.addParameter("date", "2009-10-31");
MockHttpServletResponse response = new MockHttpServletResponse();
HandlerExecutionChain chain = mapping.getHandler(request);
assertEquals(2, chain.getInterceptors().length);
assertTrue(chain.getInterceptors()[1] instanceof ConversionServiceHandlerInterceptor);
ConversionServiceHandlerInterceptor interceptor = (ConversionServiceHandlerInterceptor) chain.getInterceptors()[1];
interceptor.preHandle(request, response, handler);
assertSame(appContext.getBean(ConversionService.class), request.getAttribute(ConversionService.class.getName()));
adapter.handle(request, response, handler);
assertTrue(handler.recordedValidationError);
}
@ -119,18 +128,29 @@ public class MvcNamespaceTests {
public void testCustomConversionService() throws Exception {
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(appContext);
reader.loadBeanDefinitions(new ClassPathResource("mvc-config-custom-conversion-service.xml", getClass()));
assertEquals(4, appContext.getBeanDefinitionCount());
assertEquals(5, appContext.getBeanDefinitionCount());
appContext.refresh();
AnnotationMethodHandlerAdapter adapter = appContext.getBean(AnnotationMethodHandlerAdapter.class);
assertNotNull(adapter);
DefaultAnnotationHandlerMapping mapping = appContext.getBean(DefaultAnnotationHandlerMapping.class);
assertNotNull(mapping);
TestController handler = new TestController();
mapping.setDefaultHandler(handler);
// default web binding initializer behavior test
MockHttpServletRequest request = new MockHttpServletRequest();
request.setRequestURI("/accounts/12345");
request.addParameter("date", "2009-10-31");
MockHttpServletResponse response = new MockHttpServletResponse();
HandlerExecutionChain chain = mapping.getHandler(request);
assertEquals(2, chain.getInterceptors().length);
assertTrue(chain.getInterceptors()[1] instanceof ConversionServiceHandlerInterceptor);
ConversionServiceHandlerInterceptor interceptor = (ConversionServiceHandlerInterceptor) chain.getInterceptors()[1];
interceptor.preHandle(request, response, handler);
assertSame(appContext.getBean("conversionService"), request.getAttribute(ConversionService.class.getName()));
AnnotationMethodHandlerAdapter adapter = appContext.getBean(AnnotationMethodHandlerAdapter.class);
assertNotNull(adapter);
adapter.handle(request, response, handler);
}
@ -138,7 +158,7 @@ public class MvcNamespaceTests {
public void testCustomValidator() throws Exception {
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(appContext);
reader.loadBeanDefinitions(new ClassPathResource("mvc-config-custom-validator.xml", getClass()));
assertEquals(4, appContext.getBeanDefinitionCount());
assertEquals(5, appContext.getBeanDefinitionCount());
appContext.refresh();
AnnotationMethodHandlerAdapter adapter = appContext.getBean(AnnotationMethodHandlerAdapter.class);
@ -160,7 +180,7 @@ public class MvcNamespaceTests {
public void testInterceptors() throws Exception {
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(appContext);
reader.loadBeanDefinitions(new ClassPathResource("mvc-config-interceptors.xml", getClass()));
assertEquals(7, appContext.getBeanDefinitionCount());
assertEquals(8, appContext.getBeanDefinitionCount());
appContext.refresh();
DefaultAnnotationHandlerMapping mapping = appContext.getBean(DefaultAnnotationHandlerMapping.class);
@ -173,19 +193,20 @@ public class MvcNamespaceTests {
request.addParameter("theme", "green");
HandlerExecutionChain chain = mapping.getHandler(request);
assertEquals(3, chain.getInterceptors().length);
assertTrue(chain.getInterceptors()[1] instanceof LocaleChangeInterceptor);
assertTrue(chain.getInterceptors()[2] instanceof ThemeChangeInterceptor);
assertEquals(4, chain.getInterceptors().length);
assertTrue(chain.getInterceptors()[1] instanceof ConversionServiceHandlerInterceptor);
assertTrue(chain.getInterceptors()[2] instanceof LocaleChangeInterceptor);
assertTrue(chain.getInterceptors()[3] instanceof ThemeChangeInterceptor);
request.setRequestURI("/logged/accounts/12345");
chain = mapping.getHandler(request);
assertEquals(4, chain.getInterceptors().length);
assertTrue(chain.getInterceptors()[3] instanceof WebRequestHandlerInterceptorAdapter);
assertEquals(5, chain.getInterceptors().length);
assertTrue(chain.getInterceptors()[4] instanceof WebRequestHandlerInterceptorAdapter);
request.setRequestURI("/foo/logged");
chain = mapping.getHandler(request);
assertEquals(4, chain.getInterceptors().length);
assertTrue(chain.getInterceptors()[3] instanceof WebRequestHandlerInterceptorAdapter);
assertEquals(5, chain.getInterceptors().length);
assertTrue(chain.getInterceptors()[4] instanceof WebRequestHandlerInterceptorAdapter);
}
@ -193,7 +214,7 @@ public class MvcNamespaceTests {
public void testBeanDecoration() throws Exception {
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(appContext);
reader.loadBeanDefinitions(new ClassPathResource("mvc-config-bean-decoration.xml", getClass()));
assertEquals(6, appContext.getBeanDefinitionCount());
assertEquals(7, appContext.getBeanDefinitionCount());
appContext.refresh();
DefaultAnnotationHandlerMapping mapping = appContext.getBean(DefaultAnnotationHandlerMapping.class);
@ -203,11 +224,13 @@ public class MvcNamespaceTests {
MockHttpServletRequest request = new MockHttpServletRequest();
HandlerExecutionChain chain = mapping.getHandler(request);
assertEquals(3, chain.getInterceptors().length);
assertTrue(chain.getInterceptors()[1] instanceof LocaleChangeInterceptor);
LocaleChangeInterceptor interceptor = (LocaleChangeInterceptor) chain.getInterceptors()[1];
assertEquals(4, chain.getInterceptors().length);
assertTrue(chain.getInterceptors()[1] instanceof ConversionServiceHandlerInterceptor);
assertTrue(chain.getInterceptors()[2] instanceof LocaleChangeInterceptor);
assertTrue(chain.getInterceptors()[3] instanceof ThemeChangeInterceptor);
LocaleChangeInterceptor interceptor = (LocaleChangeInterceptor) chain.getInterceptors()[2];
assertEquals("lang", interceptor.getParamName());
ThemeChangeInterceptor interceptor2 = (ThemeChangeInterceptor) chain.getInterceptors()[2];
ThemeChangeInterceptor interceptor2 = (ThemeChangeInterceptor) chain.getInterceptors()[3];
assertEquals("style", interceptor2.getParamName());
}
@ -215,7 +238,7 @@ public class MvcNamespaceTests {
public void testViewControllers() throws Exception {
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(appContext);
reader.loadBeanDefinitions(new ClassPathResource("mvc-config-view-controllers.xml", getClass()));
assertEquals(8, appContext.getBeanDefinitionCount());
assertEquals(9, appContext.getBeanDefinitionCount());
appContext.refresh();
DefaultAnnotationHandlerMapping mapping = appContext.getBean(DefaultAnnotationHandlerMapping.class);
@ -225,8 +248,10 @@ public class MvcNamespaceTests {
MockHttpServletRequest request = new MockHttpServletRequest();
HandlerExecutionChain chain = mapping.getHandler(request);
assertEquals(3, chain.getInterceptors().length);
assertTrue(chain.getInterceptors()[1] instanceof LocaleChangeInterceptor);
assertEquals(4, chain.getInterceptors().length);
assertTrue(chain.getInterceptors()[1] instanceof ConversionServiceHandlerInterceptor);
assertTrue(chain.getInterceptors()[2] instanceof LocaleChangeInterceptor);
assertTrue(chain.getInterceptors()[3] instanceof ThemeChangeInterceptor);
SimpleUrlHandlerMapping mapping2 = appContext.getBean(SimpleUrlHandlerMapping.class);
assertNotNull(mapping2);
@ -237,15 +262,19 @@ public class MvcNamespaceTests {
request.setRequestURI("/foo");
request.setMethod("GET");
chain = mapping2.getHandler(request);
assertEquals(3, chain.getInterceptors().length);
assertTrue(chain.getInterceptors()[1] instanceof LocaleChangeInterceptor);
assertEquals(4, chain.getInterceptors().length);
assertTrue(chain.getInterceptors()[1] instanceof ConversionServiceHandlerInterceptor);
assertTrue(chain.getInterceptors()[2] instanceof LocaleChangeInterceptor);
assertTrue(chain.getInterceptors()[3] instanceof ThemeChangeInterceptor);
ModelAndView mv = adapter.handle(request, new MockHttpServletResponse(), chain.getHandler());
assertNull(mv.getViewName());
request.setRequestURI("/bar");
chain = mapping2.getHandler(request);
assertEquals(3, chain.getInterceptors().length);
assertTrue(chain.getInterceptors()[1] instanceof LocaleChangeInterceptor);
assertEquals(4, chain.getInterceptors().length);
assertTrue(chain.getInterceptors()[1] instanceof ConversionServiceHandlerInterceptor);
assertTrue(chain.getInterceptors()[2] instanceof LocaleChangeInterceptor);
assertTrue(chain.getInterceptors()[3] instanceof ThemeChangeInterceptor);
ModelAndView mv2 = adapter.handle(request, new MockHttpServletResponse(), chain.getHandler());
assertEquals("baz", mv2.getViewName());
}

View File

@ -42,7 +42,7 @@ public class EvalTagTests extends AbstractTagTests {
tag.setPageContext(context);
}
public void testEndTagPrintScopedAttributeResult() throws Exception {
public void testPrintScopedAttributeResult() throws Exception {
tag.setExpression("bean.method()");
int action = tag.doStartTag();
assertEquals(Tag.EVAL_BODY_INCLUDE, action);
@ -51,14 +51,43 @@ public class EvalTagTests extends AbstractTagTests {
assertEquals("foo", ((MockHttpServletResponse)context.getResponse()).getContentAsString());
}
public void testEndTagPrintFormattedScopedAttributeResult() throws Exception {
public void testPrintFormattedScopedAttributeResult() throws Exception {
tag.setExpression("bean.formattable");
int action = tag.doStartTag();
assertEquals(Tag.EVAL_BODY_INCLUDE, action);
action = tag.doEndTag();
assertEquals(Tag.EVAL_PAGE, action);
assertEquals("25%", ((MockHttpServletResponse) context.getResponse())
.getContentAsString());
assertEquals("25%", ((MockHttpServletResponse) context.getResponse()).getContentAsString());
}
public void testPrintHtmlEscapedAttributeResult() throws Exception {
tag.setExpression("bean.html()");
tag.setHtmlEscape("true");
int action = tag.doStartTag();
assertEquals(Tag.EVAL_BODY_INCLUDE, action);
action = tag.doEndTag();
assertEquals(Tag.EVAL_PAGE, action);
assertEquals("&lt;p&gt;", ((MockHttpServletResponse)context.getResponse()).getContentAsString());
}
public void testPrintJavaScriptEscapedAttributeResult() throws Exception {
tag.setExpression("bean.js()");
tag.setJavaScriptEscape("true");
int action = tag.doStartTag();
assertEquals(Tag.EVAL_BODY_INCLUDE, action);
action = tag.doEndTag();
assertEquals(Tag.EVAL_PAGE, action);
assertEquals("function foo() { alert(\\\"hi\\\") }", ((MockHttpServletResponse)context.getResponse()).getContentAsString());
}
public void testSetFormattedScopedAttributeResult() throws Exception {
tag.setExpression("bean.formattable");
tag.setVar("foo");
int action = tag.doStartTag();
assertEquals(Tag.EVAL_BODY_INCLUDE, action);
action = tag.doEndTag();
assertEquals(Tag.EVAL_PAGE, action);
assertEquals(new BigDecimal(".25"), context.getAttribute("foo"));
}
public static class Bean {
@ -71,5 +100,13 @@ public class EvalTagTests extends AbstractTagTests {
public BigDecimal getFormattable() {
return new BigDecimal(".25");
}
public String html() {
return "<p>";
}
public String js() {
return "function foo() { alert(\"hi\") }";
}
}
}