From 64fc4c23eaaba31a81cd7dd8fc708dad76f41d9a Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Tue, 16 Feb 2010 18:16:47 +0000 Subject: [PATCH] revised EvalTag implementation --- .../AnnotationDrivenBeanDefinitionParser.java | 4 +- ...ConversionServiceExposingInterceptor.java} | 26 +++--- .../web/servlet/tags/EvalTag.java | 87 +++++++++---------- .../servlet/tags/RequestContextAwareTag.java | 13 +-- .../web/servlet/config/MvcNamespaceTests.java | 22 ++--- .../web/servlet/tags/EvalTagTests.java | 8 +- 6 files changed, 81 insertions(+), 79 deletions(-) rename org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/handler/{ConversionServiceHandlerInterceptor.java => ConversionServiceExposingInterceptor.java} (65%) diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/AnnotationDrivenBeanDefinitionParser.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/AnnotationDrivenBeanDefinitionParser.java index 9b81b2a7606..d274a3a04f5 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/AnnotationDrivenBeanDefinitionParser.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/AnnotationDrivenBeanDefinitionParser.java @@ -38,7 +38,7 @@ 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.ConversionServiceExposingInterceptor; import org.springframework.web.servlet.handler.MappedInterceptor; import org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter; import org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping; @@ -112,7 +112,7 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser { annAdapterDef.getPropertyValues().add("messageConverters", getMessageConverters(source)); String annAdapterName = parserContext.getReaderContext().registerWithGeneratedName(annAdapterDef); - RootBeanDefinition csInterceptorDef = new RootBeanDefinition(ConversionServiceHandlerInterceptor.class); + RootBeanDefinition csInterceptorDef = new RootBeanDefinition(ConversionServiceExposingInterceptor.class); csInterceptorDef.setSource(source); csInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(0, conversionService); RootBeanDefinition mappedCsInterceptorDef = new RootBeanDefinition(MappedInterceptor.class); diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/handler/ConversionServiceHandlerInterceptor.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/handler/ConversionServiceExposingInterceptor.java similarity index 65% rename from org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/handler/ConversionServiceHandlerInterceptor.java rename to org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/handler/ConversionServiceExposingInterceptor.java index 2a72e4880ca..f32c255c01a 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/handler/ConversionServiceHandlerInterceptor.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/handler/ConversionServiceExposingInterceptor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2008 the original author or authors. + * Copyright 2002-2010 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. @@ -17,7 +17,6 @@ package org.springframework.web.servlet.handler; import java.io.IOException; - import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -26,28 +25,35 @@ 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(); + * Interceptor that places the configured {@link ConversionService} in request scope + * so it's available during request processing. The request attribute name is + * "org.springframework.core.convert.ConversionService", the value of + * ConversionService.class.getName(). + * + *

Mainly for use within JSP tags such as the spring:eval tag. + * * @author Keith Donald * @since 3.0.1 */ -public class ConversionServiceHandlerInterceptor extends HandlerInterceptorAdapter { +public class ConversionServiceExposingInterceptor 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. + * Creates a new {@link ConversionServiceExposingInterceptor}. + * @param conversionService the conversion service to export to request scope when this interceptor is invoked */ - public ConversionServiceHandlerInterceptor(ConversionService conversionService) { + public ConversionServiceExposingInterceptor(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) + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws ServletException, IOException { + request.setAttribute(ConversionService.class.getName(), this.conversionService); return true; } diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/EvalTag.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/EvalTag.java index 9f3f4ea2938..3a083c7516b 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/EvalTag.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/EvalTag.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2009 the original author or authors. + * Copyright 2002-2010 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. @@ -17,12 +17,9 @@ package org.springframework.web.servlet.tags; 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; import org.springframework.expression.AccessException; import org.springframework.expression.EvaluationContext; @@ -41,15 +38,17 @@ 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 final ExpressionParser expressionParser = new SpelExpressionParser(); + + private EvaluationContext evaluationContext; + + private Expression expression; private String var; @@ -57,11 +56,18 @@ public class EvalTag extends HtmlEscapingAwareTag { private boolean javaScriptEscape = false; + + @Override + public void setPageContext(PageContext pageContext) { + super.setPageContext(pageContext); + this.evaluationContext = createEvaluationContext(pageContext); + } + /** * Set the expression to evaluate. */ public void setExpression(String expression) { - this.expression = expression; + this.expression = this.expressionParser.parseExpression(expression); } /** @@ -89,55 +95,51 @@ public class EvalTag extends HtmlEscapingAwareTag { 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) { try { - String result = expression.getValue(context, String.class); + String result = this.expression.getValue(this.evaluationContext, 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); + catch (IOException ex) { + throw new JspException(ex); } } else { - Object result = expression.getValue(context); - pageContext.setAttribute(var, result, scope); + Object result = this.expression.getValue(this.evaluationContext); + pageContext.setAttribute(this.var, result, this.scope); } return EVAL_PAGE; } - - private EvaluationContext createEvaluationContext() { + + + private EvaluationContext createEvaluationContext(PageContext pageContext) { StandardEvaluationContext context = new StandardEvaluationContext(); - context.addPropertyAccessor(new JspPropertyAccessor(this.pageContext)); - ConversionService conversionService = getConversionService(); + context.addPropertyAccessor(new JspPropertyAccessor(pageContext)); + ConversionService conversionService = getConversionService(pageContext); if (conversionService != null) { context.setTypeConverter(new StandardTypeConverter(conversionService)); } return context; } - private ConversionService getConversionService() { - try { - return (ConversionService) this.pageContext.getRequest().getAttribute(ConversionService.class.getName()); - } catch (BeansException e) { - return null; - } + private ConversionService getConversionService(PageContext pageContext) { + return (ConversionService) pageContext.getRequest().getAttribute(ConversionService.class.getName()); } - + + private static class JspPropertyAccessor implements PropertyAccessor { - private PageContext pageContext; + private final PageContext pageContext; public JspPropertyAccessor(PageContext pageContext) { this.pageContext = pageContext; @@ -147,17 +149,11 @@ public class EvalTag extends HtmlEscapingAwareTag { return null; } - public boolean canRead(EvaluationContext context, Object target, - String name) throws AccessException { - Object implicitVar = resolveImplicitVariable(name); - if (implicitVar != null) { - return true; - } - return this.pageContext.findAttribute(name) != null; + public boolean canRead(EvaluationContext context, Object target, String name) throws AccessException { + return (resolveImplicitVariable(name) != null || this.pageContext.findAttribute(name) != null); } - public TypedValue read(EvaluationContext context, Object target, - String name) throws AccessException { + public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException { Object implicitVar = resolveImplicitVariable(name); if (implicitVar != null) { return new TypedValue(implicitVar); @@ -165,24 +161,23 @@ public class EvalTag extends HtmlEscapingAwareTag { return new TypedValue(this.pageContext.findAttribute(name)); } - public boolean canWrite(EvaluationContext context, Object target, - String name) throws AccessException { + public boolean canWrite(EvaluationContext context, Object target, String name) { return false; } - public void write(EvaluationContext context, Object target, - String name, Object newValue) throws AccessException { + public void write(EvaluationContext context, Object target, String name, Object newValue) { 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); + } + catch (Exception ex) { + throw new AccessException( + "Unexpected exception occurred accessing '" + name + "' as an implicit variable", ex); } } - } -} \ No newline at end of file +} diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/RequestContextAwareTag.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/RequestContextAwareTag.java index 261ad9e913e..63916231c73 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/RequestContextAwareTag.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/tags/RequestContextAwareTag.java @@ -1,12 +1,12 @@ /* - * Copyright 2002-2006 the original author or authors. - * + * Copyright 2002-2010 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. @@ -47,9 +47,10 @@ import org.springframework.web.servlet.support.RequestContext; */ public abstract class RequestContextAwareTag extends TagSupport implements TryCatchFinally { - /** {@link javax.servlet.jsp.PageContext} attribute for page-level + /** + * {@link javax.servlet.jsp.PageContext} attribute for page-level * {@link RequestContext} instance. - * */ + */ public static final String REQUEST_CONTEXT_PAGE_ATTRIBUTE = "org.springframework.web.servlet.tags.REQUEST_CONTEXT"; diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/MvcNamespaceTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/MvcNamespaceTests.java index 0c6ae697000..b0fb259ee1e 100644 --- a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/MvcNamespaceTests.java +++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/MvcNamespaceTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2009 the original author or authors. + * Copyright 2002-2010 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. @@ -53,7 +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.ConversionServiceExposingInterceptor; import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping; import org.springframework.web.servlet.handler.WebRequestHandlerInterceptorAdapter; import org.springframework.web.servlet.i18n.LocaleChangeInterceptor; @@ -115,8 +115,8 @@ public class MvcNamespaceTests { HandlerExecutionChain chain = mapping.getHandler(request); assertEquals(2, chain.getInterceptors().length); - assertTrue(chain.getInterceptors()[1] instanceof ConversionServiceHandlerInterceptor); - ConversionServiceHandlerInterceptor interceptor = (ConversionServiceHandlerInterceptor) chain.getInterceptors()[1]; + assertTrue(chain.getInterceptors()[1] instanceof ConversionServiceExposingInterceptor); + ConversionServiceExposingInterceptor interceptor = (ConversionServiceExposingInterceptor) chain.getInterceptors()[1]; interceptor.preHandle(request, response, handler); assertSame(appContext.getBean(ConversionService.class), request.getAttribute(ConversionService.class.getName())); @@ -144,8 +144,8 @@ public class MvcNamespaceTests { HandlerExecutionChain chain = mapping.getHandler(request); assertEquals(2, chain.getInterceptors().length); - assertTrue(chain.getInterceptors()[1] instanceof ConversionServiceHandlerInterceptor); - ConversionServiceHandlerInterceptor interceptor = (ConversionServiceHandlerInterceptor) chain.getInterceptors()[1]; + assertTrue(chain.getInterceptors()[1] instanceof ConversionServiceExposingInterceptor); + ConversionServiceExposingInterceptor interceptor = (ConversionServiceExposingInterceptor) chain.getInterceptors()[1]; interceptor.preHandle(request, response, handler); assertSame(appContext.getBean("conversionService"), request.getAttribute(ConversionService.class.getName())); @@ -194,7 +194,7 @@ public class MvcNamespaceTests { HandlerExecutionChain chain = mapping.getHandler(request); assertEquals(4, chain.getInterceptors().length); - assertTrue(chain.getInterceptors()[1] instanceof ConversionServiceHandlerInterceptor); + assertTrue(chain.getInterceptors()[1] instanceof ConversionServiceExposingInterceptor); assertTrue(chain.getInterceptors()[2] instanceof LocaleChangeInterceptor); assertTrue(chain.getInterceptors()[3] instanceof ThemeChangeInterceptor); @@ -225,7 +225,7 @@ public class MvcNamespaceTests { HandlerExecutionChain chain = mapping.getHandler(request); assertEquals(4, chain.getInterceptors().length); - assertTrue(chain.getInterceptors()[1] instanceof ConversionServiceHandlerInterceptor); + assertTrue(chain.getInterceptors()[1] instanceof ConversionServiceExposingInterceptor); assertTrue(chain.getInterceptors()[2] instanceof LocaleChangeInterceptor); assertTrue(chain.getInterceptors()[3] instanceof ThemeChangeInterceptor); LocaleChangeInterceptor interceptor = (LocaleChangeInterceptor) chain.getInterceptors()[2]; @@ -249,7 +249,7 @@ public class MvcNamespaceTests { HandlerExecutionChain chain = mapping.getHandler(request); assertEquals(4, chain.getInterceptors().length); - assertTrue(chain.getInterceptors()[1] instanceof ConversionServiceHandlerInterceptor); + assertTrue(chain.getInterceptors()[1] instanceof ConversionServiceExposingInterceptor); assertTrue(chain.getInterceptors()[2] instanceof LocaleChangeInterceptor); assertTrue(chain.getInterceptors()[3] instanceof ThemeChangeInterceptor); @@ -263,7 +263,7 @@ public class MvcNamespaceTests { request.setMethod("GET"); chain = mapping2.getHandler(request); assertEquals(4, chain.getInterceptors().length); - assertTrue(chain.getInterceptors()[1] instanceof ConversionServiceHandlerInterceptor); + assertTrue(chain.getInterceptors()[1] instanceof ConversionServiceExposingInterceptor); assertTrue(chain.getInterceptors()[2] instanceof LocaleChangeInterceptor); assertTrue(chain.getInterceptors()[3] instanceof ThemeChangeInterceptor); ModelAndView mv = adapter.handle(request, new MockHttpServletResponse(), chain.getHandler()); @@ -272,7 +272,7 @@ public class MvcNamespaceTests { request.setRequestURI("/bar"); chain = mapping2.getHandler(request); assertEquals(4, chain.getInterceptors().length); - assertTrue(chain.getInterceptors()[1] instanceof ConversionServiceHandlerInterceptor); + assertTrue(chain.getInterceptors()[1] instanceof ConversionServiceExposingInterceptor); assertTrue(chain.getInterceptors()[2] instanceof LocaleChangeInterceptor); assertTrue(chain.getInterceptors()[3] instanceof ThemeChangeInterceptor); ModelAndView mv2 = adapter.handle(request, new MockHttpServletResponse(), chain.getHandler()); diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/tags/EvalTagTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/tags/EvalTagTests.java index 3b0bd2dcc33..e3d404ebd09 100644 --- a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/tags/EvalTagTests.java +++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/tags/EvalTagTests.java @@ -1,12 +1,12 @@ /* - * Copyright 2008 the original author or authors. - * + * Copyright 2002-2010 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.