diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapter.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapter.java index d8e839ffc7..af3f5c3621 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapter.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapter.java @@ -50,8 +50,10 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.SessionAttributes; import org.springframework.web.bind.support.DefaultDataBinderFactory; import org.springframework.web.bind.support.DefaultSessionAttributeStore; +import org.springframework.web.bind.support.FlashStatus; import org.springframework.web.bind.support.SessionAttributeStore; import org.springframework.web.bind.support.SessionStatus; +import org.springframework.web.bind.support.SimpleFlashStatus; import org.springframework.web.bind.support.SimpleSessionStatus; import org.springframework.web.bind.support.WebBindingInitializer; import org.springframework.web.bind.support.WebDataBinderFactory; @@ -59,6 +61,7 @@ import org.springframework.web.context.request.ServletWebRequest; import org.springframework.web.context.request.WebRequest; import org.springframework.web.method.HandlerMethod; import org.springframework.web.method.HandlerMethodSelector; +import org.springframework.web.method.annotation.FlashAttributesHandler; import org.springframework.web.method.annotation.ModelFactory; import org.springframework.web.method.annotation.SessionAttributesHandler; import org.springframework.web.method.annotation.support.ErrorsMethodArgumentResolver; @@ -146,6 +149,9 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter i private final Map, SessionAttributesHandler> sessionAttributesHandlerCache = new ConcurrentHashMap, SessionAttributesHandler>(); + private final Map, FlashAttributesHandler> flashAttributesHandlerCache = + new ConcurrentHashMap, FlashAttributesHandler>(); + private HandlerMethodArgumentResolverComposite argumentResolvers; private HandlerMethodArgumentResolverComposite initBinderArgumentResolvers; @@ -481,19 +487,27 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter i } /** - * Whether the given handler type defines any handler-specific session attributes via {@link SessionAttributes}. - * Also initializes the sessionAttributesHandlerCache for the given handler type. + * Whether the given handler type defines any handler-specific session attributes + * via {@link SessionAttributes}. */ private boolean hasSessionAttributes(Class handlerType) { - SessionAttributesHandler handler = null; + SessionAttributesHandler sessionAttrsHandler = null; synchronized(this.sessionAttributesHandlerCache) { - handler = this.sessionAttributesHandlerCache.get(handlerType); - if (handler == null) { - handler = new SessionAttributesHandler(handlerType, sessionAttributeStore); - this.sessionAttributesHandlerCache.put(handlerType, handler); + sessionAttrsHandler = this.sessionAttributesHandlerCache.get(handlerType); + if (sessionAttrsHandler == null) { + sessionAttrsHandler = new SessionAttributesHandler(handlerType, sessionAttributeStore); + this.sessionAttributesHandlerCache.put(handlerType, sessionAttrsHandler); + } + } + FlashAttributesHandler flashAttrsHandler = null; + synchronized(this.flashAttributesHandlerCache) { + flashAttrsHandler = this.flashAttributesHandlerCache.get(handlerType); + if (flashAttrsHandler == null) { + flashAttrsHandler = new FlashAttributesHandler(handlerType); + this.flashAttributesHandlerCache.put(handlerType, flashAttrsHandler); } } - return handler.hasSessionAttributes(); + return sessionAttrsHandler.hasSessionAttributes() || flashAttrsHandler.hasFlashAttributes(); } /** @@ -509,12 +523,13 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter i ServletWebRequest webRequest = new ServletWebRequest(request, response); SessionStatus sessionStatus = new SimpleSessionStatus(); + FlashStatus flashStatus = new SimpleFlashStatus(); ModelAndViewContainer mavContainer = new ModelAndViewContainer(); modelFactory.initModel(webRequest, mavContainer, requestMethod); - requestMethod.invokeAndHandle(webRequest, mavContainer, sessionStatus); - modelFactory.updateModel(webRequest, mavContainer, sessionStatus); + requestMethod.invokeAndHandle(webRequest, mavContainer, sessionStatus, flashStatus); + modelFactory.updateModel(webRequest, mavContainer, sessionStatus, flashStatus); if (!mavContainer.isResolveView()) { return null; @@ -569,7 +584,10 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter i modelAttrMethods.add(attrMethod); } - return new ModelFactory(modelAttrMethods, binderFactory, sessionAttributesHandlerCache.get(handlerType)); + SessionAttributesHandler sessionAttrsHandler = sessionAttributesHandlerCache.get(handlerType); + FlashAttributesHandler flashAttrsHandler = flashAttributesHandlerCache.get(handlerType); + + return new ModelFactory(modelAttrMethods, binderFactory, sessionAttrsHandler, flashAttrsHandler); } private ServletInvocableHandlerMethod createRequestMappingMethod(HandlerMethod handlerMethod, diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/AbstractServletHandlerMethodTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/AbstractServletHandlerMethodTests.java new file mode 100644 index 0000000000..07eac6d8c2 --- /dev/null +++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/AbstractServletHandlerMethodTests.java @@ -0,0 +1,112 @@ +/* + * Copyright 2002-2011 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.mvc.method.annotation; + +import static junit.framework.Assert.assertNotNull; + +import javax.servlet.ServletException; + +import org.junit.After; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.context.ApplicationContextInitializer; +import org.springframework.mock.web.MockServletConfig; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.context.support.GenericWebApplicationContext; +import org.springframework.web.servlet.DispatcherServlet; +import org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver; +import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver; + +/** + * Base class for tests using on the DispatcherServlet and HandlerMethod infrastructure classes: + *
    + *
  • RequestMappingHandlerMapping + *
  • RequestMappingHandlerAdapter + *
  • ExceptionHandlerExceptionResolver + *
+ * + * @author Rossen Stoyanchev + */ +public class AbstractServletHandlerMethodTests { + + private DispatcherServlet servlet; + + @After + public void tearDown() { + this.servlet = null; + } + + protected DispatcherServlet getServlet() { + assertNotNull("DispatcherServlet not initialized", servlet); + return servlet; + } + + /** + * Initialize a DispatcherServlet instance registering zero or more controller classes. + */ + protected WebApplicationContext initServletWithControllers(final Class... controllerClasses) + throws ServletException { + return initServlet(null, controllerClasses); + } + + /** + * Initialize a DispatcherServlet instance registering zero or more controller classes + * and also providing additional bean definitions through a callback. + */ + @SuppressWarnings("serial") + protected WebApplicationContext initServlet( + final ApplicationContextInitializer initializer, + final Class... controllerClasses) throws ServletException { + + final GenericWebApplicationContext wac = new GenericWebApplicationContext(); + + servlet = new DispatcherServlet() { + @Override + protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) { + for (Class clazz : controllerClasses) { + wac.registerBeanDefinition(clazz.getSimpleName(), new RootBeanDefinition(clazz)); + } + + Class mappingType = RequestMappingHandlerMapping.class; + wac.registerBeanDefinition("handlerMapping", new RootBeanDefinition(mappingType)); + + Class adapterType = RequestMappingHandlerAdapter.class; + wac.registerBeanDefinition("handlerAdapter", new RootBeanDefinition(adapterType)); + + Class resolverType = ExceptionHandlerExceptionResolver.class; + wac.registerBeanDefinition("requestMappingResolver", new RootBeanDefinition(resolverType)); + + resolverType = ResponseStatusExceptionResolver.class; + wac.registerBeanDefinition("responseStatusResolver", new RootBeanDefinition(resolverType)); + + resolverType = DefaultHandlerExceptionResolver.class; + wac.registerBeanDefinition("defaultResolver", new RootBeanDefinition(resolverType)); + + if (initializer != null) { + initializer.initialize(wac); + } + + wac.refresh(); + return wac; + } + }; + + servlet.init(new MockServletConfig()); + + return wac; + } + +} diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/FlashAttributesServletTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/FlashAttributesServletTests.java new file mode 100644 index 0000000000..99311da52f --- /dev/null +++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/FlashAttributesServletTests.java @@ -0,0 +1,215 @@ +/* + * Copyright 2002-2011 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.mvc.method.annotation; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +import java.util.Locale; +import java.util.Map; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.junit.Test; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.context.ApplicationContextInitializer; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.FlashAttributes; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.support.FlashStatus; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.context.support.GenericWebApplicationContext; +import org.springframework.web.method.annotation.FlashAttributesHandler; +import org.springframework.web.servlet.View; +import org.springframework.web.servlet.ViewResolver; + +/** + * Test controllers with @{@link FlashAttributes} through the DispatcherServlet. + * + * @author Rossen Stoyanchev + */ +public class FlashAttributesServletTests extends AbstractServletHandlerMethodTests { + + private static final String MESSAGE_KEY = "message"; + + @Test + public void successMessage() throws Exception { + + initServletWithModelExposingViewResolver(MessageController.class); + + MockHttpServletRequest req = new MockHttpServletRequest("GET", "/message"); + MockHttpServletResponse res = new MockHttpServletResponse(); + getServlet().service(req, res); + + assertEquals(200, res.getStatus()); + assertNull(getModelAttribute(req, MESSAGE_KEY)); + assertNull(getFlashAttribute(req, MESSAGE_KEY)); + + req.setMethod("POST"); + getServlet().service(req, res); + + assertEquals(200, res.getStatus()); + assertEquals("Yay!", ((Message) getModelAttribute(req, MESSAGE_KEY)).getText()); + assertEquals("Yay!", ((Message) getFlashAttribute(req, MESSAGE_KEY)).getText()); + + req.setMethod("GET"); + getServlet().service(req, res); + + assertEquals(200, res.getStatus()); + assertEquals("Yay!", ((Message) getModelAttribute(req, MESSAGE_KEY)).getText()); + assertNull(getFlashAttribute(req, MESSAGE_KEY)); + } + + @Test + public void successMessageAcrossControllers() throws Exception { + + initServletWithModelExposingViewResolver(MessageController.class, SecondMessageController.class); + + MockHttpServletRequest req = new MockHttpServletRequest("POST", "/message"); + MockHttpServletResponse res = new MockHttpServletResponse(); + getServlet().service(req, res); + + req.setParameter("another", "true"); + getServlet().service(req, res); + + assertEquals(200, res.getStatus()); + assertEquals("Nay!", ((Message) getModelAttribute(req, MESSAGE_KEY)).getText()); + assertEquals("Nay!", ((Message) getFlashAttribute(req, MESSAGE_KEY)).getText()); + + req.setMethod("GET"); + req.setRequestURI("/second/message"); + getServlet().service(req, res); + + assertEquals(200, res.getStatus()); + assertEquals("Nay!", ((Message) getModelAttribute(req, MESSAGE_KEY)).getText()); + assertNull(getFlashAttribute(req, MESSAGE_KEY)); + } + + @Controller + @FlashAttributes("message") + static class MessageController { + + @RequestMapping(value="/message", method=RequestMethod.GET) + public void message(Model model) { + } + + @RequestMapping(value="/message", method=RequestMethod.POST) + public String sendMessage(Model model, FlashStatus status) { + status.setActive(); + model.addAttribute(Message.success("Yay!")); + return "redirect:/message"; + } + + @RequestMapping(value="/message", method=RequestMethod.POST, params="another") + public String sendMessageToSecondController(Model model, FlashStatus status) { + status.setActive(); + model.addAttribute(Message.error("Nay!")); + return "redirect:/second/message"; + } + } + + @Controller + static class SecondMessageController { + + @RequestMapping(value="/second/message", method=RequestMethod.GET) + public void message(Model model) { + } + } + + private static class Message { + + private final MessageType type; + + private final String text; + + private Message(MessageType type, String text) { + this.type = type; + this.text = text; + } + + public static Message success(String text) { + return new Message(MessageType.success, text); + } + + public static Message error(String text) { + return new Message(MessageType.error, text); + } + + public MessageType getType() { + return type; + } + + public String getText() { + return text; + } + + public String toString() { + return type + ": " + text; + } + + } + + private static enum MessageType { + info, success, warning, error + } + + @SuppressWarnings("unchecked") + private Object getModelAttribute(MockHttpServletRequest req, String key) { + Map model = (Map) req.getAttribute(ModelExposingViewResolver.REQUEST_ATTRIBITE_MODEL); + return model.get(key); + } + + @SuppressWarnings("unchecked") + private Object getFlashAttribute(MockHttpServletRequest req, String key) { + String flashAttributesKey = FlashAttributesHandler.FLASH_ATTRIBUTES_SESSION_KEY; + Map attrs = (Map) req.getSession().getAttribute(flashAttributesKey); + return (attrs != null) ? attrs.get(key) : null; + } + + private WebApplicationContext initServletWithModelExposingViewResolver(Class... controllerClasses) + throws ServletException { + + return initServlet(new ApplicationContextInitializer() { + public void initialize(GenericWebApplicationContext wac) { + wac.registerBeanDefinition("viewResolver", new RootBeanDefinition(ModelExposingViewResolver.class)); + } + }, controllerClasses); + } + + static class ModelExposingViewResolver implements ViewResolver { + + static String REQUEST_ATTRIBITE_MODEL = "ModelExposingViewResolver.model"; + + public View resolveViewName(final String viewName, Locale locale) throws Exception { + return new View() { + public void render(Map model, HttpServletRequest request, HttpServletResponse response) throws Exception { + request.setAttribute(REQUEST_ATTRIBITE_MODEL, model); + } + public String getContentType() { + return null; + } + }; + } + } + +} diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapterIntegrationTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapterIntegrationTests.java index 23f87e3103..85c79335da 100644 --- a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapterIntegrationTests.java +++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapterIntegrationTests.java @@ -92,7 +92,7 @@ import org.springframework.web.servlet.mvc.method.annotation.support.ServletWebA *

If you wish to add high-level tests, consider the following other "integration"-style tests: *

    *
  • {@link HandlerMethodAnnotationDetectionTests} - *
  • {@link ServletHandlerMethodTests} + *
  • {@link ServletAnnotationControllerHandlerMethodTests} *
* * @author Rossen Stoyanchev diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapterTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapterTests.java index c36453891a..ccf6246c9a 100644 --- a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapterTests.java +++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapterTests.java @@ -49,7 +49,7 @@ import org.springframework.web.servlet.mvc.method.annotation.support.ServletRequ * *

For higher-level adapter tests see: *

    - *
  • {@link ServletHandlerMethodTests} + *
  • {@link ServletAnnotationControllerHandlerMethodTests} *
  • {@link HandlerMethodAnnotationDetectionTests} *
  • {@link RequestMappingHandlerAdapterIntegrationTests} *
diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ServletHandlerMethodTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ServletAnnotationControllerHandlerMethodTests.java similarity index 87% rename from org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ServletHandlerMethodTests.java rename to org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ServletAnnotationControllerHandlerMethodTests.java index 385a5853e1..c3e198278f 100644 --- a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ServletHandlerMethodTests.java +++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ServletAnnotationControllerHandlerMethodTests.java @@ -16,6 +16,14 @@ package org.springframework.web.servlet.mvc.method.annotation; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + import java.beans.PropertyEditorSupport; import java.io.IOException; import java.io.Serializable; @@ -40,6 +48,7 @@ import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; + import javax.servlet.ServletConfig; import javax.servlet.ServletContext; import javax.servlet.ServletException; @@ -52,7 +61,6 @@ import javax.validation.constraints.NotNull; import javax.xml.bind.annotation.XmlRootElement; import org.junit.Test; - import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator; import org.springframework.aop.interceptor.SimpleTraceInterceptor; import org.springframework.aop.support.DefaultPointcutAdvisor; @@ -66,6 +74,7 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.beans.propertyeditors.CustomDateEditor; +import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.annotation.AnnotationConfigUtils; import org.springframework.core.MethodParameter; import org.springframework.core.convert.converter.Converter; @@ -121,126 +130,130 @@ import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.context.request.WebRequest; import org.springframework.web.context.support.GenericWebApplicationContext; +import org.springframework.web.method.HandlerMethod; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.multipart.support.StringMultipartFileEditor; -import org.springframework.web.servlet.DispatcherServlet; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.View; import org.springframework.web.servlet.ViewResolver; import org.springframework.web.servlet.mvc.annotation.ModelAndViewResolver; -import org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver; import org.springframework.web.servlet.mvc.method.annotation.support.ServletWebArgumentResolverAdapter; -import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver; import org.springframework.web.servlet.view.InternalResourceViewResolver; -import static org.junit.Assert.*; - /** - * The origin of this test fixture is {@link ServletHandlerMethodTests} with tests in this class adapted to run - * against the HandlerMethod infrastructure rather than against the DefaultAnnotationHandlerMapping, the - * AnnotationMethodHandlerAdapter, and the AnnotationMethodHandlerExceptionResolver. Tests that are not - * supported are listed at the bottom. + * The origin of this test class is {@link ServletAnnotationControllerHandlerMethodTests}. + * + * Tests in this class run against the {@link HandlerMethod} infrastructure: + *
    + *
  • RequestMappingHandlerMapping + *
  • RequestMappingHandlerAdapter + *
  • ExceptionHandlerExceptionResolver + *
+ * + *

Rather than against the existing infrastructure: + *

    + *
  • DefaultAnnotationHandlerMapping + *
  • AnnotationMethodHandlerAdapter + *
  • AnnotationMethodHandlerExceptionResolver + *
* * @author Rossen Stoyanchev - * @since 3.1 */ -public class ServletHandlerMethodTests { - - private DispatcherServlet servlet; +public class ServletAnnotationControllerHandlerMethodTests extends AbstractServletHandlerMethodTests { @Test public void emptyValueMapping() throws Exception { - initDispatcherServlet(ControllerWithEmptyValueMapping.class, null); + initServletWithControllers(ControllerWithEmptyValueMapping.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo"); request.setContextPath("/foo"); request.setServletPath(""); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("test", response.getContentAsString()); } @Test public void customAnnotationController() throws Exception { - initDispatcherServlet(CustomAnnotationController.class, null); + initServletWithControllers(CustomAnnotationController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath.do"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("Invalid response status code", HttpServletResponse.SC_OK, response.getStatus()); } @Test public void requiredParamMissing() throws Exception { - initDispatcherServlet(RequiredParamController.class, null); + WebApplicationContext webAppContext = initServletWithControllers(RequiredParamController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath.do"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("Invalid response status code", HttpServletResponse.SC_BAD_REQUEST, response.getStatus()); - assertTrue(servlet.getWebApplicationContext().isSingleton("controller")); + assertTrue(webAppContext.isSingleton(RequiredParamController.class.getSimpleName())); } @Test public void typeConversionError() throws Exception { - initDispatcherServlet(RequiredParamController.class, null); + initServletWithControllers(RequiredParamController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath.do"); request.addParameter("id", "foo"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("Invalid response status code", HttpServletResponse.SC_BAD_REQUEST, response.getStatus()); } @Test public void optionalParamPresent() throws Exception { - initDispatcherServlet(OptionalParamController.class, null); + initServletWithControllers(OptionalParamController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath.do"); request.addParameter("id", "val"); request.addParameter("flag", "true"); request.addHeader("header", "otherVal"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("val-true-otherVal", response.getContentAsString()); } @Test public void optionalParamMissing() throws Exception { - initDispatcherServlet(OptionalParamController.class, null); + initServletWithControllers(OptionalParamController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath.do"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("null-false-null", response.getContentAsString()); } @Test public void defaultParameters() throws Exception { - initDispatcherServlet(DefaultValueParamController.class, null); + initServletWithControllers(DefaultValueParamController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath.do"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("foo--bar", response.getContentAsString()); } @Test public void defaultExpressionParameters() throws Exception { - initDispatcherServlet(DefaultExpressionValueParamController.class, new BeanDefinitionRegistrar() { - public void register(GenericWebApplicationContext context) { + initServlet(new ApplicationContextInitializer() { + public void initialize(GenericWebApplicationContext context) { RootBeanDefinition ppc = new RootBeanDefinition(PropertyPlaceholderConfigurer.class); ppc.getPropertyValues().add("properties", "myKey=foo"); context.registerBeanDefinition("ppc", ppc); } - }); + }, DefaultExpressionValueParamController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myApp/myPath.do"); request.setContextPath("/myApp"); MockHttpServletResponse response = new MockHttpServletResponse(); System.setProperty("myHeader", "bar"); try { - servlet.service(request, response); + getServlet().service(request, response); } finally { System.clearProperty("myHeader"); @@ -250,8 +263,8 @@ public class ServletHandlerMethodTests { @Test public void typeNestedSetBinding() throws Exception { - initDispatcherServlet(NestedSetController.class, new BeanDefinitionRegistrar() { - public void register(GenericWebApplicationContext context) { + initServlet(new ApplicationContextInitializer() { + public void initialize(GenericWebApplicationContext context) { RootBeanDefinition csDef = new RootBeanDefinition(FormattingConversionServiceFactoryBean.class); csDef.getPropertyValues().add("converters", new TestBeanConverter()); RootBeanDefinition wbiDef = new RootBeanDefinition(ConfigurableWebBindingInitializer.class); @@ -260,22 +273,22 @@ public class ServletHandlerMethodTests { adapterDef.getPropertyValues().add("webBindingInitializer", wbiDef); context.registerBeanDefinition("handlerAdapter", adapterDef); } - }); + }, NestedSetController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath.do"); request.addParameter("testBeanSet", new String[] {"1", "2"}); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("[1, 2]-org.springframework.beans.TestBean", response.getContentAsString()); } @Test public void methodNotAllowed() throws Exception { - initDispatcherServlet(MethodNotAllowedController.class, null); + initServletWithControllers(MethodNotAllowedController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath.do"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("Invalid response status", HttpServletResponse.SC_METHOD_NOT_ALLOWED, response.getStatus()); String allowHeader = (String) response.getHeader("Allow"); assertNotNull("No Allow header", allowHeader); @@ -292,19 +305,19 @@ public class ServletHandlerMethodTests { @Test public void emptyParameterListHandleMethod() throws Exception { - initDispatcherServlet(EmptyParameterListHandlerMethodController.class, new BeanDefinitionRegistrar() { - public void register(GenericWebApplicationContext context) { + initServlet(new ApplicationContextInitializer() { + public void initialize(GenericWebApplicationContext context) { RootBeanDefinition vrDef = new RootBeanDefinition(InternalResourceViewResolver.class); vrDef.getPropertyValues().add("suffix", ".jsp"); context.registerBeanDefinition("viewResolver", vrDef); } - }); + }, EmptyParameterListHandlerMethodController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/emptyParameterListHandler"); MockHttpServletResponse response = new MockHttpServletResponse(); EmptyParameterListHandlerMethodController.called = false; - servlet.service(request, response); + getServlet().service(request, response); assertTrue(EmptyParameterListHandlerMethodController.called); assertEquals("", response.getContentAsString()); } @@ -312,15 +325,15 @@ public class ServletHandlerMethodTests { @SuppressWarnings("rawtypes") @Test public void sessionAttributeExposure() throws Exception { - initDispatcherServlet(MySessionAttributesController.class, new BeanDefinitionRegistrar() { - public void register(GenericWebApplicationContext context) { + initServlet(new ApplicationContextInitializer() { + public void initialize(GenericWebApplicationContext context) { context.registerBeanDefinition("viewResolver", new RootBeanDefinition(ModelExposingViewResolver.class)); } - }); + }, MySessionAttributesController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPage"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("page1", request.getAttribute("viewName")); HttpSession session = request.getSession(); assertTrue(session.getAttribute("object1") != null); @@ -331,7 +344,7 @@ public class ServletHandlerMethodTests { request = new MockHttpServletRequest("POST", "/myPage"); request.setSession(session); response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("page2", request.getAttribute("viewName")); assertTrue(session.getAttribute("object1") != null); assertTrue(session.getAttribute("object2") != null); @@ -342,19 +355,19 @@ public class ServletHandlerMethodTests { @SuppressWarnings("rawtypes") @Test public void sessionAttributeExposureWithInterface() throws Exception { - initDispatcherServlet(MySessionAttributesControllerImpl.class, new BeanDefinitionRegistrar() { - public void register(GenericWebApplicationContext context) { + initServlet(new ApplicationContextInitializer() { + public void initialize(GenericWebApplicationContext context) { context.registerBeanDefinition("viewResolver", new RootBeanDefinition(ModelExposingViewResolver.class)); DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator(); autoProxyCreator.setBeanFactory(context.getBeanFactory()); context.getBeanFactory().addBeanPostProcessor(autoProxyCreator); context.getBeanFactory().registerSingleton("advisor", new DefaultPointcutAdvisor(new SimpleTraceInterceptor())); } - }); + }, MySessionAttributesControllerImpl.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPage"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("page1", request.getAttribute("viewName")); HttpSession session = request.getSession(); assertTrue(session.getAttribute("object1") != null); @@ -365,7 +378,7 @@ public class ServletHandlerMethodTests { request = new MockHttpServletRequest("POST", "/myPage"); request.setSession(session); response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("page2", request.getAttribute("viewName")); assertTrue(session.getAttribute("object1") != null); assertTrue(session.getAttribute("object2") != null); @@ -376,15 +389,15 @@ public class ServletHandlerMethodTests { @SuppressWarnings("rawtypes") @Test public void parameterizedAnnotatedInterface() throws Exception { - initDispatcherServlet(MyParameterizedControllerImpl.class, new BeanDefinitionRegistrar() { - public void register(GenericWebApplicationContext context) { + initServlet(new ApplicationContextInitializer() { + public void initialize(GenericWebApplicationContext context) { context.registerBeanDefinition("viewResolver", new RootBeanDefinition(ModelExposingViewResolver.class)); } - }); + }, MyParameterizedControllerImpl.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPage"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("page1", request.getAttribute("viewName")); HttpSession session = request.getSession(); assertTrue(session.getAttribute("object1") != null); @@ -396,7 +409,7 @@ public class ServletHandlerMethodTests { request = new MockHttpServletRequest("POST", "/myPage"); request.setSession(session); response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("page2", request.getAttribute("viewName")); assertTrue(session.getAttribute("object1") != null); assertTrue(session.getAttribute("object2") != null); @@ -408,15 +421,15 @@ public class ServletHandlerMethodTests { @SuppressWarnings("rawtypes") @Test public void parameterizedAnnotatedInterfaceWithOverriddenMappingsInImpl() throws Exception { - initDispatcherServlet(MyParameterizedControllerImplWithOverriddenMappings.class, new BeanDefinitionRegistrar() { - public void register(GenericWebApplicationContext context) { + initServlet(new ApplicationContextInitializer() { + public void initialize(GenericWebApplicationContext context) { context.registerBeanDefinition("viewResolver", new RootBeanDefinition(ModelExposingViewResolver.class)); } - }); + }, MyParameterizedControllerImplWithOverriddenMappings.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPage"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("page1", request.getAttribute("viewName")); HttpSession session = request.getSession(); assertTrue(session.getAttribute("object1") != null); @@ -428,7 +441,7 @@ public class ServletHandlerMethodTests { request = new MockHttpServletRequest("POST", "/myPage"); request.setSession(session); response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("page2", request.getAttribute("viewName")); assertTrue(session.getAttribute("object1") != null); assertTrue(session.getAttribute("object2") != null); @@ -453,13 +466,13 @@ public class ServletHandlerMethodTests { } private void doTestAdaptedHandleMethods(final Class controllerClass) throws Exception { - initDispatcherServlet(controllerClass, null); + initServletWithControllers(controllerClass); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath1.do"); MockHttpServletResponse response = new MockHttpServletResponse(); request.addParameter("param1", "value1"); request.addParameter("param2", "2"); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("test", response.getContentAsString()); request = new MockHttpServletRequest("GET", "/myPath2.do"); @@ -468,7 +481,7 @@ public class ServletHandlerMethodTests { request.addHeader("header1", "10"); request.setCookies(new Cookie("cookie1", "3")); response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("test-value1-2-10-3", response.getContentAsString()); request = new MockHttpServletRequest("GET", "/myPath3.do"); @@ -477,7 +490,7 @@ public class ServletHandlerMethodTests { request.addParameter("name", "name1"); request.addParameter("age", "2"); response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("test-name1-2", response.getContentAsString()); request = new MockHttpServletRequest("GET", "/myPath4.do"); @@ -486,46 +499,46 @@ public class ServletHandlerMethodTests { request.addParameter("name", "name1"); request.addParameter("age", "value2"); response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("test-name1-typeMismatch", response.getContentAsString()); } @Test public void formController() throws Exception { - initDispatcherServlet(MyFormController.class, new BeanDefinitionRegistrar() { - public void register(GenericWebApplicationContext wac) { + initServlet(new ApplicationContextInitializer() { + public void initialize(GenericWebApplicationContext wac) { wac.registerBeanDefinition("viewResolver", new RootBeanDefinition(TestViewResolver.class)); } - }); + }, MyFormController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath.do"); request.addParameter("name", "name1"); request.addParameter("age", "value2"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("myView-name1-typeMismatch-tb1-myValue", response.getContentAsString()); } @Test public void modelFormController() throws Exception { - initDispatcherServlet(MyModelFormController.class, new BeanDefinitionRegistrar() { - public void register(GenericWebApplicationContext wac) { + initServlet(new ApplicationContextInitializer() { + public void initialize(GenericWebApplicationContext wac) { wac.registerBeanDefinition("viewResolver", new RootBeanDefinition(TestViewResolver.class)); } - }); + }, MyModelFormController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath.do"); request.addParameter("name", "name1"); request.addParameter("age", "value2"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("myPath-name1-typeMismatch-tb1-myValue-yourValue", response.getContentAsString()); } @Test public void proxiedFormController() throws Exception { - initDispatcherServlet(MyFormController.class, new BeanDefinitionRegistrar() { - public void register(GenericWebApplicationContext wac) { + initServlet(new ApplicationContextInitializer() { + public void initialize(GenericWebApplicationContext wac) { wac.registerBeanDefinition("viewResolver", new RootBeanDefinition(TestViewResolver.class)); DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator(); autoProxyCreator.setBeanFactory(wac.getBeanFactory()); @@ -533,40 +546,40 @@ public class ServletHandlerMethodTests { wac.getBeanFactory() .registerSingleton("advisor", new DefaultPointcutAdvisor(new SimpleTraceInterceptor())); } - }); + }, MyFormController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath.do"); request.addParameter("name", "name1"); request.addParameter("age", "value2"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("myView-name1-typeMismatch-tb1-myValue", response.getContentAsString()); } @Test public void commandProvidingFormControllerWithCustomEditor() throws Exception { - initDispatcherServlet(MyCommandProvidingFormController.class, new BeanDefinitionRegistrar() { - public void register(GenericWebApplicationContext wac) { + initServlet(new ApplicationContextInitializer() { + public void initialize(GenericWebApplicationContext wac) { wac.registerBeanDefinition("viewResolver", new RootBeanDefinition(TestViewResolver.class)); RootBeanDefinition adapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class); adapterDef.getPropertyValues().add("webBindingInitializer", new MyWebBindingInitializer()); wac.registerBeanDefinition("handlerAdapter", adapterDef); } - }); + }, MyCommandProvidingFormController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath.do"); request.addParameter("defaultName", "myDefaultName"); request.addParameter("age", "value2"); request.addParameter("date", "2007-10-02"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("myView-String:myDefaultName-typeMismatch-tb1-myOriginalValue", response.getContentAsString()); } @Test public void typedCommandProvidingFormController() throws Exception { - initDispatcherServlet(MyTypedCommandProvidingFormController.class, new BeanDefinitionRegistrar() { - public void register(GenericWebApplicationContext wac) { + initServlet(new ApplicationContextInitializer() { + public void initialize(GenericWebApplicationContext wac) { wac.registerBeanDefinition("viewResolver", new RootBeanDefinition(TestViewResolver.class)); RootBeanDefinition adapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class); adapterDef.getPropertyValues().add("webBindingInitializer", new MyWebBindingInitializer()); @@ -575,14 +588,14 @@ public class ServletHandlerMethodTests { adapterDef.getPropertyValues().add("customArgumentResolvers", argumentResolvers); wac.registerBeanDefinition("handlerAdapter", adapterDef); } - }); + }, MyTypedCommandProvidingFormController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath.do"); request.addParameter("defaultName", "10"); request.addParameter("age", "value2"); request.addParameter("date", "2007-10-02"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("myView-Integer:10-typeMismatch-tb1-myOriginalValue", response.getContentAsString()); request = new MockHttpServletRequest("GET", "/myOtherPath.do"); @@ -590,7 +603,7 @@ public class ServletHandlerMethodTests { request.addParameter("age", "value2"); request.addParameter("date", "2007-10-02"); response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("myView-myName-typeMismatch-tb1-myOriginalValue", response.getContentAsString()); request = new MockHttpServletRequest("GET", "/myThirdPath.do"); @@ -598,41 +611,41 @@ public class ServletHandlerMethodTests { request.addParameter("age", "100"); request.addParameter("date", "2007-10-02"); response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("myView-special-99-special-99", response.getContentAsString()); } @Test public void binderInitializingCommandProvidingFormController() throws Exception { - initDispatcherServlet(MyBinderInitializingCommandProvidingFormController.class, new BeanDefinitionRegistrar() { - public void register(GenericWebApplicationContext wac) { + initServlet(new ApplicationContextInitializer() { + public void initialize(GenericWebApplicationContext wac) { wac.registerBeanDefinition("viewResolver", new RootBeanDefinition(TestViewResolver.class)); } - }); + }, MyBinderInitializingCommandProvidingFormController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath.do"); request.addParameter("defaultName", "myDefaultName"); request.addParameter("age", "value2"); request.addParameter("date", "2007-10-02"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("myView-String:myDefaultName-typeMismatch-tb1-myOriginalValue", response.getContentAsString()); } @Test public void specificBinderInitializingCommandProvidingFormController() throws Exception { - initDispatcherServlet(MySpecificBinderInitializingCommandProvidingFormController.class, new BeanDefinitionRegistrar() { - public void register(GenericWebApplicationContext wac) { + initServlet(new ApplicationContextInitializer() { + public void initialize(GenericWebApplicationContext wac) { wac.registerBeanDefinition("viewResolver", new RootBeanDefinition(TestViewResolver.class)); } - }); + }, MySpecificBinderInitializingCommandProvidingFormController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath.do"); request.addParameter("defaultName", "myDefaultName"); request.addParameter("age", "value2"); request.addParameter("date", "2007-10-02"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("myView-String:myDefaultName-typeMismatch-tb1-myOriginalValue", response.getContentAsString()); } @@ -641,21 +654,19 @@ public class ServletHandlerMethodTests { final MockServletContext servletContext = new MockServletContext(); final MockServletConfig servletConfig = new MockServletConfig(servletContext); - initDispatcherServlet(MyParameterDispatchingController.class, new BeanDefinitionRegistrar() { - public void register(GenericWebApplicationContext wac) { - wac.setServletContext(servletContext); - RootBeanDefinition bd = new RootBeanDefinition(MyParameterDispatchingController.class); - //bd.setScope(WebApplicationContext.SCOPE_REQUEST); - wac.registerBeanDefinition("controller", bd); - AnnotationConfigUtils.registerAnnotationConfigProcessors(wac); - wac.getBeanFactory().registerResolvableDependency(ServletConfig.class, servletConfig); - } - }); + WebApplicationContext webAppContext = + initServlet(new ApplicationContextInitializer() { + public void initialize(GenericWebApplicationContext wac) { + wac.setServletContext(servletContext); + AnnotationConfigUtils.registerAnnotationConfigProcessors(wac); + wac.getBeanFactory().registerResolvableDependency(ServletConfig.class, servletConfig); + } + }, MyParameterDispatchingController.class); MockHttpServletRequest request = new MockHttpServletRequest(servletContext, "GET", "/myPath.do"); MockHttpServletResponse response = new MockHttpServletResponse(); HttpSession session = request.getSession(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("myView", response.getContentAsString()); assertSame(servletContext, request.getAttribute("servletContext")); assertSame(servletConfig, request.getAttribute("servletConfig")); @@ -666,7 +677,7 @@ public class ServletHandlerMethodTests { request = new MockHttpServletRequest(servletContext, "GET", "/myPath.do"); response = new MockHttpServletResponse(); session = request.getSession(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("myView", response.getContentAsString()); assertSame(servletContext, request.getAttribute("servletContext")); assertSame(servletConfig, request.getAttribute("servletConfig")); @@ -676,96 +687,97 @@ public class ServletHandlerMethodTests { request = new MockHttpServletRequest(servletContext, "GET", "/myPath.do"); request.addParameter("view", "other"); response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("myOtherView", response.getContentAsString()); request = new MockHttpServletRequest(servletContext, "GET", "/myPath.do"); request.addParameter("view", "my"); request.addParameter("lang", "de"); response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("myLangView", response.getContentAsString()); request = new MockHttpServletRequest(servletContext, "GET", "/myPath.do"); request.addParameter("surprise", "!"); response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("mySurpriseView", response.getContentAsString()); - MyParameterDispatchingController deserialized = (MyParameterDispatchingController) SerializationTestUtils - .serializeAndDeserialize(servlet.getWebApplicationContext().getBean("controller")); + MyParameterDispatchingController deserialized = + (MyParameterDispatchingController) SerializationTestUtils.serializeAndDeserialize( + webAppContext.getBean(MyParameterDispatchingController.class.getSimpleName())); assertNotNull(deserialized.request); assertNotNull(deserialized.session); } @Test public void relativePathDispatchingController() throws Exception { - initDispatcherServlet(MyRelativePathDispatchingController.class, null); - servlet.init(new MockServletConfig()); + initServletWithControllers(MyRelativePathDispatchingController.class); + getServlet().init(new MockServletConfig()); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myApp/myHandle"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("myView", response.getContentAsString()); request = new MockHttpServletRequest("GET", "/myApp/myOther"); response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("myOtherView", response.getContentAsString()); request = new MockHttpServletRequest("GET", "/myApp/myLang"); response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("myLangView", response.getContentAsString()); request = new MockHttpServletRequest("GET", "/myApp/surprise.do"); response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("mySurpriseView", response.getContentAsString()); } @Test public void relativeMethodPathDispatchingController() throws Exception { - initDispatcherServlet(MyRelativeMethodPathDispatchingController.class, null); - servlet.init(new MockServletConfig()); + initServletWithControllers(MyRelativeMethodPathDispatchingController.class); + getServlet().init(new MockServletConfig()); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myApp/myHandle"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("myView", response.getContentAsString()); request = new MockHttpServletRequest("GET", "/yourApp/myOther"); response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("myOtherView", response.getContentAsString()); request = new MockHttpServletRequest("GET", "/hisApp/myLang"); response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("myLangView", response.getContentAsString()); request = new MockHttpServletRequest("GET", "/herApp/surprise.do"); response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("mySurpriseView", response.getContentAsString()); } @Test public void nullCommandController() throws Exception { - initDispatcherServlet(MyNullCommandController.class, null); - servlet.init(new MockServletConfig()); + initServletWithControllers(MyNullCommandController.class); + getServlet().init(new MockServletConfig()); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath"); request.setUserPrincipal(new OtherPrincipal()); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("myView", response.getContentAsString()); } @Test public void equivalentMappingsWithSameMethodName() throws Exception { try { - initDispatcherServlet(ChildController.class, null); + initServletWithControllers(ChildController.class); fail("Expected 'method already mapped' error"); } catch (BeanCreationException e) { @@ -776,17 +788,17 @@ public class ServletHandlerMethodTests { @Test public void pathOrdering() throws ServletException, IOException { - initDispatcherServlet(PathOrderingController.class, null); + initServletWithControllers(PathOrderingController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/dir/myPath1.do"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("method1", response.getContentAsString()); } @Test public void requestBodyResponseBody() throws ServletException, IOException { - initDispatcherServlet(RequestResponseBodyController.class, null); + initServletWithControllers(RequestResponseBodyController.class); MockHttpServletRequest request = new MockHttpServletRequest("PUT", "/something"); String requestBody = "Hello World"; @@ -794,21 +806,21 @@ public class ServletHandlerMethodTests { request.addHeader("Content-Type", "text/plain; charset=utf-8"); request.addHeader("Accept", "text/*, */*"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals(200, response.getStatus()); assertEquals(requestBody, response.getContentAsString()); } @Test public void responseBodyNoAcceptableMediaType() throws ServletException, IOException { - initDispatcherServlet(RequestResponseBodyProducesController.class, new BeanDefinitionRegistrar() { - public void register(GenericWebApplicationContext wac) { + initServlet(new ApplicationContextInitializer() { + public void initialize(GenericWebApplicationContext wac) { RootBeanDefinition adapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class); StringHttpMessageConverter converter = new StringHttpMessageConverter(); adapterDef.getPropertyValues().add("messageConverters", converter); wac.registerBeanDefinition("handlerAdapter", adapterDef); } - }); + }, RequestResponseBodyProducesController.class); MockHttpServletRequest request = new MockHttpServletRequest("PUT", "/something"); String requestBody = "Hello World"; @@ -816,13 +828,13 @@ public class ServletHandlerMethodTests { request.addHeader("Content-Type", "text/plain; charset=utf-8"); request.addHeader("Accept", "application/pdf, application/msword"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals(406, response.getStatus()); } @Test public void responseBodyWildCardMediaType() throws ServletException, IOException { - initDispatcherServlet(RequestResponseBodyController.class, null); + initServletWithControllers(RequestResponseBodyController.class); MockHttpServletRequest request = new MockHttpServletRequest("PUT", "/something"); String requestBody = "Hello World"; @@ -830,66 +842,66 @@ public class ServletHandlerMethodTests { request.addHeader("Content-Type", "text/plain; charset=utf-8"); request.addHeader("Accept", "*/*"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals(requestBody, response.getContentAsString()); } @Test public void unsupportedRequestBody() throws ServletException, IOException { - initDispatcherServlet(RequestResponseBodyController.class, new BeanDefinitionRegistrar() { - public void register(GenericWebApplicationContext wac) { + initServlet(new ApplicationContextInitializer() { + public void initialize(GenericWebApplicationContext wac) { RootBeanDefinition adapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class); adapterDef.getPropertyValues().add("messageConverters", new ByteArrayHttpMessageConverter()); wac.registerBeanDefinition("handlerAdapter", adapterDef); } - }); + }, RequestResponseBodyController.class); MockHttpServletRequest request = new MockHttpServletRequest("PUT", "/something"); String requestBody = "Hello World"; request.setContent(requestBody.getBytes("UTF-8")); request.addHeader("Content-Type", "application/pdf"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals(415, response.getStatus()); assertNotNull("No Accept response header set", response.getHeader("Accept")); } @Test public void responseBodyNoAcceptHeader() throws ServletException, IOException { - initDispatcherServlet(RequestResponseBodyController.class, null); + initServletWithControllers(RequestResponseBodyController.class); MockHttpServletRequest request = new MockHttpServletRequest("PUT", "/something"); String requestBody = "Hello World"; request.setContent(requestBody.getBytes("UTF-8")); request.addHeader("Content-Type", "text/plain; charset=utf-8"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals(200, response.getStatus()); assertEquals(requestBody, response.getContentAsString()); } @Test public void badRequestRequestBody() throws ServletException, IOException { - initDispatcherServlet(RequestResponseBodyController.class, new BeanDefinitionRegistrar() { - public void register(GenericWebApplicationContext wac) { + initServlet(new ApplicationContextInitializer() { + public void initialize(GenericWebApplicationContext wac) { RootBeanDefinition adapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class); adapterDef.getPropertyValues().add("messageConverters", new NotReadableMessageConverter()); wac.registerBeanDefinition("handlerAdapter", adapterDef); } - }); + }, RequestResponseBodyController.class); MockHttpServletRequest request = new MockHttpServletRequest("PUT", "/something"); String requestBody = "Hello World"; request.setContent(requestBody.getBytes("UTF-8")); request.addHeader("Content-Type", "application/pdf"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("Invalid response status code", HttpServletResponse.SC_BAD_REQUEST, response.getStatus()); } @Test public void httpEntity() throws ServletException, IOException { - initDispatcherServlet(ResponseEntityController.class, null); + initServletWithControllers(ResponseEntityController.class); MockHttpServletRequest request = new MockHttpServletRequest("PUT", "/foo"); String requestBody = "Hello World"; @@ -898,14 +910,14 @@ public class ServletHandlerMethodTests { request.addHeader("Accept", "text/*, */*"); request.addHeader("MyRequestHeader", "MyValue"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals(201, response.getStatus()); assertEquals(requestBody, response.getContentAsString()); assertEquals("MyValue", response.getHeader("MyResponseHeader")); request = new MockHttpServletRequest("PUT", "/bar"); response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("MyValue", response.getHeader("MyResponseHeader")); assertEquals(404, response.getStatus()); } @@ -916,8 +928,8 @@ public class ServletHandlerMethodTests { */ @Test public void overlappingMessageConvertersRequestBody() throws ServletException, IOException { - initDispatcherServlet(RequestResponseBodyController.class, new BeanDefinitionRegistrar() { - public void register(GenericWebApplicationContext wac) { + initServlet(new ApplicationContextInitializer() { + public void initialize(GenericWebApplicationContext wac) { RootBeanDefinition adapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class); List> messageConverters = new ArrayList>(); messageConverters.add(new StringHttpMessageConverter()); @@ -926,32 +938,32 @@ public class ServletHandlerMethodTests { adapterDef.getPropertyValues().add("messageConverters", messageConverters); wac.registerBeanDefinition("handlerAdapter", adapterDef); } - }); + }, RequestResponseBodyController.class); MockHttpServletRequest request = new MockHttpServletRequest("PUT", "/something"); request.setContent("Hello World".getBytes("UTF-8")); request.addHeader("Content-Type", "text/plain; charset=utf-8"); request.addHeader("Accept", "application/json, text/javascript, */*"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("Invalid content-type", "application/json", response.getHeader("Content-Type")); } @Test public void responseBodyVoid() throws ServletException, IOException { - initDispatcherServlet(ResponseBodyVoidController.class, null); + initServletWithControllers(ResponseBodyVoidController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/something"); request.addHeader("Accept", "text/*, */*"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals(200, response.getStatus()); } @Test public void responseBodyArgMismatch() throws ServletException, IOException { - initDispatcherServlet(RequestBodyArgMismatchController.class, new BeanDefinitionRegistrar() { - public void register(GenericWebApplicationContext wac) { + initServlet(new ApplicationContextInitializer() { + public void initialize(GenericWebApplicationContext wac) { Jaxb2Marshaller marshaller = new Jaxb2Marshaller(); marshaller.setClassesToBeBound(A.class, B.class); try { @@ -966,158 +978,158 @@ public class ServletHandlerMethodTests { adapterDef.getPropertyValues().add("messageConverters", messageConverter); wac.registerBeanDefinition("handlerAdapter", adapterDef); } - }); + }, RequestBodyArgMismatchController.class); MockHttpServletRequest request = new MockHttpServletRequest("PUT", "/something"); String requestBody = ""; request.setContent(requestBody.getBytes("UTF-8")); request.addHeader("Content-Type", "application/xml; charset=utf-8"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals(400, response.getStatus()); } @Test public void contentTypeHeaders() throws ServletException, IOException { - initDispatcherServlet(ContentTypeHeadersController.class, null); + initServletWithControllers(ContentTypeHeadersController.class); MockHttpServletRequest request = new MockHttpServletRequest("POST", "/something"); request.setContentType("application/pdf"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("pdf", response.getContentAsString()); request = new MockHttpServletRequest("POST", "/something"); request.setContentType("text/html"); response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("text", response.getContentAsString()); request = new MockHttpServletRequest("POST", "/something"); request.setContentType("application/xml"); response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals(415, response.getStatus()); } @Test public void consumes() throws ServletException, IOException { - initDispatcherServlet(ConsumesController.class, null); + initServletWithControllers(ConsumesController.class); MockHttpServletRequest request = new MockHttpServletRequest("POST", "/something"); request.setContentType("application/pdf"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("pdf", response.getContentAsString()); request = new MockHttpServletRequest("POST", "/something"); request.setContentType("text/html"); response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("text", response.getContentAsString()); request = new MockHttpServletRequest("POST", "/something"); request.setContentType("application/xml"); response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals(415, response.getStatus()); } @Test public void negatedContentTypeHeaders() throws ServletException, IOException { - initDispatcherServlet(NegatedContentTypeHeadersController.class, null); + initServletWithControllers(NegatedContentTypeHeadersController.class); MockHttpServletRequest request = new MockHttpServletRequest("POST", "/something"); request.setContentType("application/pdf"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("pdf", response.getContentAsString()); request = new MockHttpServletRequest("POST", "/something"); request.setContentType("text/html"); response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("non-pdf", response.getContentAsString()); } @Test public void acceptHeaders() throws ServletException, IOException { - initDispatcherServlet(AcceptHeadersController.class, null); + initServletWithControllers(AcceptHeadersController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/something"); request.addHeader("Accept", "text/html"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("html", response.getContentAsString()); request = new MockHttpServletRequest("GET", "/something"); request.addHeader("Accept", "application/xml"); response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("xml", response.getContentAsString()); request = new MockHttpServletRequest("GET", "/something"); request.addHeader("Accept", "application/xml, text/html"); response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("xml", response.getContentAsString()); request = new MockHttpServletRequest("GET", "/something"); request.addHeader("Accept", "text/html;q=0.9, application/xml"); response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("xml", response.getContentAsString()); request = new MockHttpServletRequest("GET", "/something"); request.addHeader("Accept", "application/msword"); response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals(406, response.getStatus()); } @Test public void produces() throws ServletException, IOException { - initDispatcherServlet(ProducesController.class, null); + initServletWithControllers(ProducesController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/something"); request.addHeader("Accept", "text/html"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("html", response.getContentAsString()); request = new MockHttpServletRequest("GET", "/something"); request.addHeader("Accept", "application/xml"); response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("xml", response.getContentAsString()); request = new MockHttpServletRequest("GET", "/something"); request.addHeader("Accept", "application/xml, text/html"); response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("xml", response.getContentAsString()); request = new MockHttpServletRequest("GET", "/something"); request.addHeader("Accept", "text/html;q=0.9, application/xml"); response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("xml", response.getContentAsString()); request = new MockHttpServletRequest("GET", "/something"); request.addHeader("Accept", "application/msword"); response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals(406, response.getStatus()); } @Test public void responseStatus() throws ServletException, IOException { - initDispatcherServlet(ResponseStatusController.class, null); + initServletWithControllers(ResponseStatusController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/something"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("something", response.getContentAsString()); assertEquals(201, response.getStatus()); assertEquals("It's alive!", response.getErrorMessage()); @@ -1125,160 +1137,160 @@ public class ServletHandlerMethodTests { @Test public void mavResolver() throws ServletException, IOException { - initDispatcherServlet(ModelAndViewResolverController.class, new BeanDefinitionRegistrar() { - public void register(GenericWebApplicationContext wac) { + initServlet(new ApplicationContextInitializer() { + public void initialize(GenericWebApplicationContext wac) { RootBeanDefinition adapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class); ModelAndViewResolver[] mavResolvers = new ModelAndViewResolver[] {new MyModelAndViewResolver()}; adapterDef.getPropertyValues().add("modelAndViewResolvers", mavResolvers); wac.registerBeanDefinition("handlerAdapter", adapterDef); } - }); + }, ModelAndViewResolverController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("myValue", response.getContentAsString()); } @Test public void bindingCookieValue() throws ServletException, IOException { - initDispatcherServlet(BindingCookieValueController.class, null); + initServletWithControllers(BindingCookieValueController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/test"); request.setCookies(new Cookie("date", "2008-11-18")); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("test-2008", response.getContentAsString()); } @Test public void ambiguousParams() throws ServletException, IOException { - initDispatcherServlet(AmbiguousParamsController.class, null); + initServletWithControllers(AmbiguousParamsController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/test"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("noParams", response.getContentAsString()); request = new MockHttpServletRequest("GET", "/test"); request.addParameter("myParam", "42"); response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("myParam-42", response.getContentAsString()); } @Test public void bridgeMethods() throws Exception { - initDispatcherServlet(TestControllerImpl.class, null); + initServletWithControllers(TestControllerImpl.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/method"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); } @Test public void requestParamMap() throws Exception { - initDispatcherServlet(RequestParamMapController.class, null); + initServletWithControllers(RequestParamMapController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/map"); request.addParameter("key1", "value1"); request.addParameter("key2", new String[]{"value21", "value22"}); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("key1=value1,key2=value21", response.getContentAsString()); request.setRequestURI("/multiValueMap"); response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("key1=[value1],key2=[value21,value22]", response.getContentAsString()); } @Test public void requestHeaderMap() throws Exception { - initDispatcherServlet(RequestHeaderMapController.class, null); + initServletWithControllers(RequestHeaderMapController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/map"); request.addHeader("Content-Type", "text/html"); request.addHeader("Custom-Header", new String[]{"value21", "value22"}); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("Content-Type=text/html,Custom-Header=value21", response.getContentAsString()); request.setRequestURI("/multiValueMap"); response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("Content-Type=[text/html],Custom-Header=[value21,value22]", response.getContentAsString()); request.setRequestURI("/httpHeaders"); response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("Content-Type=[text/html],Custom-Header=[value21,value22]", response.getContentAsString()); } @Test public void requestMappingInterface() throws Exception { - initDispatcherServlet(IMyControllerImpl.class, null); + initServletWithControllers(IMyControllerImpl.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/handle"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("handle null", response.getContentAsString()); request = new MockHttpServletRequest("GET", "/handle"); request.addParameter("p", "value"); response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("handle value", response.getContentAsString()); } @Test public void requestMappingInterfaceWithProxy() throws Exception { - initDispatcherServlet(IMyControllerImpl.class, new BeanDefinitionRegistrar() { - public void register(GenericWebApplicationContext wac) { + initServlet(new ApplicationContextInitializer() { + public void initialize(GenericWebApplicationContext wac) { DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator(); autoProxyCreator.setBeanFactory(wac.getBeanFactory()); wac.getBeanFactory().addBeanPostProcessor(autoProxyCreator); wac.getBeanFactory().registerSingleton("advisor", new DefaultPointcutAdvisor(new SimpleTraceInterceptor())); } - }); + }, IMyControllerImpl.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/handle"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("handle null", response.getContentAsString()); request = new MockHttpServletRequest("GET", "/handle"); request.addParameter("p", "value"); response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("handle value", response.getContentAsString()); } @Test public void requestMappingBaseClass() throws Exception { - initDispatcherServlet(MyAbstractControllerImpl.class, null); + initServletWithControllers(MyAbstractControllerImpl.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/handle"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("handle", response.getContentAsString()); } @Test public void trailingSlash() throws Exception { - initDispatcherServlet(TrailingSlashController.class, null); + initServletWithControllers(TrailingSlashController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo/"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("templatePath", response.getContentAsString()); } @@ -1287,83 +1299,83 @@ public class ServletHandlerMethodTests { */ @Test public void customMapEditor() throws Exception { - initDispatcherServlet(CustomMapEditorController.class, null); + initServletWithControllers(CustomMapEditorController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/handle"); request.addParameter("map", "bar"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("test-{foo=bar}", response.getContentAsString()); } @Test public void multipartFileAsSingleString() throws Exception { - initDispatcherServlet(MultipartController.class, null); + initServletWithControllers(MultipartController.class); MockMultipartHttpServletRequest request = new MockMultipartHttpServletRequest(); request.setRequestURI("/singleString"); request.addFile(new MockMultipartFile("content", "Juergen".getBytes())); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("Juergen", response.getContentAsString()); } @Test public void regularParameterAsSingleString() throws Exception { - initDispatcherServlet(MultipartController.class, null); + initServletWithControllers(MultipartController.class); MockHttpServletRequest request = new MockHttpServletRequest(); request.setRequestURI("/singleString"); request.setMethod("POST"); request.addParameter("content", "Juergen"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("Juergen", response.getContentAsString()); } @Test public void multipartFileAsStringArray() throws Exception { - initDispatcherServlet(MultipartController.class, null); + initServletWithControllers(MultipartController.class); MockMultipartHttpServletRequest request = new MockMultipartHttpServletRequest(); request.setRequestURI("/stringArray"); request.addFile(new MockMultipartFile("content", "Juergen".getBytes())); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("Juergen", response.getContentAsString()); } @Test public void regularParameterAsStringArray() throws Exception { - initDispatcherServlet(MultipartController.class, null); + initServletWithControllers(MultipartController.class); MockHttpServletRequest request = new MockHttpServletRequest(); request.setRequestURI("/stringArray"); request.setMethod("POST"); request.addParameter("content", "Juergen"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("Juergen", response.getContentAsString()); } @Test public void multipartFilesAsStringArray() throws Exception { - initDispatcherServlet(MultipartController.class, null); + initServletWithControllers(MultipartController.class); MockMultipartHttpServletRequest request = new MockMultipartHttpServletRequest(); request.setRequestURI("/stringArray"); request.addFile(new MockMultipartFile("content", "Juergen".getBytes())); request.addFile(new MockMultipartFile("content", "Eva".getBytes())); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("Juergen-Eva", response.getContentAsString()); } @Test public void regularParametersAsStringArray() throws Exception { - initDispatcherServlet(MultipartController.class, null); + initServletWithControllers(MultipartController.class); MockHttpServletRequest request = new MockHttpServletRequest(); request.setRequestURI("/stringArray"); @@ -1371,14 +1383,14 @@ public class ServletHandlerMethodTests { request.addParameter("content", "Juergen"); request.addParameter("content", "Eva"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("Juergen-Eva", response.getContentAsString()); } @Test public void parameterCsvAsStringArray() throws Exception { - initDispatcherServlet(CsvController.class, new BeanDefinitionRegistrar() { - public void register(GenericWebApplicationContext wac) { + initServlet(new ApplicationContextInitializer() { + public void initialize(GenericWebApplicationContext wac) { RootBeanDefinition csDef = new RootBeanDefinition(FormattingConversionServiceFactoryBean.class); RootBeanDefinition wbiDef = new RootBeanDefinition(ConfigurableWebBindingInitializer.class); wbiDef.getPropertyValues().add("conversionService", csDef); @@ -1386,24 +1398,24 @@ public class ServletHandlerMethodTests { adapterDef.getPropertyValues().add("webBindingInitializer", wbiDef); wac.registerBeanDefinition("handlerAdapter", adapterDef); } - }); + }, CsvController.class); MockHttpServletRequest request = new MockHttpServletRequest(); request.setRequestURI("/integerArray"); request.setMethod("POST"); request.addParameter("content", "1,2"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("1-2", response.getContentAsString()); } @Test public void testMatchWithoutMethodLevelPath() throws Exception { - initDispatcherServlet(NoPathGetAndM2PostController.class, null); + initServletWithControllers(NoPathGetAndM2PostController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/t1/m2"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals(405, response.getStatus()); } @@ -2701,46 +2713,6 @@ public class ServletHandlerMethodTests { } } - private interface BeanDefinitionRegistrar { - void register(GenericWebApplicationContext context); - } - - @SuppressWarnings("serial") - private void initDispatcherServlet(final Class controllerClass, final BeanDefinitionRegistrar registrar) - throws ServletException { - - servlet = new DispatcherServlet() { - @Override - protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) { - GenericWebApplicationContext wac = new GenericWebApplicationContext(); - wac.registerBeanDefinition("controller", new RootBeanDefinition(controllerClass)); - - Class mappingType = RequestMappingHandlerMapping.class; - wac.registerBeanDefinition("handlerMapping", new RootBeanDefinition(mappingType)); - - Class adapterType = RequestMappingHandlerAdapter.class; - wac.registerBeanDefinition("handlerAdapter", new RootBeanDefinition(adapterType)); - - Class resolverType = ExceptionHandlerExceptionResolver.class; - wac.registerBeanDefinition("requestMappingResolver", new RootBeanDefinition(resolverType)); - - resolverType = ResponseStatusExceptionResolver.class; - wac.registerBeanDefinition("responseStatusResolver", new RootBeanDefinition(resolverType)); - - resolverType = DefaultHandlerExceptionResolver.class; - wac.registerBeanDefinition("defaultResolver", new RootBeanDefinition(resolverType)); - - if (registrar != null) { - registrar.register(wac); - } - - wac.refresh(); - return wac; - } - }; - servlet.init(new MockServletConfig()); - } - // Test cases deleted from the original SevletAnnotationControllerTests: // @Ignore("Controller interface => no method-level @RequestMapping annotation") diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/UriTemplateServletHandlerMethodTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/UriTemplateServletAnnotationControllerHandlerMethodTests.java similarity index 79% rename from org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/UriTemplateServletHandlerMethodTests.java rename to org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/UriTemplateServletAnnotationControllerHandlerMethodTests.java index f560e6912c..0a2510f4af 100644 --- a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/UriTemplateServletHandlerMethodTests.java +++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/UriTemplateServletAnnotationControllerHandlerMethodTests.java @@ -28,16 +28,15 @@ import java.util.HashMap; import java.util.Locale; import java.util.Map; -import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.junit.Test; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.beans.propertyeditors.CustomDateEditor; +import org.springframework.context.ApplicationContextInitializer; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; -import org.springframework.mock.web.MockServletConfig; import org.springframework.stereotype.Controller; import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.annotation.InitBinder; @@ -46,45 +45,51 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.support.GenericWebApplicationContext; -import org.springframework.web.servlet.DispatcherServlet; +import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.View; import org.springframework.web.servlet.ViewResolver; -import org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver; import org.springframework.web.servlet.mvc.annotation.UriTemplateServletAnnotationControllerTests; -import org.springframework.web.servlet.mvc.annotation.UriTemplateServletAnnotationControllerTests.VariableNamesController; -import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver; import org.springframework.web.servlet.view.AbstractView; /** - * The origin of this test class is {@link UriTemplateServletAnnotationControllerTests} with the tests in this class - * adapted to run against the HandlerMethod infrastructure rather than against the DefaultAnnotationHandlerMapping, - * the AnnotationMethodHandlerAdapter, and the AnnotationMethodHandlerExceptionResolver. Tests that are not supported - * are listed at the bottom. - * + * The origin of this test class is {@link UriTemplateServletAnnotationControllerTests}. + * + * Tests in this class run against the {@link HandlerMethod} infrastructure: + *
    + *
  • RequestMappingHandlerMapping + *
  • RequestMappingHandlerAdapter + *
  • ExceptionHandlerExceptionResolver + *
+ * + *

Rather than against the existing infrastructure: + *

    + *
  • DefaultAnnotationHandlerMapping + *
  • AnnotationMethodHandlerAdapter + *
  • AnnotationMethodHandlerExceptionResolver + *
+ * * @author Rossen Stoyanchev * @since 3.1 */ -public class UriTemplateServletHandlerMethodTests { - - private DispatcherServlet servlet; +public class UriTemplateServletAnnotationControllerHandlerMethodTests extends AbstractServletHandlerMethodTests { @Test public void simple() throws Exception { - initDispatcherServlet(SimpleUriTemplateController.class, null); + initServletWithControllers(SimpleUriTemplateController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/42"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("test-42", response.getContentAsString()); } @Test public void multiple() throws Exception { - initDispatcherServlet(MultipleUriTemplateController.class, null); + initServletWithControllers(MultipleUriTemplateController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/hotels/42/bookings/21-other"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("test-42-21-other", response.getContentAsString()); } @@ -96,16 +101,16 @@ public class UriTemplateServletHandlerMethodTests { pathVars.put("other", "other"); WebApplicationContext wac = - initDispatcherServlet(ViewRenderingController.class, new BeanDefinitionRegistrar() { - public void register(GenericWebApplicationContext context) { + initServlet(new ApplicationContextInitializer() { + public void initialize(GenericWebApplicationContext context) { RootBeanDefinition beanDef = new RootBeanDefinition(ModelValidatingViewResolver.class); beanDef.getConstructorArgumentValues().addGenericArgumentValue(pathVars); context.registerBeanDefinition("viewResolver", beanDef); } - }); + }, ViewRenderingController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/hotels/42/bookings/21-other"); - servlet.service(request, new MockHttpServletResponse()); + getServlet().service(request, new MockHttpServletResponse()); ModelValidatingViewResolver resolver = wac.getBean(ModelValidatingViewResolver.class); assertEquals(3, resolver.validatedAttrCount); @@ -113,153 +118,153 @@ public class UriTemplateServletHandlerMethodTests { @Test public void binding() throws Exception { - initDispatcherServlet(BindingUriTemplateController.class, null); + initServletWithControllers(BindingUriTemplateController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/hotels/42/dates/2008-11-18"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals(200, response.getStatus()); request = new MockHttpServletRequest("GET", "/hotels/42/dates/2008-foo-bar"); response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals(400, response.getStatus()); - initDispatcherServlet(NonBindingUriTemplateController.class, null); + initServletWithControllers(NonBindingUriTemplateController.class); request = new MockHttpServletRequest("GET", "/hotels/42/dates/2008-foo-bar"); response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals(500, response.getStatus()); } @Test public void ambiguous() throws Exception { - initDispatcherServlet(AmbiguousUriTemplateController.class, null); + initServletWithControllers(AmbiguousUriTemplateController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/hotels/new"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("specific", response.getContentAsString()); } @Test public void relative() throws Exception { - initDispatcherServlet(RelativePathUriTemplateController.class, null); + initServletWithControllers(RelativePathUriTemplateController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/hotels/42/bookings/21"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("test-42-21", response.getContentAsString()); request = new MockHttpServletRequest("GET", "/hotels/42/bookings/21.html"); response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("test-42-21", response.getContentAsString()); } @Test public void extension() throws Exception { - initDispatcherServlet(SimpleUriTemplateController.class, null); + initServletWithControllers(SimpleUriTemplateController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/42.xml"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("test-42", response.getContentAsString()); } @Test public void typeConversionError() throws Exception { - initDispatcherServlet(SimpleUriTemplateController.class, null); + initServletWithControllers(SimpleUriTemplateController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo.xml"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("Invalid response status code", HttpServletResponse.SC_BAD_REQUEST, response.getStatus()); } @Test public void explicitSubPath() throws Exception { - initDispatcherServlet(ExplicitSubPathController.class, null); + initServletWithControllers(ExplicitSubPathController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/hotels/42"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("test-42", response.getContentAsString()); } @Test public void implicitSubPath() throws Exception { - initDispatcherServlet(ImplicitSubPathController.class, null); + initServletWithControllers(ImplicitSubPathController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/hotels/42"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("test-42", response.getContentAsString()); } @Test public void crud() throws Exception { - initDispatcherServlet(CrudController.class, null); + initServletWithControllers(CrudController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/hotels"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("list", response.getContentAsString()); request = new MockHttpServletRequest("GET", "/hotels/"); response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("list", response.getContentAsString()); request = new MockHttpServletRequest("POST", "/hotels"); response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("create", response.getContentAsString()); request = new MockHttpServletRequest("GET", "/hotels/42"); response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("show-42", response.getContentAsString()); request = new MockHttpServletRequest("GET", "/hotels/42/"); response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("show-42", response.getContentAsString()); request = new MockHttpServletRequest("PUT", "/hotels/42"); response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("createOrUpdate-42", response.getContentAsString()); request = new MockHttpServletRequest("DELETE", "/hotels/42"); response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("remove-42", response.getContentAsString()); } @Test public void methodNotSupported() throws Exception { - initDispatcherServlet(MethodNotAllowedController.class, null); + initServletWithControllers(MethodNotAllowedController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/hotels/1"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals(200, response.getStatus()); request = new MockHttpServletRequest("POST", "/hotels/1"); response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals(405, response.getStatus()); request = new MockHttpServletRequest("GET", "/hotels"); response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals(200, response.getStatus()); request = new MockHttpServletRequest("POST", "/hotels"); response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals(405, response.getStatus()); @@ -267,26 +272,26 @@ public class UriTemplateServletHandlerMethodTests { @Test public void multiPaths() throws Exception { - initDispatcherServlet(MultiPathController.class, null); + initServletWithControllers(MultiPathController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/category/page/5"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("handle4-page-5", response.getContentAsString()); request = new MockHttpServletRequest("GET", "/category/page/5.html"); response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("handle4-page-5", response.getContentAsString()); } @Test public void customRegex() throws Exception { - initDispatcherServlet(CustomRegexController.class, null); + initServletWithControllers(CustomRegexController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/42"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("test-42", response.getContentAsString()); } @@ -295,11 +300,11 @@ public class UriTemplateServletHandlerMethodTests { */ @Test public void menuTree() throws Exception { - initDispatcherServlet(MenuTreeController.class, null); + initServletWithControllers(MenuTreeController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/book/menu/type/M5"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("M5", response.getContentAsString()); } @@ -308,16 +313,16 @@ public class UriTemplateServletHandlerMethodTests { */ @Test public void variableNames() throws Exception { - initDispatcherServlet(VariableNamesController.class, null); + initServletWithControllers(VariableNamesController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/test/foo"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("foo-foo", response.getContentAsString()); request = new MockHttpServletRequest("DELETE", "/test/bar"); response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("bar-bar", response.getContentAsString()); } @@ -326,11 +331,11 @@ public class UriTemplateServletHandlerMethodTests { */ @Test public void variableNamesWithUrlExtension() throws Exception { - initDispatcherServlet(VariableNamesController.class, null); + initServletWithControllers(VariableNamesController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/test/foo.json"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("foo-foo", response.getContentAsString()); } @@ -339,26 +344,26 @@ public class UriTemplateServletHandlerMethodTests { */ @Test public void doIt() throws Exception { - initDispatcherServlet(Spr6978Controller.class, null); + initServletWithControllers(Spr6978Controller.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo/100"); MockHttpServletResponse response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("loadEntity:foo:100", response.getContentAsString()); request = new MockHttpServletRequest("POST", "/foo/100"); response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("publish:foo:100", response.getContentAsString()); request = new MockHttpServletRequest("GET", "/module/100"); response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("loadModule:100", response.getContentAsString()); request = new MockHttpServletRequest("POST", "/module/100"); response = new MockHttpServletResponse(); - servlet.service(request, response); + getServlet().service(request, response); assertEquals("publish:module:100", response.getContentAsString()); } @@ -672,50 +677,6 @@ public class UriTemplateServletHandlerMethodTests { } } - private interface BeanDefinitionRegistrar { - public void register(GenericWebApplicationContext context); - } - - @SuppressWarnings("serial") - private WebApplicationContext initDispatcherServlet(final Class controllerClass, final BeanDefinitionRegistrar registrar) - throws ServletException { - - final GenericWebApplicationContext wac = new GenericWebApplicationContext(); - - servlet = new DispatcherServlet() { - @Override - protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) { - wac.registerBeanDefinition("controller", new RootBeanDefinition(controllerClass)); - - Class mappingType = RequestMappingHandlerMapping.class; - wac.registerBeanDefinition("handlerMapping", new RootBeanDefinition(mappingType)); - - Class adapterType = RequestMappingHandlerAdapter.class; - wac.registerBeanDefinition("handlerAdapter", new RootBeanDefinition(adapterType)); - - Class resolverType = ExceptionHandlerExceptionResolver.class; - wac.registerBeanDefinition("requestMappingResolver", new RootBeanDefinition(resolverType)); - - resolverType = ResponseStatusExceptionResolver.class; - wac.registerBeanDefinition("responseStatusResolver", new RootBeanDefinition(resolverType)); - - resolverType = DefaultHandlerExceptionResolver.class; - wac.registerBeanDefinition("defaultResolver", new RootBeanDefinition(resolverType)); - - if (registrar != null) { - registrar.register(wac); - } - - wac.refresh(); - return wac; - } - }; - - servlet.init(new MockServletConfig()); - - return wac; - } - // @Ignore("ControllerClassNameHandlerMapping") // public void controllerClassName() throws Exception { diff --git a/org.springframework.web/src/main/java/org/springframework/web/bind/annotation/FlashAttributes.java b/org.springframework.web/src/main/java/org/springframework/web/bind/annotation/FlashAttributes.java new file mode 100644 index 0000000000..32aa8bdcf6 --- /dev/null +++ b/org.springframework.web/src/main/java/org/springframework/web/bind/annotation/FlashAttributes.java @@ -0,0 +1,56 @@ +/* + * 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.bind.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation that indicates what attributes should be stored in the session or in + * some conversational storage in order to survive a client-side redirect. + * + * TODO ... + * + * @author Rossen Stoyanchev + * @since 3.1 + * + * @see org.springframework.web.bind.support.FlashStatus + */ +@Target({ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +@Documented +public @interface FlashAttributes { + + /** + * The names of flash attributes in the model to be stored. + * + * TODO ... + */ + String[] value() default {}; + + /** + * TODO ... + * + */ + Class[] types() default {}; + +} diff --git a/org.springframework.web/src/main/java/org/springframework/web/bind/support/FlashStatus.java b/org.springframework.web/src/main/java/org/springframework/web/bind/support/FlashStatus.java new file mode 100644 index 0000000000..b2ce47b370 --- /dev/null +++ b/org.springframework.web/src/main/java/org/springframework/web/bind/support/FlashStatus.java @@ -0,0 +1,51 @@ +/* + * Copyright 2002-2011 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.bind.support; + +import org.springframework.web.bind.annotation.FlashAttributes; + + +/** + * Simple interface to pass into controller methods to allow them to activate + * a mode in which model attributes identified as "flash attributes" are + * temporarily stored in the session to make them available to the next + * request. The most common scenario is a client-side redirect. + * + *

In active mode, model attributes that match the attribute names or + * types declared via @{@link FlashAttributes} are saved in the session. + * On the next request, any flash attributes found in the session are + * automatically added to the model of the target controller method and + * are also cleared from the session. + * + * TODO ... + * + * @author Rossen Stoyanchev + * @since 3.1 + */ +public interface FlashStatus { + + /** + * TODO ... + */ + void setActive(); + + /** + * TODO ... + */ + boolean isActive(); + +} diff --git a/org.springframework.web/src/main/java/org/springframework/web/bind/support/SimpleFlashStatus.java b/org.springframework.web/src/main/java/org/springframework/web/bind/support/SimpleFlashStatus.java new file mode 100644 index 0000000000..0f8c4b5f08 --- /dev/null +++ b/org.springframework.web/src/main/java/org/springframework/web/bind/support/SimpleFlashStatus.java @@ -0,0 +1,37 @@ +/* + * Copyright 2002-2011 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.bind.support; + +/** + * TODO ... + * + * @author Rossen Stoyanchev + * @since 3.1 + */ +public class SimpleFlashStatus implements FlashStatus { + + private boolean active = false; + + public void setActive() { + this.active = true; + } + + public boolean isActive() { + return this.active; + } + +} diff --git a/org.springframework.web/src/main/java/org/springframework/web/method/annotation/FlashAttributesHandler.java b/org.springframework.web/src/main/java/org/springframework/web/method/annotation/FlashAttributesHandler.java new file mode 100644 index 0000000000..759293de97 --- /dev/null +++ b/org.springframework.web/src/main/java/org/springframework/web/method/annotation/FlashAttributesHandler.java @@ -0,0 +1,108 @@ +/* + * Copyright 2002-2011 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.method.annotation; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; + +import org.springframework.core.annotation.AnnotationUtils; +import org.springframework.web.bind.annotation.FlashAttributes; +import org.springframework.web.context.request.WebRequest; + +/** + * Manages flash attributes declared via @{@link FlashAttributes}. + * + * TODO ... + * + * @author Rossen Stoyanchev + * @since 3.1 + */ +public class FlashAttributesHandler { + + public static final String FLASH_ATTRIBUTES_SESSION_KEY = FlashAttributesHandler.class.getName() + ".attributes"; + + private final Set attributeNames = new HashSet(); + + private final Set> attributeTypes = new HashSet>(); + + /** + * TODO ... + */ + public FlashAttributesHandler(Class handlerType) { + FlashAttributes annotation = AnnotationUtils.findAnnotation(handlerType, FlashAttributes.class); + if (annotation != null) { + this.attributeNames.addAll(Arrays.asList(annotation.value())); + this.attributeTypes.addAll(Arrays.>asList(annotation.types())); + } + } + + /** + * Whether the controller represented by this handler has declared flash + * attribute names or types via @{@link FlashAttributes}. + */ + public boolean hasFlashAttributes() { + return ((this.attributeNames.size() > 0) || (this.attributeTypes.size() > 0)); + } + + /** + * TODO ... + */ + public boolean isFlashAttribute(String attributeName, Class attributeType) { + return (this.attributeNames.contains(attributeName) || this.attributeTypes.contains(attributeType)); + } + + /** + * TODO ... + */ + public void storeAttributes(WebRequest request, Map attributes) { + Map filtered = filterAttributes(attributes); + if (!filtered.isEmpty()) { + request.setAttribute(FLASH_ATTRIBUTES_SESSION_KEY, filtered, WebRequest.SCOPE_SESSION); + } + } + + private Map filterAttributes(Map attributes) { + Map result = new LinkedHashMap(); + for (String name : attributes.keySet()) { + Object value = attributes.get(name); + Class type = (value != null) ? value.getClass() : null; + if (isFlashAttribute(name, type)) { + result.put(name, value); + } + } + return result; + } + + /** + * TODO ... + */ + @SuppressWarnings("unchecked") + public Map retrieveAttributes(WebRequest request) { + return (Map) request.getAttribute(FLASH_ATTRIBUTES_SESSION_KEY, WebRequest.SCOPE_SESSION); + } + + /** + * TODO ... + */ + public void cleanupAttributes(WebRequest request) { + request.removeAttribute(FLASH_ATTRIBUTES_SESSION_KEY, WebRequest.SCOPE_SESSION); + } + +} \ No newline at end of file diff --git a/org.springframework.web/src/main/java/org/springframework/web/method/annotation/ModelFactory.java b/org.springframework.web/src/main/java/org/springframework/web/method/annotation/ModelFactory.java index 49ee5128d4..a85592cc87 100644 --- a/org.springframework.web/src/main/java/org/springframework/web/method/annotation/ModelFactory.java +++ b/org.springframework.web/src/main/java/org/springframework/web/method/annotation/ModelFactory.java @@ -26,6 +26,7 @@ import org.springframework.beans.BeanUtils; import org.springframework.core.Conventions; import org.springframework.core.GenericTypeResolver; import org.springframework.core.MethodParameter; +import org.springframework.ui.Model; import org.springframework.ui.ModelMap; import org.springframework.util.StringUtils; import org.springframework.validation.BindingResult; @@ -34,6 +35,7 @@ import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.SessionAttributes; +import org.springframework.web.bind.support.FlashStatus; import org.springframework.web.bind.support.SessionStatus; import org.springframework.web.bind.support.WebDataBinderFactory; import org.springframework.web.context.request.NativeWebRequest; @@ -42,15 +44,16 @@ import org.springframework.web.method.support.InvocableHandlerMethod; import org.springframework.web.method.support.ModelAndViewContainer; /** - * Contains methods for creating and updating a model. A {@link ModelFactory} is associated with a specific controller - * through knowledge of its @{@link ModelAttribute} methods and @{@link SessionAttributes}. + * Provides methods to initialize the {@link Model} before a controller method + * invocation and to update it after the controller method has been invoked. * - *

{@link #initModel(NativeWebRequest, ModelAndViewContainer, HandlerMethod)} populates the model - * with handler session attributes and by invoking model attribute methods. + *

On initialization the model may be populated with session attributes + * stored during a previous request as a result of a {@link SessionAttributes} + * annotation. @{@link ModelAttribute} methods in the same controller may + * also be invoked to populate the model. * - *

{@link #updateModel(NativeWebRequest, ModelAndViewContainer, SessionStatus)} updates - * the model (usually after the {@link RequestMapping} method has been called) promoting attributes - * to the session and adding {@link BindingResult} attributes as necessary. + *

On update attributes may be removed from or stored in the session. + * {@link BindingResult} attributes may also be added as necessary. * * @author Rossen Stoyanchev * @since 3.1 @@ -61,45 +64,52 @@ public final class ModelFactory { private final WebDataBinderFactory binderFactory; - private final SessionAttributesHandler sessionHandler; + private final SessionAttributesHandler sessionAttributesHandler; + + private final FlashAttributesHandler flashAttributesHandler; /** * Create a ModelFactory instance with the provided {@link ModelAttribute} methods. - * @param attributeMethods {@link ModelAttribute}-annotated methods to invoke when populating a model - * @param binderFactory the binder factory to use when adding {@link BindingResult}s to the model - * @param sessionHandler a session attributes handler to synch attributes with the session + * @param attributeMethods {@link ModelAttribute} methods to initialize model instances with + * @param binderFactory used to add {@link BindingResult} attributes to the model + * @param sessionAttributesHandler used to access handler-specific session attributes + * @param flashAttributesHandler used to access flash attributes */ public ModelFactory(List attributeMethods, WebDataBinderFactory binderFactory, - SessionAttributesHandler sessionHandler) { + SessionAttributesHandler sessionAttributesHandler, + FlashAttributesHandler flashAttributesHandler) { this.attributeMethods = (attributeMethods != null) ? attributeMethods : new ArrayList(); this.binderFactory = binderFactory; - this.sessionHandler = sessionHandler; + this.sessionAttributesHandler = sessionAttributesHandler; + this.flashAttributesHandler = flashAttributesHandler; } /** - * Populate the model for a request with attributes obtained in the following order: + * Populate the model in the following order: *

    - *
  1. Retrieve "known" (i.e. have been in the model in prior requests) handler session attributes from the session - *
  2. Create attributes by invoking model attribute methods - *
  3. Check for not yet known handler session attributes in the session + *
  4. Retrieve "remembered" (i.e. previously stored) controller-specific session attributes + *
  5. Invoke @{@link ModelAttribute} methods + *
  6. Check the session for any controller-specific attributes not yet "remembered". *
- *

As a general rule model attributes are added only once following the above order. - * * @param request the current request - * @param mavContainer the {@link ModelAndViewContainer} to add model attributes to - * @param requestMethod the request handling method for which the model is needed - * @throws Exception if an exception occurs while invoking model attribute methods + * @param mavContainer contains the model to initialize + * @param handlerMethod the @{@link RequestMapping} method for which the model is initialized + * @throws Exception may arise from the invocation of @{@link ModelAttribute} methods */ - public void initModel(NativeWebRequest request, ModelAndViewContainer mavContainer, HandlerMethod requestMethod) + public void initModel(NativeWebRequest request, ModelAndViewContainer mavContainer, HandlerMethod handlerMethod) throws Exception { - Map sessionAttributes = this.sessionHandler.retrieveHandlerSessionAttributes(request); - mavContainer.addAllAttributes(sessionAttributes); + Map sessionAttrs = this.sessionAttributesHandler.retrieveAttributes(request); + mavContainer.addAllAttributes(sessionAttrs); + + Map flashAttrs = this.flashAttributesHandler.retrieveAttributes(request); + mavContainer.addAllAttributes(flashAttrs); + this.flashAttributesHandler.cleanupAttributes(request); invokeAttributeMethods(request, mavContainer); - checkMissingSessionAttributes(request, mavContainer, requestMethod); + checkHandlerSessionAttributes(request, mavContainer, handlerMethod); } /** @@ -125,26 +135,26 @@ public final class ModelFactory { } /** - * Checks if any {@link ModelAttribute}-annotated handler method arguments are eligible as handler session - * attributes, as defined by @{@link SessionAttributes}, and are not yet present in the model. - * If so, attempts to retrieve them from the session and add them to the model. + * Checks if any @{@link ModelAttribute} handler method arguments declared as + * session attributes via @{@link SessionAttributes} but are not already in the + * model. If found add them to the model, raise an exception otherwise. * * @throws HttpSessionRequiredException raised if a handler session attribute could is missing */ - private void checkMissingSessionAttributes(NativeWebRequest request, + private void checkHandlerSessionAttributes(NativeWebRequest request, ModelAndViewContainer mavContainer, - HandlerMethod requestMethod) throws HttpSessionRequiredException { - for (MethodParameter parameter : requestMethod.getMethodParameters()) { + HandlerMethod handlerMethod) throws HttpSessionRequiredException { + for (MethodParameter parameter : handlerMethod.getMethodParameters()) { if (parameter.hasParameterAnnotation(ModelAttribute.class)) { - String name = getNameForParameter(parameter); - if (!mavContainer.containsAttribute(name)) { - if (sessionHandler.isHandlerSessionAttribute(name, parameter.getParameterType())) { - Object attrValue = sessionHandler.retrieveAttribute(request, name); + String attrName = getNameForParameter(parameter); + if (!mavContainer.containsAttribute(attrName)) { + if (sessionAttributesHandler.isHandlerSessionAttribute(attrName, parameter.getParameterType())) { + Object attrValue = sessionAttributesHandler.retrieveAttribute(request, attrName); if (attrValue == null){ throw new HttpSessionRequiredException( - "Session attribute '" + name + "' not found in session: " + requestMethod); + "Session attribute '" + attrName + "' not found in session: " + handlerMethod); } - mavContainer.addAttribute(name, attrValue); + mavContainer.addAttribute(attrName, attrValue); } } } @@ -196,15 +206,20 @@ public final class ModelFactory { * @param sessionStatus whether session processing is complete * @throws Exception if the process of creating {@link BindingResult} attributes causes an error */ - public void updateModel(NativeWebRequest request, ModelAndViewContainer mavContainer, SessionStatus sessionStatus) - throws Exception { + public void updateModel(NativeWebRequest request, ModelAndViewContainer mavContainer, + SessionStatus sessionStatus, FlashStatus flashStatus) throws Exception { if (sessionStatus.isComplete()){ - this.sessionHandler.cleanupHandlerSessionAttributes(request); + this.sessionAttributesHandler.cleanupAttributes(request); + } + else { + this.sessionAttributesHandler.storeAttributes(request, mavContainer.getModel()); } - this.sessionHandler.storeHandlerSessionAttributes(request, mavContainer.getModel()); - + if (flashStatus.isActive()) { + this.flashAttributesHandler.storeAttributes(request, mavContainer.getModel()); + } + if (mavContainer.isResolveView()) { updateBindingResult(request, mavContainer.getModel()); } @@ -238,7 +253,7 @@ public final class ModelFactory { } Class attrType = (value != null) ? value.getClass() : null; - if (this.sessionHandler.isHandlerSessionAttribute(attributeName, attrType)) { + if (this.sessionAttributesHandler.isHandlerSessionAttribute(attributeName, attrType)) { return true; } diff --git a/org.springframework.web/src/main/java/org/springframework/web/method/annotation/SessionAttributesHandler.java b/org.springframework.web/src/main/java/org/springframework/web/method/annotation/SessionAttributesHandler.java index 933796602c..b96c654998 100644 --- a/org.springframework.web/src/main/java/org/springframework/web/method/annotation/SessionAttributesHandler.java +++ b/org.springframework.web/src/main/java/org/springframework/web/method/annotation/SessionAttributesHandler.java @@ -32,22 +32,15 @@ import org.springframework.web.bind.support.SessionStatus; import org.springframework.web.context.request.WebRequest; /** - * Provides operations for managing handler-specific session attributes as defined by the - * {@link SessionAttributes} type-level annotation performing all operations through an - * instance of a {@link SessionAttributeStore}. + * Manages handler-specific session attributes declared via @{@link SessionAttributes}. + * Actual storage is performed through an instance of {@link SessionAttributeStore}. * - *

A typical scenario involves a handler adding attributes to the {@link Model} during - * a request. At the end of the request, model attributes that match to session attribute - * names defined through an {@link SessionAttributes} annotation are automatically - * "promoted" to the session. Handler session attributes are then removed when - * {@link SessionStatus#setComplete()} is called by a handler. - * - *

Therefore "session attributes" for this class means only attributes that have been - * previously confirmed by calls to {@link #isHandlerSessionAttribute(String, Class)}. - * Attribute names that have never been resolved that way will be filtered out from - * operations of this class. That means initially the actual set of resolved session - * attribute names is empty and it grows gradually as attributes are added to - * the {@link Model} and then considered for being added to the session. + *

A typical scenario begins with a controller adding attributes to the {@link Model}. + * At the end of the request, model attributes are checked to see if any of them match + * the names and types declared via @{@link SessionAttributes}. Matching model + * attributes are "promoted" to the session and remain there until the controller + * calls {@link SessionStatus#setComplete()} to indicate the session attributes are + * no longer needed and can be removed. * * @author Rossen Stoyanchev * @since 3.1 @@ -56,48 +49,48 @@ public class SessionAttributesHandler { private final Set attributeNames = new HashSet(); - @SuppressWarnings("rawtypes") - private final Set attributeTypes = new HashSet(); + private final Set> attributeTypes = new HashSet>(); private final Set resolvedAttributeNames = Collections.synchronizedSet(new HashSet(4)); - private final SessionAttributeStore attributeStore; + private final SessionAttributeStore sessionAttributeStore; /** - * Creates a {@link SessionAttributesHandler} instance for the specified handlerType. - *

Inspects the given handler type for the presence of a {@link SessionAttributes} annotation and - * stores that information for use in subsequent calls to {@link #isHandlerSessionAttribute(String, Class)}. - * If the handler type does not contain such an annotation, - * {@link #isHandlerSessionAttribute(String, Class)} always returns {@code false} and all other operations - * on handler session attributes have no effect on the backend session. - *

Use {@link #hasSessionAttributes()} to check if the handler type has defined any session attribute names - * of interest through a {@link SessionAttributes} annotation. + * Creates a {@link SessionAttributesHandler} instance for the specified handler type + * Inspects the given handler type for the presence of an @{@link SessionAttributes} + * and stores that information to identify model attribute that need to be stored, + * retrieved, or removed from the session. * @param handlerType the handler type to inspect for a {@link SessionAttributes} annotation - * @param attributeStore the {@link SessionAttributeStore} to delegate to for the actual backend session access + * @param sessionAttributeStore used for session access */ - public SessionAttributesHandler(Class handlerType, SessionAttributeStore attributeStore) { - Assert.notNull(attributeStore, "SessionAttributeStore may not be null."); - this.attributeStore = attributeStore; + public SessionAttributesHandler(Class handlerType, SessionAttributeStore sessionAttributeStore) { + Assert.notNull(sessionAttributeStore, "SessionAttributeStore may not be null."); + this.sessionAttributeStore = sessionAttributeStore; SessionAttributes annotation = AnnotationUtils.findAnnotation(handlerType, SessionAttributes.class); if (annotation != null) { this.attributeNames.addAll(Arrays.asList(annotation.value())); - this.attributeTypes.addAll(Arrays.asList(annotation.types())); + this.attributeTypes.addAll(Arrays.>asList(annotation.types())); } } /** - * Returns true if the handler type has specified any session attribute names of interest through a - * {@link SessionAttributes} annotation. + * Whether the controller represented by this handler has declared session + * attribute names or types of interest via @{@link SessionAttributes}. */ public boolean hasSessionAttributes() { return ((this.attributeNames.size() > 0) || (this.attributeTypes.size() > 0)); } /** - * Indicate whether or not an attribute is a handler session attribute of interest as defined - * in a {@link SessionAttributes} annotation. Attributes names successfully resolved through - * this method are remembered and in other operations. + * Whether the controller represented by this instance has declared a specific + * attribute as a session attribute via @{@link SessionAttributes}. + * + *

Attributes successfully resolved through this method are "remembered" and + * used by calls to {@link #retrieveAttributes(WebRequest)} and + * {@link #cleanupAttributes(WebRequest)}. In other words unless attributes + * have been resolved and stored before, retrieval and cleanup have no impact. + * * @param attributeName the attribute name to check, must not be null * @param attributeType the type for the attribute, not required but should be provided when * available as session attributes of interest can be matched by type @@ -114,29 +107,32 @@ public class SessionAttributesHandler { } /** - * Retrieves the specified attribute through the underlying {@link SessionAttributeStore}. - * Although not required use of this method implies a prior call to - * {@link #isHandlerSessionAttribute(String, Class)} has been made to see if the attribute - * name is a handler-specific session attribute of interest. - * @param request the request for the session operation - * @param attributeName the name of the attribute - * @return the attribute value or {@code null} if none + * Stores a subset of the given attributes in the session. Attributes not + * declared as session attributes via @{@link SessionAttributes} are ignored. + * @param request the current request + * @param attributes candidate attributes for session storage */ - public Object retrieveAttribute(WebRequest request, String attributeName) { - return this.attributeStore.retrieveAttribute(request, attributeName); + public void storeAttributes(WebRequest request, Map attributes) { + for (String name : attributes.keySet()) { + Object value = attributes.get(name); + Class attrType = (value != null) ? value.getClass() : null; + + if (isHandlerSessionAttribute(name, attrType)) { + this.sessionAttributeStore.storeAttribute(request, name, value); + } + } } /** - * Retrieve attributes for the underlying handler type from the backend session. - *

Only attributes that have previously been successfully resolved via calls to - * {@link #isHandlerSessionAttribute(String, Class)} are considered. + * Retrieves "remembered" (i.e. previously stored) session attributes + * for the controller represented by this handler. * @param request the current request - * @return a map with attributes or an empty map + * @return a map with handler session attributes; possibly empty. */ - public Map retrieveHandlerSessionAttributes(WebRequest request) { + public Map retrieveAttributes(WebRequest request) { Map attributes = new HashMap(); for (String name : this.resolvedAttributeNames) { - Object value = this.attributeStore.retrieveAttribute(request, name); + Object value = this.sessionAttributeStore.retrieveAttribute(request, name); if (value != null) { attributes.put(name, value); } @@ -145,34 +141,24 @@ public class SessionAttributesHandler { } /** - * Clean up attributes for the underlying handler type from the backend session. - *

Only attributes that have previously been successfully resolved via calls to - * {@link #isHandlerSessionAttribute(String, Class)} are removed. + * Cleans "remembered" (i.e. previously stored) session attributes + * for the controller represented by this handler. * @param request the current request */ - public void cleanupHandlerSessionAttributes(WebRequest request) { + public void cleanupAttributes(WebRequest request) { for (String attributeName : this.resolvedAttributeNames) { - this.attributeStore.cleanupAttribute(request, attributeName); + this.sessionAttributeStore.cleanupAttribute(request, attributeName); } } /** - * Store attributes in the backend session. - *

Only attributes that have previously been successfully resolved via calls to - * {@link #isHandlerSessionAttribute(String, Class)} are stored. All other attributes - * from the input map are ignored. + * A pass-through call to the underlying {@link SessionAttributeStore}. * @param request the current request - * @param attributes the attribute pairs to consider for storing + * @param attributeName the name of the attribute of interest + * @return the attribute value or {@code null} */ - public void storeHandlerSessionAttributes(WebRequest request, Map attributes) { - for (String name : attributes.keySet()) { - Object value = attributes.get(name); - Class attrType = (value != null) ? value.getClass() : null; - - if (isHandlerSessionAttribute(name, attrType)) { - this.attributeStore.storeAttribute(request, name, value); - } - } + Object retrieveAttribute(WebRequest request, String attributeName) { + return this.sessionAttributeStore.retrieveAttribute(request, attributeName); } - + } \ No newline at end of file diff --git a/org.springframework.web/src/test/java/org/springframework/web/method/annotation/ModelFactoryTests.java b/org.springframework.web/src/test/java/org/springframework/web/method/annotation/ModelFactoryTests.java index bfd2e9e5ca..351911a519 100644 --- a/org.springframework.web/src/test/java/org/springframework/web/method/annotation/ModelFactoryTests.java +++ b/org.springframework.web/src/test/java/org/springframework/web/method/annotation/ModelFactoryTests.java @@ -41,6 +41,7 @@ import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.SessionAttributes; import org.springframework.web.bind.support.DefaultSessionAttributeStore; import org.springframework.web.bind.support.SessionAttributeStore; +import org.springframework.web.bind.support.SimpleFlashStatus; import org.springframework.web.bind.support.SimpleSessionStatus; import org.springframework.web.bind.support.WebDataBinderFactory; import org.springframework.web.context.request.NativeWebRequest; @@ -63,8 +64,10 @@ public class ModelFactoryTests { private InvocableHandlerMethod handleSessionAttrMethod; - private SessionAttributesHandler handlerSessionAttributeStore; - + private SessionAttributesHandler sessionAttrsHandler; + + private FlashAttributesHandler flashAttrsHandler; + private SessionAttributeStore sessionAttributeStore; private ModelAndViewContainer mavContainer; @@ -78,13 +81,14 @@ public class ModelFactoryTests { Method method = handlerType.getDeclaredMethod("handleSessionAttr", String.class); handleSessionAttrMethod = new InvocableHandlerMethod(handler, method); sessionAttributeStore = new DefaultSessionAttributeStore(); - handlerSessionAttributeStore = new SessionAttributesHandler(handlerType, sessionAttributeStore); + sessionAttrsHandler = new SessionAttributesHandler(handlerType, sessionAttributeStore); + flashAttrsHandler = new FlashAttributesHandler(handlerType); mavContainer = new ModelAndViewContainer(); webRequest = new ServletWebRequest(new MockHttpServletRequest()); } @Test - public void addAttributeToModel() throws Exception { + public void modelAttributeMethod() throws Exception { ModelFactory modelFactory = createModelFactory("modelAttr", Model.class); modelFactory.initModel(webRequest, mavContainer, handleMethod); @@ -92,7 +96,7 @@ public class ModelFactoryTests { } @Test - public void returnAttributeWithName() throws Exception { + public void modelAttributeMethodWithSpecifiedName() throws Exception { ModelFactory modelFactory = createModelFactory("modelAttrWithName"); modelFactory.initModel(webRequest, mavContainer, handleMethod); @@ -100,7 +104,7 @@ public class ModelFactoryTests { } @Test - public void returnAttributeWithNameByConvention() throws Exception { + public void modelAttributeMethodWithNameByConvention() throws Exception { ModelFactory modelFactory = createModelFactory("modelAttrConvention"); modelFactory.initModel(webRequest, mavContainer, handleMethod); @@ -108,7 +112,7 @@ public class ModelFactoryTests { } @Test - public void returnNullAttributeValue() throws Exception { + public void modelAttributeMethodWithNullReturnValue() throws Exception { ModelFactory modelFactory = createModelFactory("nullModelAttr"); modelFactory.initModel(webRequest, mavContainer, handleMethod); @@ -117,11 +121,11 @@ public class ModelFactoryTests { } @Test - public void retrieveAttributeFromSession() throws Exception { + public void sessionAttribute() throws Exception { sessionAttributeStore.storeAttribute(webRequest, "sessionAttr", "sessionAttrValue"); // Resolve successfully handler session attribute once - assertTrue(handlerSessionAttributeStore.isHandlerSessionAttribute("sessionAttr", null)); + assertTrue(sessionAttrsHandler.isHandlerSessionAttribute("sessionAttr", null)); ModelFactory modelFactory = createModelFactory("modelAttr", Model.class); modelFactory.initModel(webRequest, mavContainer, handleMethod); @@ -131,7 +135,7 @@ public class ModelFactoryTests { @Test public void requiredSessionAttribute() throws Exception { - ModelFactory modelFactory = new ModelFactory(null, null, handlerSessionAttributeStore); + ModelFactory modelFactory = new ModelFactory(null, null, sessionAttrsHandler, flashAttrsHandler); try { modelFactory.initModel(webRequest, mavContainer, handleSessionAttrMethod); @@ -145,19 +149,18 @@ public class ModelFactoryTests { } @Test - public void updateBindingResult() throws Exception { + public void updateModelBindingResultKeys() throws Exception { String attrName = "attr1"; Object attrValue = new Object(); mavContainer.addAttribute(attrName, attrValue); WebDataBinder dataBinder = new WebDataBinder(attrValue, attrName); - WebDataBinderFactory binderFactory = createMock(WebDataBinderFactory.class); expect(binderFactory.createBinder(webRequest, attrValue, attrName)).andReturn(dataBinder); replay(binderFactory); - ModelFactory modelFactory = new ModelFactory(null, binderFactory, handlerSessionAttributeStore); - modelFactory.updateModel(webRequest, mavContainer, new SimpleSessionStatus()); + ModelFactory modelFactory = new ModelFactory(null, binderFactory, sessionAttrsHandler, flashAttrsHandler); + modelFactory.updateModel(webRequest, mavContainer, new SimpleSessionStatus(), new SimpleFlashStatus()); assertEquals(attrValue, mavContainer.getModel().remove(attrName)); assertSame(dataBinder.getBindingResult(), mavContainer.getModel().remove(bindingResultKey(attrName))); @@ -165,6 +168,36 @@ public class ModelFactoryTests { verify(binderFactory); } + + @Test + public void updateModelSessionStatusComplete() throws Exception { + String attrName = "sessionAttr"; + String attrValue = "sessionAttrValue"; + + mavContainer.addAttribute(attrName, attrValue); + sessionAttributeStore.storeAttribute(webRequest, attrName, attrValue); + + // Resolve successfully handler session attribute once + assertTrue(sessionAttrsHandler.isHandlerSessionAttribute(attrName, null)); + + WebDataBinder dataBinder = new WebDataBinder(attrValue, attrName); + WebDataBinderFactory binderFactory = createMock(WebDataBinderFactory.class); + expect(binderFactory.createBinder(webRequest, attrValue, attrName)).andReturn(dataBinder); + replay(binderFactory); + + SimpleSessionStatus status = new SimpleSessionStatus(); + status.setComplete(); + + // TODO: test with active FlashStatus + + ModelFactory modelFactory = new ModelFactory(null, binderFactory, sessionAttrsHandler, flashAttrsHandler); + modelFactory.updateModel(webRequest, mavContainer, status, new SimpleFlashStatus()); + + assertEquals(attrValue, mavContainer.getAttribute(attrName)); + assertNull(sessionAttributeStore.retrieveAttribute(webRequest, attrName)); + + verify(binderFactory); + } private String bindingResultKey(String key) { return BindingResult.MODEL_KEY_PREFIX + key; @@ -181,7 +214,7 @@ public class ModelFactoryTests { handlerMethod.setDataBinderFactory(null); handlerMethod.setParameterNameDiscoverer(new LocalVariableTableParameterNameDiscoverer()); - return new ModelFactory(Arrays.asList(handlerMethod), null, handlerSessionAttributeStore); + return new ModelFactory(Arrays.asList(handlerMethod), null, sessionAttrsHandler, flashAttrsHandler); } @SessionAttributes("sessionAttr") @SuppressWarnings("unused") diff --git a/org.springframework.web/src/test/java/org/springframework/web/method/annotation/HandlerSessionAttributeStoreTests.java b/org.springframework.web/src/test/java/org/springframework/web/method/annotation/SessionAttributesHandlerTests.java similarity index 94% rename from org.springframework.web/src/test/java/org/springframework/web/method/annotation/HandlerSessionAttributeStoreTests.java rename to org.springframework.web/src/test/java/org/springframework/web/method/annotation/SessionAttributesHandlerTests.java index 5dfba5a935..06575004b9 100644 --- a/org.springframework.web/src/test/java/org/springframework/web/method/annotation/HandlerSessionAttributeStoreTests.java +++ b/org.springframework.web/src/test/java/org/springframework/web/method/annotation/SessionAttributesHandlerTests.java @@ -42,7 +42,7 @@ import org.springframework.web.context.request.ServletWebRequest; * * @author Rossen Stoyanchev */ -public class HandlerSessionAttributeStoreTests { +public class SessionAttributesHandlerTests { private Class handlerType = SessionAttributeHandler.class; @@ -77,7 +77,7 @@ public class HandlerSessionAttributeStoreTests { assertTrue(sessionAttributesHandler.isHandlerSessionAttribute("attr1", null)); assertTrue(sessionAttributesHandler.isHandlerSessionAttribute("attr3", TestBean.class)); - Map attributes = sessionAttributesHandler.retrieveHandlerSessionAttributes(request); + Map attributes = sessionAttributesHandler.retrieveAttributes(request); assertEquals(new HashSet(asList("attr1", "attr3")), attributes.keySet()); } @@ -92,7 +92,7 @@ public class HandlerSessionAttributeStoreTests { assertTrue(sessionAttributesHandler.isHandlerSessionAttribute("attr1", null)); assertTrue(sessionAttributesHandler.isHandlerSessionAttribute("attr3", TestBean.class)); - sessionAttributesHandler.cleanupHandlerSessionAttributes(request); + sessionAttributesHandler.cleanupAttributes(request); assertNull(sessionAttributeStore.retrieveAttribute(request, "attr1")); assertNotNull(sessionAttributeStore.retrieveAttribute(request, "attr2")); @@ -111,7 +111,7 @@ public class HandlerSessionAttributeStoreTests { assertTrue(sessionAttributesHandler.isHandlerSessionAttribute("attr2", null)); assertTrue(sessionAttributesHandler.isHandlerSessionAttribute("attr3", TestBean.class)); - sessionAttributesHandler.storeHandlerSessionAttributes(request, model); + sessionAttributesHandler.storeAttributes(request, model); assertEquals("value1", sessionAttributeStore.retrieveAttribute(request, "attr1")); assertEquals("value2", sessionAttributeStore.retrieveAttribute(request, "attr2"));