/* * Copyright 2002-2017 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 java.beans.ConstructorProperties; import java.beans.PropertyEditorSupport; import java.io.IOException; import java.io.Serializable; import java.io.Writer; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.lang.reflect.Method; import java.net.URI; import java.net.URISyntaxException; import java.nio.charset.StandardCharsets; import java.security.Principal; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Date; import java.util.GregorianCalendar; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; 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; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import javax.validation.Valid; 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; import org.springframework.beans.factory.BeanCreationException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.config.BeanDefinition; 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; import org.springframework.format.support.FormattingConversionServiceFactoryBean; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpInputMessage; import org.springframework.http.HttpOutputMessage; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.http.converter.ByteArrayHttpMessageConverter; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.HttpMessageNotReadableException; import org.springframework.http.converter.HttpMessageNotWritableException; import org.springframework.http.converter.StringHttpMessageConverter; import org.springframework.http.converter.xml.MarshallingHttpMessageConverter; import org.springframework.mock.web.test.MockHttpServletRequest; import org.springframework.mock.web.test.MockHttpServletResponse; import org.springframework.mock.web.test.MockMultipartFile; import org.springframework.mock.web.test.MockMultipartHttpServletRequest; import org.springframework.mock.web.test.MockServletConfig; import org.springframework.mock.web.test.MockServletContext; import org.springframework.oxm.jaxb.Jaxb2Marshaller; import org.springframework.stereotype.Controller; import org.springframework.tests.sample.beans.DerivedTestBean; import org.springframework.tests.sample.beans.GenericBean; import org.springframework.tests.sample.beans.ITestBean; import org.springframework.tests.sample.beans.TestBean; import org.springframework.ui.ExtendedModelMap; import org.springframework.ui.Model; import org.springframework.ui.ModelMap; import org.springframework.util.MultiValueMap; import org.springframework.util.SerializationTestUtils; import org.springframework.util.StringUtils; import org.springframework.validation.BindingResult; import org.springframework.validation.Errors; import org.springframework.validation.FieldError; import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; import org.springframework.web.accept.ContentNegotiationManagerFactoryBean; import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.annotation.CookieValue; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.InitBinder; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.SessionAttributes; import org.springframework.web.bind.support.ConfigurableWebBindingInitializer; import org.springframework.web.bind.support.WebArgumentResolver; import org.springframework.web.bind.support.WebBindingInitializer; 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.support.HandlerMethodArgumentResolver; import org.springframework.web.multipart.support.StringMultipartFileEditor; 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.support.RedirectAttributes; import org.springframework.web.servlet.support.RequestContextUtils; import org.springframework.web.servlet.view.InternalResourceViewResolver; import static org.junit.Assert.assertArrayEquals; 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; /** * @author Rossen Stoyanchev */ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServletHandlerMethodTests { @Test public void emptyValueMapping() throws Exception { initServletWithControllers(ControllerWithEmptyValueMapping.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo"); request.setContextPath("/foo"); request.setServletPath(""); MockHttpServletResponse response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("test", response.getContentAsString()); } @Test public void errorThrownFromHandlerMethod() throws Exception { initServletWithControllers(ControllerWithErrorThrown.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo"); request.setContextPath("/foo"); request.setServletPath(""); MockHttpServletResponse response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("test", response.getContentAsString()); } @Test public void customAnnotationController() throws Exception { initServletWithControllers(CustomAnnotationController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath.do"); MockHttpServletResponse response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("Invalid response status code", HttpServletResponse.SC_OK, response.getStatus()); } @Test public void requiredParamMissing() throws Exception { WebApplicationContext webAppContext = initServletWithControllers(RequiredParamController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath.do"); MockHttpServletResponse response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("Invalid response status code", HttpServletResponse.SC_BAD_REQUEST, response.getStatus()); assertTrue(webAppContext.isSingleton(RequiredParamController.class.getSimpleName())); } @Test public void typeConversionError() throws Exception { initServletWithControllers(RequiredParamController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath.do"); request.addParameter("id", "foo"); MockHttpServletResponse response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("Invalid response status code", HttpServletResponse.SC_BAD_REQUEST, response.getStatus()); } @Test public void optionalParamPresent() throws Exception { 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(); getServlet().service(request, response); assertEquals("val-true-otherVal", response.getContentAsString()); } @Test public void optionalParamMissing() throws Exception { initServletWithControllers(OptionalParamController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath.do"); MockHttpServletResponse response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("null-false-null", response.getContentAsString()); } @Test public void defaultParameters() throws Exception { initServletWithControllers(DefaultValueParamController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath.do"); MockHttpServletResponse response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("foo--bar", response.getContentAsString()); } @Test public void defaultExpressionParameters() throws Exception { initServlet(new ApplicationContextInitializer<GenericWebApplicationContext>() { @Override 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 { getServlet().service(request, response); } finally { System.clearProperty("myHeader"); } assertEquals("foo-bar-/myApp", response.getContentAsString()); } @Test public void typeNestedSetBinding() throws Exception { initServlet(new ApplicationContextInitializer<GenericWebApplicationContext>() { @Override public void initialize(GenericWebApplicationContext context) { RootBeanDefinition csDef = new RootBeanDefinition(FormattingConversionServiceFactoryBean.class); csDef.getPropertyValues().add("converters", new TestBeanConverter()); RootBeanDefinition wbiDef = new RootBeanDefinition(ConfigurableWebBindingInitializer.class); wbiDef.getPropertyValues().add("conversionService", csDef); RootBeanDefinition adapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class); adapterDef.getPropertyValues().add("webBindingInitializer", wbiDef); context.registerBeanDefinition("handlerAdapter", adapterDef); } }, NestedSetController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath.do"); request.addParameter("testBeanSet", "1", "2"); MockHttpServletResponse response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("[1, 2]-org.springframework.tests.sample.beans.TestBean", response.getContentAsString()); } @Test // SPR-12903 public void pathVariableWithCustomConverter() throws Exception { initServlet(new ApplicationContextInitializer<GenericWebApplicationContext>() { @Override public void initialize(GenericWebApplicationContext context) { RootBeanDefinition csDef = new RootBeanDefinition(FormattingConversionServiceFactoryBean.class); csDef.getPropertyValues().add("converters", new AnnotatedExceptionRaisingConverter()); RootBeanDefinition wbiDef = new RootBeanDefinition(ConfigurableWebBindingInitializer.class); wbiDef.getPropertyValues().add("conversionService", csDef); RootBeanDefinition adapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class); adapterDef.getPropertyValues().add("webBindingInitializer", wbiDef); context.registerBeanDefinition("handlerAdapter", adapterDef); } }, PathVariableWithCustomConverterController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath/1"); MockHttpServletResponse response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals(404, response.getStatus()); } @Test public void methodNotAllowed() throws Exception { initServletWithControllers(MethodNotAllowedController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath.do"); MockHttpServletResponse response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("Invalid response status", HttpServletResponse.SC_METHOD_NOT_ALLOWED, response.getStatus()); String allowHeader = response.getHeader("Allow"); assertNotNull("No Allow header", allowHeader); Set<String> allowedMethods = new HashSet<>(); allowedMethods.addAll(Arrays.asList(StringUtils.delimitedListToStringArray(allowHeader, ", "))); assertEquals("Invalid amount of supported methods", 6, allowedMethods.size()); assertTrue("PUT not allowed", allowedMethods.contains("PUT")); assertTrue("DELETE not allowed", allowedMethods.contains("DELETE")); assertTrue("HEAD not allowed", allowedMethods.contains("HEAD")); assertTrue("TRACE not allowed", allowedMethods.contains("TRACE")); assertTrue("OPTIONS not allowed", allowedMethods.contains("OPTIONS")); assertTrue("POST not allowed", allowedMethods.contains("POST")); } @Test public void emptyParameterListHandleMethod() throws Exception { initServlet(new ApplicationContextInitializer<GenericWebApplicationContext>() { @Override 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; getServlet().service(request, response); assertTrue(EmptyParameterListHandlerMethodController.called); assertEquals("", response.getContentAsString()); } @SuppressWarnings("rawtypes") @Test public void sessionAttributeExposure() throws Exception { initServlet(new ApplicationContextInitializer<GenericWebApplicationContext>() { @Override public void initialize(GenericWebApplicationContext context) { context.registerBeanDefinition("viewResolver", new RootBeanDefinition(ModelExposingViewResolver.class)); } }, MySessionAttributesController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPage"); MockHttpServletResponse response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("page1", request.getAttribute("viewName")); HttpSession session = request.getSession(); assertTrue(session.getAttribute("object1") != null); assertTrue(session.getAttribute("object2") != null); assertTrue(((Map) session.getAttribute("model")).containsKey("object1")); assertTrue(((Map) session.getAttribute("model")).containsKey("object2")); request = new MockHttpServletRequest("POST", "/myPage"); request.setSession(session); response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("page2", request.getAttribute("viewName")); assertTrue(session.getAttribute("object1") != null); assertTrue(session.getAttribute("object2") != null); assertTrue(((Map) session.getAttribute("model")).containsKey("object1")); assertTrue(((Map) session.getAttribute("model")).containsKey("object2")); } @SuppressWarnings("rawtypes") @Test public void sessionAttributeExposureWithInterface() throws Exception { initServlet(new ApplicationContextInitializer<GenericWebApplicationContext>() { @Override 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(); getServlet().service(request, response); assertEquals("page1", request.getAttribute("viewName")); HttpSession session = request.getSession(); assertTrue(session.getAttribute("object1") != null); assertTrue(session.getAttribute("object2") != null); assertTrue(((Map) session.getAttribute("model")).containsKey("object1")); assertTrue(((Map) session.getAttribute("model")).containsKey("object2")); request = new MockHttpServletRequest("POST", "/myPage"); request.setSession(session); response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("page2", request.getAttribute("viewName")); assertTrue(session.getAttribute("object1") != null); assertTrue(session.getAttribute("object2") != null); assertTrue(((Map) session.getAttribute("model")).containsKey("object1")); assertTrue(((Map) session.getAttribute("model")).containsKey("object2")); } @SuppressWarnings("rawtypes") @Test public void parameterizedAnnotatedInterface() throws Exception { initServlet(new ApplicationContextInitializer<GenericWebApplicationContext>() { @Override public void initialize(GenericWebApplicationContext context) { context.registerBeanDefinition("viewResolver", new RootBeanDefinition(ModelExposingViewResolver.class)); } }, MyParameterizedControllerImpl.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPage"); MockHttpServletResponse response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("page1", request.getAttribute("viewName")); HttpSession session = request.getSession(); assertTrue(session.getAttribute("object1") != null); assertTrue(session.getAttribute("object2") != null); assertTrue(((Map) session.getAttribute("model")).containsKey("object1")); assertTrue(((Map) session.getAttribute("model")).containsKey("object2")); assertTrue(((Map) session.getAttribute("model")).containsKey("testBeanList")); request = new MockHttpServletRequest("POST", "/myPage"); request.setSession(session); response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("page2", request.getAttribute("viewName")); assertTrue(session.getAttribute("object1") != null); assertTrue(session.getAttribute("object2") != null); assertTrue(((Map) session.getAttribute("model")).containsKey("object1")); assertTrue(((Map) session.getAttribute("model")).containsKey("object2")); assertTrue(((Map) session.getAttribute("model")).containsKey("testBeanList")); } @SuppressWarnings("rawtypes") @Test public void parameterizedAnnotatedInterfaceWithOverriddenMappingsInImpl() throws Exception { initServlet(new ApplicationContextInitializer<GenericWebApplicationContext>() { @Override public void initialize(GenericWebApplicationContext context) { context.registerBeanDefinition("viewResolver", new RootBeanDefinition(ModelExposingViewResolver.class)); } }, MyParameterizedControllerImplWithOverriddenMappings.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPage"); MockHttpServletResponse response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("page1", request.getAttribute("viewName")); HttpSession session = request.getSession(); assertTrue(session.getAttribute("object1") != null); assertTrue(session.getAttribute("object2") != null); assertTrue(((Map) session.getAttribute("model")).containsKey("object1")); assertTrue(((Map) session.getAttribute("model")).containsKey("object2")); assertTrue(((Map) session.getAttribute("model")).containsKey("testBeanList")); request = new MockHttpServletRequest("POST", "/myPage"); request.setSession(session); response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("page2", request.getAttribute("viewName")); assertTrue(session.getAttribute("object1") != null); assertTrue(session.getAttribute("object2") != null); assertTrue(((Map) session.getAttribute("model")).containsKey("object1")); assertTrue(((Map) session.getAttribute("model")).containsKey("object2")); assertTrue(((Map) session.getAttribute("model")).containsKey("testBeanList")); } @Test public void adaptedHandleMethods() throws Exception { doTestAdaptedHandleMethods(MyAdaptedController.class); } @Test public void adaptedHandleMethods2() throws Exception { doTestAdaptedHandleMethods(MyAdaptedController2.class); } @Test public void adaptedHandleMethods3() throws Exception { doTestAdaptedHandleMethods(MyAdaptedController3.class); } private void doTestAdaptedHandleMethods(final Class<?> controllerClass) throws Exception { initServletWithControllers(controllerClass); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath1.do"); MockHttpServletResponse response = new MockHttpServletResponse(); request.addParameter("param1", "value1"); request.addParameter("param2", "2"); getServlet().service(request, response); assertEquals("test", response.getContentAsString()); request = new MockHttpServletRequest("GET", "/myPath2.do"); request.addParameter("param1", "value1"); request.addParameter("param2", "2"); request.addHeader("header1", "10"); request.setCookies(new Cookie("cookie1", "3")); response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("test-value1-2-10-3", response.getContentAsString()); request = new MockHttpServletRequest("GET", "/myPath3.do"); request.addParameter("param1", "value1"); request.addParameter("param2", "2"); request.addParameter("name", "name1"); request.addParameter("age", "2"); response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("test-name1-2", response.getContentAsString()); request = new MockHttpServletRequest("GET", "/myPath4.do"); request.addParameter("param1", "value1"); request.addParameter("param2", "2"); request.addParameter("name", "name1"); request.addParameter("age", "value2"); response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("test-name1-typeMismatch", response.getContentAsString()); } @Test public void formController() throws Exception { initServlet(new ApplicationContextInitializer<GenericWebApplicationContext>() { @Override 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(); getServlet().service(request, response); assertEquals("myView-name1-typeMismatch-tb1-myValue", response.getContentAsString()); } @Test public void modelFormController() throws Exception { initServlet(new ApplicationContextInitializer<GenericWebApplicationContext>() { @Override 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(); getServlet().service(request, response); assertEquals("myPath-name1-typeMismatch-tb1-myValue-yourValue", response.getContentAsString()); } @Test public void proxiedFormController() throws Exception { initServlet(new ApplicationContextInitializer<GenericWebApplicationContext>() { @Override public void initialize(GenericWebApplicationContext wac) { wac.registerBeanDefinition("viewResolver", new RootBeanDefinition(TestViewResolver.class)); DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator(); autoProxyCreator.setBeanFactory(wac.getBeanFactory()); wac.getBeanFactory().addBeanPostProcessor(autoProxyCreator); 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(); getServlet().service(request, response); assertEquals("myView-name1-typeMismatch-tb1-myValue", response.getContentAsString()); } @Test public void commandProvidingFormControllerWithCustomEditor() throws Exception { initServlet(new ApplicationContextInitializer<GenericWebApplicationContext>() { @Override 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(); getServlet().service(request, response); assertEquals("myView-String:myDefaultName-typeMismatch-tb1-myOriginalValue", response.getContentAsString()); } @Test public void typedCommandProvidingFormController() throws Exception { initServlet(new ApplicationContextInitializer<GenericWebApplicationContext>() { @Override public void initialize(GenericWebApplicationContext wac) { wac.registerBeanDefinition("viewResolver", new RootBeanDefinition(TestViewResolver.class)); RootBeanDefinition adapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class); adapterDef.getPropertyValues().add("webBindingInitializer", new MyWebBindingInitializer()); List<HandlerMethodArgumentResolver> argumentResolvers = new ArrayList<>(); argumentResolvers.add(new ServletWebArgumentResolverAdapter(new MySpecialArgumentResolver())); 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(); getServlet().service(request, response); assertEquals("myView-Integer:10-typeMismatch-tb1-myOriginalValue", response.getContentAsString()); request = new MockHttpServletRequest("GET", "/myOtherPath.do"); request.addParameter("defaultName", "10"); request.addParameter("age", "value2"); request.addParameter("date", "2007-10-02"); response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("myView-myName-typeMismatch-tb1-myOriginalValue", response.getContentAsString()); request = new MockHttpServletRequest("GET", "/myThirdPath.do"); request.addParameter("defaultName", "10"); request.addParameter("age", "100"); request.addParameter("date", "2007-10-02"); response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("myView-special-99-special-99", response.getContentAsString()); } @Test public void binderInitializingCommandProvidingFormController() throws Exception { initServlet(new ApplicationContextInitializer<GenericWebApplicationContext>() { @Override 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(); getServlet().service(request, response); assertEquals("myView-String:myDefaultName-typeMismatch-tb1-myOriginalValue", response.getContentAsString()); } @Test public void specificBinderInitializingCommandProvidingFormController() throws Exception { initServlet(new ApplicationContextInitializer<GenericWebApplicationContext>() { @Override 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(); getServlet().service(request, response); assertEquals("myView-String:myDefaultName-typeMismatch-tb1-myOriginalValue", response.getContentAsString()); } @Test public void parameterDispatchingController() throws Exception { final MockServletContext servletContext = new MockServletContext(); final MockServletConfig servletConfig = new MockServletConfig(servletContext); WebApplicationContext webAppContext = initServlet(new ApplicationContextInitializer<GenericWebApplicationContext>() { @Override 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(); getServlet().service(request, response); assertEquals("myView", response.getContentAsString()); assertSame(servletContext, request.getAttribute("servletContext")); assertSame(servletConfig, request.getAttribute("servletConfig")); assertSame(session.getId(), request.getAttribute("sessionId")); assertSame(request.getRequestURI(), request.getAttribute("requestUri")); assertSame(request.getLocale(), request.getAttribute("locale")); request = new MockHttpServletRequest(servletContext, "GET", "/myPath.do"); response = new MockHttpServletResponse(); session = request.getSession(); getServlet().service(request, response); assertEquals("myView", response.getContentAsString()); assertSame(servletContext, request.getAttribute("servletContext")); assertSame(servletConfig, request.getAttribute("servletConfig")); assertSame(session.getId(), request.getAttribute("sessionId")); assertSame(request.getRequestURI(), request.getAttribute("requestUri")); request = new MockHttpServletRequest(servletContext, "GET", "/myPath.do"); request.addParameter("view", "other"); response = new MockHttpServletResponse(); 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(); getServlet().service(request, response); assertEquals("myLangView", response.getContentAsString()); request = new MockHttpServletRequest(servletContext, "GET", "/myPath.do"); request.addParameter("surprise", "!"); response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("mySurpriseView", response.getContentAsString()); MyParameterDispatchingController deserialized = (MyParameterDispatchingController) SerializationTestUtils.serializeAndDeserialize( webAppContext.getBean(MyParameterDispatchingController.class.getSimpleName())); assertNotNull(deserialized.request); assertNotNull(deserialized.session); } @Test public void relativePathDispatchingController() throws Exception { initServletWithControllers(MyRelativePathDispatchingController.class); getServlet().init(new MockServletConfig()); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myApp/myHandle"); MockHttpServletResponse response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("myView", response.getContentAsString()); request = new MockHttpServletRequest("GET", "/myApp/myOther"); response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("myOtherView", response.getContentAsString()); request = new MockHttpServletRequest("GET", "/myApp/myLang"); response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("myLangView", response.getContentAsString()); request = new MockHttpServletRequest("GET", "/myApp/surprise.do"); response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("mySurpriseView", response.getContentAsString()); } @Test public void relativeMethodPathDispatchingController() throws Exception { initServletWithControllers(MyRelativeMethodPathDispatchingController.class); getServlet().init(new MockServletConfig()); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myApp/myHandle"); MockHttpServletResponse response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("myView", response.getContentAsString()); request = new MockHttpServletRequest("GET", "/yourApp/myOther"); response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("myOtherView", response.getContentAsString()); request = new MockHttpServletRequest("GET", "/hisApp/myLang"); response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("myLangView", response.getContentAsString()); request = new MockHttpServletRequest("GET", "/herApp/surprise.do"); response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("mySurpriseView", response.getContentAsString()); } @Test public void nullCommandController() throws Exception { initServletWithControllers(MyNullCommandController.class); getServlet().init(new MockServletConfig()); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath"); request.setUserPrincipal(new OtherPrincipal()); MockHttpServletResponse response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("myView", response.getContentAsString()); } @Test public void equivalentMappingsWithSameMethodName() throws Exception { try { initServletWithControllers(ChildController.class); fail("Expected 'method already mapped' error"); } catch (BeanCreationException e) { assertTrue(e.getCause() instanceof IllegalStateException); assertTrue(e.getCause().getMessage().contains("Ambiguous mapping")); } } @Test public void pathOrdering() throws ServletException, IOException { initServletWithControllers(PathOrderingController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/dir/myPath1.do"); MockHttpServletResponse response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("method1", response.getContentAsString()); } @Test public void requestBodyResponseBody() throws ServletException, IOException { 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"); request.addHeader("Accept", "text/*, */*"); MockHttpServletResponse response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals(200, response.getStatus()); assertEquals(requestBody, response.getContentAsString()); } @Test public void httpPatch() throws ServletException, IOException { initServletWithControllers(RequestResponseBodyController.class); MockHttpServletRequest request = new MockHttpServletRequest("PATCH", "/something"); String requestBody = "Hello world!"; request.setContent(requestBody.getBytes("UTF-8")); request.addHeader("Content-Type", "text/plain; charset=utf-8"); request.addHeader("Accept", "text/*, */*"); MockHttpServletResponse response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals(200, response.getStatus()); assertEquals(requestBody, response.getContentAsString()); } @Test public void responseBodyNoAcceptableMediaType() throws ServletException, IOException { initServlet(new ApplicationContextInitializer<GenericWebApplicationContext>() { @Override 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"; request.setContent(requestBody.getBytes("UTF-8")); request.addHeader("Content-Type", "text/plain; charset=utf-8"); request.addHeader("Accept", "application/pdf, application/msword"); MockHttpServletResponse response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals(406, response.getStatus()); } @Test public void responseBodyWildCardMediaType() throws ServletException, IOException { 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"); request.addHeader("Accept", "*/*"); MockHttpServletResponse response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals(requestBody, response.getContentAsString()); } @Test public void unsupportedRequestBody() throws ServletException, IOException { initServlet(new ApplicationContextInitializer<GenericWebApplicationContext>() { @Override 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(); getServlet().service(request, response); assertEquals(415, response.getStatus()); assertNotNull("No Accept response header set", response.getHeader("Accept")); } @Test public void responseBodyNoAcceptHeader() throws ServletException, IOException { 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(); getServlet().service(request, response); assertEquals(200, response.getStatus()); assertEquals(requestBody, response.getContentAsString()); } @Test public void badRequestRequestBody() throws ServletException, IOException { initServlet(new ApplicationContextInitializer<GenericWebApplicationContext>() { @Override 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(); getServlet().service(request, response); assertEquals("Invalid response status code", HttpServletResponse.SC_BAD_REQUEST, response.getStatus()); } @Test public void httpEntity() throws ServletException, IOException { initServletWithControllers(ResponseEntityController.class); MockHttpServletRequest request = new MockHttpServletRequest("POST", "/foo"); String requestBody = "Hello World"; request.setContent(requestBody.getBytes("UTF-8")); request.addHeader("Content-Type", "text/plain; charset=utf-8"); request.addHeader("Accept", "text/*, */*"); request.addHeader("MyRequestHeader", "MyValue"); MockHttpServletResponse response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals(201, response.getStatus()); assertEquals(requestBody, response.getContentAsString()); assertEquals("MyValue", response.getHeader("MyResponseHeader")); request = new MockHttpServletRequest("GET", "/bar"); response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("MyValue", response.getHeader("MyResponseHeader")); assertEquals(404, response.getStatus()); } /* * See SPR-6877 */ @Test public void overlappingMessageConvertersRequestBody() throws ServletException, IOException { initServlet(new ApplicationContextInitializer<GenericWebApplicationContext>() { @Override public void initialize(GenericWebApplicationContext wac) { RootBeanDefinition adapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class); List<HttpMessageConverter<?>> messageConverters = new ArrayList<>(); messageConverters.add(new StringHttpMessageConverter()); messageConverters .add(new SimpleMessageConverter(new MediaType("application","json"), MediaType.ALL)); 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(); getServlet().service(request, response); assertEquals("Invalid content-type", "application/json;charset=ISO-8859-1", response.getHeader("Content-Type")); } @Test public void responseBodyVoid() throws ServletException, IOException { initServletWithControllers(ResponseBodyVoidController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/something"); request.addHeader("Accept", "text/*, */*"); MockHttpServletResponse response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals(200, response.getStatus()); } @Test public void responseBodyArgMismatch() throws ServletException, IOException { initServlet(new ApplicationContextInitializer<GenericWebApplicationContext>() { @Override public void initialize(GenericWebApplicationContext wac) { Jaxb2Marshaller marshaller = new Jaxb2Marshaller(); marshaller.setClassesToBeBound(A.class, B.class); try { marshaller.afterPropertiesSet(); } catch (Exception ex) { throw new BeanCreationException(ex.getMessage(), ex); } MarshallingHttpMessageConverter messageConverter = new MarshallingHttpMessageConverter(marshaller); RootBeanDefinition adapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class); adapterDef.getPropertyValues().add("messageConverters", messageConverter); wac.registerBeanDefinition("handlerAdapter", adapterDef); } }, RequestBodyArgMismatchController.class); MockHttpServletRequest request = new MockHttpServletRequest("PUT", "/something"); String requestBody = "<b/>"; request.setContent(requestBody.getBytes("UTF-8")); request.addHeader("Content-Type", "application/xml; charset=utf-8"); MockHttpServletResponse response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals(400, response.getStatus()); } @Test public void contentTypeHeaders() throws ServletException, IOException { initServletWithControllers(ContentTypeHeadersController.class); MockHttpServletRequest request = new MockHttpServletRequest("POST", "/something"); request.setContentType("application/pdf"); MockHttpServletResponse response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("pdf", response.getContentAsString()); request = new MockHttpServletRequest("POST", "/something"); request.setContentType("text/html"); response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("text", response.getContentAsString()); request = new MockHttpServletRequest("POST", "/something"); request.setContentType("application/xml"); response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals(415, response.getStatus()); } @Test public void consumes() throws ServletException, IOException { initServletWithControllers(ConsumesController.class); MockHttpServletRequest request = new MockHttpServletRequest("POST", "/something"); request.setContentType("application/pdf"); MockHttpServletResponse response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("pdf", response.getContentAsString()); request = new MockHttpServletRequest("POST", "/something"); request.setContentType("text/html"); response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("text", response.getContentAsString()); request = new MockHttpServletRequest("POST", "/something"); request.setContentType("application/xml"); response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals(415, response.getStatus()); } @Test public void negatedContentTypeHeaders() throws ServletException, IOException { initServletWithControllers(NegatedContentTypeHeadersController.class); MockHttpServletRequest request = new MockHttpServletRequest("POST", "/something"); request.setContentType("application/pdf"); MockHttpServletResponse response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("pdf", response.getContentAsString()); request = new MockHttpServletRequest("POST", "/something"); request.setContentType("text/html"); response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("non-pdf", response.getContentAsString()); } @Test public void acceptHeaders() throws ServletException, IOException { initServletWithControllers(AcceptHeadersController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/something"); request.addHeader("Accept", "text/html"); MockHttpServletResponse response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("html", response.getContentAsString()); request = new MockHttpServletRequest("GET", "/something"); request.addHeader("Accept", "application/xml"); response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("xml", response.getContentAsString()); request = new MockHttpServletRequest("GET", "/something"); request.addHeader("Accept", "application/xml, text/html"); response = new MockHttpServletResponse(); 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(); getServlet().service(request, response); assertEquals("xml", response.getContentAsString()); request = new MockHttpServletRequest("GET", "/something"); request.addHeader("Accept", "application/msword"); response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals(406, response.getStatus()); } @Test public void produces() throws ServletException, IOException { initServletWithControllers(ProducesController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/something"); request.addHeader("Accept", "text/html"); MockHttpServletResponse response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("html", response.getContentAsString()); request = new MockHttpServletRequest("GET", "/something"); request.addHeader("Accept", "application/xml"); response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("xml", response.getContentAsString()); request = new MockHttpServletRequest("GET", "/something"); request.addHeader("Accept", "application/xml, text/html"); response = new MockHttpServletResponse(); 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(); getServlet().service(request, response); assertEquals("xml", response.getContentAsString()); request = new MockHttpServletRequest("GET", "/something"); request.addHeader("Accept", "application/msword"); response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals(406, response.getStatus()); } @Test public void responseStatus() throws ServletException, IOException { initServletWithControllers(ResponseStatusController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/something"); MockHttpServletResponse response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("something", response.getContentAsString()); assertEquals(201, response.getStatus()); assertEquals("It's alive!", response.getErrorMessage()); } @Test public void mavResolver() throws ServletException, IOException { initServlet(new ApplicationContextInitializer<GenericWebApplicationContext>() { @Override 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(); getServlet().service(request, response); assertEquals("myValue", response.getContentAsString()); } @Test public void bindingCookieValue() throws ServletException, IOException { initServletWithControllers(BindingCookieValueController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/test"); request.setCookies(new Cookie("date", "2008-11-18")); MockHttpServletResponse response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("test-2008", response.getContentAsString()); } @Test public void ambiguousParams() throws ServletException, IOException { initServletWithControllers(AmbiguousParamsController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/test"); MockHttpServletResponse response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("noParams", response.getContentAsString()); request = new MockHttpServletRequest("GET", "/test"); request.addParameter("myParam", "42"); response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("myParam-42", response.getContentAsString()); } @Test // SPR-9062 public void ambiguousPathAndRequestMethod() throws Exception { initServletWithControllers(AmbiguousPathAndRequestMethodController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/bug/EXISTING"); MockHttpServletResponse response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals(200, response.getStatus()); assertEquals("Pattern", response.getContentAsString()); } @Test public void bridgeMethods() throws Exception { initServletWithControllers(TestControllerImpl.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/method"); MockHttpServletResponse response = new MockHttpServletResponse(); getServlet().service(request, response); } @Test public void requestParamMap() throws Exception { initServletWithControllers(RequestParamMapController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/map"); request.addParameter("key1", "value1"); request.addParameter("key2", new String[]{"value21", "value22"}); MockHttpServletResponse response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("key1=value1,key2=value21", response.getContentAsString()); request.setRequestURI("/multiValueMap"); response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("key1=[value1],key2=[value21,value22]", response.getContentAsString()); } @Test public void requestHeaderMap() throws Exception { 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(); getServlet().service(request, response); assertEquals("Content-Type=text/html,Custom-Header=value21", response.getContentAsString()); request.setRequestURI("/multiValueMap"); response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("Content-Type=[text/html],Custom-Header=[value21,value22]", response.getContentAsString()); request.setRequestURI("/httpHeaders"); response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("Content-Type=[text/html],Custom-Header=[value21,value22]", response.getContentAsString()); } @Test public void requestMappingInterface() throws Exception { initServletWithControllers(IMyControllerImpl.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/handle"); MockHttpServletResponse response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("handle null", response.getContentAsString()); request = new MockHttpServletRequest("GET", "/handle"); request.addParameter("p", "value"); response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("handle value", response.getContentAsString()); } @Test public void requestMappingInterfaceWithProxy() throws Exception { initServlet(new ApplicationContextInitializer<GenericWebApplicationContext>() { @Override 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(); getServlet().service(request, response); assertEquals("handle null", response.getContentAsString()); request = new MockHttpServletRequest("GET", "/handle"); request.addParameter("p", "value"); response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("handle value", response.getContentAsString()); } @Test public void requestMappingBaseClass() throws Exception { initServletWithControllers(MyAbstractControllerImpl.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/handle"); MockHttpServletResponse response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("handle", response.getContentAsString()); } @Test public void trailingSlash() throws Exception { initServletWithControllers(TrailingSlashController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo/"); MockHttpServletResponse response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("templatePath", response.getContentAsString()); } /* * See SPR-6021 */ @Test public void customMapEditor() throws Exception { initServletWithControllers(CustomMapEditorController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/handle"); request.addParameter("map", "bar"); MockHttpServletResponse response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("test-{foo=bar}", response.getContentAsString()); } @Test public void multipartFileAsSingleString() throws Exception { initServletWithControllers(MultipartController.class); MockMultipartHttpServletRequest request = new MockMultipartHttpServletRequest(); request.setRequestURI("/singleString"); request.addFile(new MockMultipartFile("content", "Juergen".getBytes())); MockHttpServletResponse response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("Juergen", response.getContentAsString()); } @Test public void regularParameterAsSingleString() throws Exception { initServletWithControllers(MultipartController.class); MockHttpServletRequest request = new MockHttpServletRequest(); request.setRequestURI("/singleString"); request.setMethod("POST"); request.addParameter("content", "Juergen"); MockHttpServletResponse response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("Juergen", response.getContentAsString()); } @Test public void multipartFileAsStringArray() throws Exception { initServletWithControllers(MultipartController.class); MockMultipartHttpServletRequest request = new MockMultipartHttpServletRequest(); request.setRequestURI("/stringArray"); request.addFile(new MockMultipartFile("content", "Juergen".getBytes())); MockHttpServletResponse response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("Juergen", response.getContentAsString()); } @Test public void regularParameterAsStringArray() throws Exception { initServletWithControllers(MultipartController.class); MockHttpServletRequest request = new MockHttpServletRequest(); request.setRequestURI("/stringArray"); request.setMethod("POST"); request.addParameter("content", "Juergen"); MockHttpServletResponse response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("Juergen", response.getContentAsString()); } @Test public void multipartFilesAsStringArray() throws Exception { 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(); getServlet().service(request, response); assertEquals("Juergen-Eva", response.getContentAsString()); } @Test public void regularParametersAsStringArray() throws Exception { initServletWithControllers(MultipartController.class); MockHttpServletRequest request = new MockHttpServletRequest(); request.setRequestURI("/stringArray"); request.setMethod("POST"); request.addParameter("content", "Juergen"); request.addParameter("content", "Eva"); MockHttpServletResponse response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("Juergen-Eva", response.getContentAsString()); } @Test public void parameterCsvAsStringArray() throws Exception { initServlet(new ApplicationContextInitializer<GenericWebApplicationContext>() { @Override public void initialize(GenericWebApplicationContext wac) { RootBeanDefinition csDef = new RootBeanDefinition(FormattingConversionServiceFactoryBean.class); RootBeanDefinition wbiDef = new RootBeanDefinition(ConfigurableWebBindingInitializer.class); wbiDef.getPropertyValues().add("conversionService", csDef); RootBeanDefinition adapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class); 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(); getServlet().service(request, response); assertEquals("1-2", response.getContentAsString()); } @Test public void testMatchWithoutMethodLevelPath() throws Exception { initServletWithControllers(NoPathGetAndM2PostController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/t1/m2"); MockHttpServletResponse response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals(405, response.getStatus()); } @Test // SPR-8536 public void testHeadersCondition() throws Exception { initServletWithControllers(HeadersConditionController.class); // No "Accept" header MockHttpServletRequest request = new MockHttpServletRequest("GET", "/"); MockHttpServletResponse response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals(200, response.getStatus()); assertEquals("home", response.getForwardedUrl()); // Accept "*/*" request = new MockHttpServletRequest("GET", "/"); request.addHeader("Accept", "*/*"); response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals(200, response.getStatus()); assertEquals("home", response.getForwardedUrl()); // Accept "application/json" request = new MockHttpServletRequest("GET", "/"); request.addHeader("Accept", "application/json"); response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals(200, response.getStatus()); assertEquals("application/json;charset=ISO-8859-1", response.getHeader("Content-Type")); assertEquals("homeJson", response.getContentAsString()); } @Test public void redirectAttribute() throws Exception { initServletWithControllers(RedirectAttributesController.class); MockHttpServletRequest request = new MockHttpServletRequest("POST", "/messages"); HttpSession session = request.getSession(); MockHttpServletResponse response = new MockHttpServletResponse(); getServlet().service(request, response); // POST -> bind error getServlet().service(request, response); assertEquals(200, response.getStatus()); assertEquals("messages/new", response.getForwardedUrl()); assertTrue(RequestContextUtils.getOutputFlashMap(request).isEmpty()); // POST -> success request = new MockHttpServletRequest("POST", "/messages"); request.setSession(session); request.addParameter("name", "Jeff"); response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals(302, response.getStatus()); assertEquals("/messages/1?name=value", response.getRedirectedUrl()); assertEquals("yay!", RequestContextUtils.getOutputFlashMap(request).get("successMessage")); // GET after POST request = new MockHttpServletRequest("GET", "/messages/1"); request.setQueryString("name=value"); request.setSession(session); response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals(200, response.getStatus()); assertEquals("Got: yay!", response.getContentAsString()); assertTrue(RequestContextUtils.getOutputFlashMap(request).isEmpty()); } @Test // SPR-15176 public void flashAttributesWithResponseEntity() throws Exception { initServletWithControllers(RedirectAttributesController.class); MockHttpServletRequest request = new MockHttpServletRequest("POST", "/messages-response-entity"); MockHttpServletResponse response = new MockHttpServletResponse(); HttpSession session = request.getSession(); getServlet().service(request, response); assertEquals(302, response.getStatus()); assertEquals("/messages/1?name=value", response.getRedirectedUrl()); assertEquals("yay!", RequestContextUtils.getOutputFlashMap(request).get("successMessage")); // GET after POST request = new MockHttpServletRequest("GET", "/messages/1"); request.setQueryString("name=value"); request.setSession(session); response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals(200, response.getStatus()); assertEquals("Got: yay!", response.getContentAsString()); assertTrue(RequestContextUtils.getOutputFlashMap(request).isEmpty()); } @Test public void prototypeController() throws Exception { initServlet(new ApplicationContextInitializer<GenericWebApplicationContext>() { @Override public void initialize(GenericWebApplicationContext context) { RootBeanDefinition beanDef = new RootBeanDefinition(PrototypeController.class); beanDef.setScope(BeanDefinition.SCOPE_PROTOTYPE); context.registerBeanDefinition("controller", beanDef); } }); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/"); request.addParameter("param", "1"); MockHttpServletResponse response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("count:3", response.getContentAsString()); response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("count:3", response.getContentAsString()); } @Test public void restController() throws Exception { initServletWithControllers(ThisWillActuallyRun.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/"); MockHttpServletResponse response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("Hello World!", response.getContentAsString()); } @Test public void responseAsHttpHeaders() throws Exception { initServletWithControllers(HttpHeadersResponseController.class); MockHttpServletResponse response = new MockHttpServletResponse(); getServlet().service(new MockHttpServletRequest("POST", "/"), response); assertEquals("Wrong status code", MockHttpServletResponse.SC_CREATED, response.getStatus()); assertEquals("Wrong number of headers", 1, response.getHeaderNames().size()); assertEquals("Wrong value for 'location' header", "/test/items/123", response.getHeader("location")); assertEquals("Expected an empty content", 0, response.getContentLength()); } @Test public void responseAsHttpHeadersNoHeader() throws Exception { initServletWithControllers(HttpHeadersResponseController.class); MockHttpServletResponse response = new MockHttpServletResponse(); getServlet().service(new MockHttpServletRequest("POST", "/empty"), response); assertEquals("Wrong status code", MockHttpServletResponse.SC_CREATED, response.getStatus()); assertEquals("Wrong number of headers", 0, response.getHeaderNames().size()); assertEquals("Expected an empty content", 0, response.getContentLength()); } @Test public void responseBodyAsHtml() throws Exception { initServlet(new ApplicationContextInitializer<GenericWebApplicationContext>() { @Override public void initialize(GenericWebApplicationContext wac) { ContentNegotiationManagerFactoryBean factoryBean = new ContentNegotiationManagerFactoryBean(); factoryBean.afterPropertiesSet(); RootBeanDefinition adapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class); adapterDef.getPropertyValues().add("contentNegotiationManager", factoryBean.getObject()); wac.registerBeanDefinition("handlerAdapter", adapterDef); } }, TextRestController.class); byte[] content = "alert('boo')".getBytes(StandardCharsets.ISO_8859_1); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/a1.html"); request.setContent(content); MockHttpServletResponse response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals(200, response.getStatus()); assertEquals("text/html;charset=ISO-8859-1", response.getContentType()); assertEquals("inline;filename=f.txt", response.getHeader("Content-Disposition")); assertArrayEquals(content, response.getContentAsByteArray()); } @Test public void responseBodyAsHtmlWithSuffixPresent() throws Exception { initServlet(new ApplicationContextInitializer<GenericWebApplicationContext>() { @Override public void initialize(GenericWebApplicationContext wac) { ContentNegotiationManagerFactoryBean factoryBean = new ContentNegotiationManagerFactoryBean(); factoryBean.afterPropertiesSet(); RootBeanDefinition adapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class); adapterDef.getPropertyValues().add("contentNegotiationManager", factoryBean.getObject()); wac.registerBeanDefinition("handlerAdapter", adapterDef); } }, TextRestController.class); byte[] content = "alert('boo')".getBytes(StandardCharsets.ISO_8859_1); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/a2.html"); request.setContent(content); MockHttpServletResponse response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals(200, response.getStatus()); assertEquals("text/html;charset=ISO-8859-1", response.getContentType()); assertNull(response.getHeader("Content-Disposition")); assertArrayEquals(content, response.getContentAsByteArray()); } @Test public void responseBodyAsHtmlWithProducesCondition() throws Exception { initServlet(new ApplicationContextInitializer<GenericWebApplicationContext>() { @Override public void initialize(GenericWebApplicationContext wac) { ContentNegotiationManagerFactoryBean factoryBean = new ContentNegotiationManagerFactoryBean(); factoryBean.afterPropertiesSet(); RootBeanDefinition adapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class); adapterDef.getPropertyValues().add("contentNegotiationManager", factoryBean.getObject()); wac.registerBeanDefinition("handlerAdapter", adapterDef); } }, TextRestController.class); byte[] content = "alert('boo')".getBytes(StandardCharsets.ISO_8859_1); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/a3.html"); request.setContent(content); MockHttpServletResponse response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals(200, response.getStatus()); assertEquals("text/html;charset=ISO-8859-1", response.getContentType()); assertNull(response.getHeader("Content-Disposition")); assertArrayEquals(content, response.getContentAsByteArray()); } @Test public void responseBodyAsTextWithCssExtension() throws Exception { initServlet(new ApplicationContextInitializer<GenericWebApplicationContext>() { @Override public void initialize(GenericWebApplicationContext wac) { ContentNegotiationManagerFactoryBean factoryBean = new ContentNegotiationManagerFactoryBean(); factoryBean.afterPropertiesSet(); RootBeanDefinition adapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class); adapterDef.getPropertyValues().add("contentNegotiationManager", factoryBean.getObject()); wac.registerBeanDefinition("handlerAdapter", adapterDef); } }, TextRestController.class); byte[] content = "body".getBytes(StandardCharsets.ISO_8859_1); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/a4.css"); request.setContent(content); MockHttpServletResponse response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals(200, response.getStatus()); assertEquals("text/css;charset=ISO-8859-1", response.getContentType()); assertNull(response.getHeader("Content-Disposition")); assertArrayEquals(content, response.getContentAsByteArray()); } @Test public void modelAndViewWithStatus() throws Exception { initServletWithControllers(ModelAndViewController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/path"); MockHttpServletResponse response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals(422, response.getStatus()); assertEquals("view", response.getForwardedUrl()); } @Test // SPR-14796 public void modelAndViewWithStatusInExceptionHandler() throws Exception { initServletWithControllers(ModelAndViewController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/exception"); MockHttpServletResponse response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals(422, response.getStatus()); assertEquals("view", response.getForwardedUrl()); } @Test public void httpHead() throws ServletException, IOException { initServletWithControllers(ResponseEntityController.class); MockHttpServletRequest request = new MockHttpServletRequest("HEAD", "/baz"); MockHttpServletResponse response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals(200, response.getStatus()); assertEquals("MyValue", response.getHeader("MyResponseHeader")); assertEquals(4, response.getContentLength()); assertTrue(response.getContentAsByteArray().length == 0); // Now repeat with GET request = new MockHttpServletRequest("GET", "/baz"); response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals(200, response.getStatus()); assertEquals("MyValue", response.getHeader("MyResponseHeader")); assertEquals(4, response.getContentLength()); assertEquals("body", response.getContentAsString()); } @Test public void httpHeadExplicit() throws ServletException, IOException { initServletWithControllers(ResponseEntityController.class); MockHttpServletRequest request = new MockHttpServletRequest("HEAD", "/stores"); MockHttpServletResponse response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals(200, response.getStatus()); assertEquals("v1", response.getHeader("h1")); } @Test public void httpOptions() throws ServletException, IOException { initServletWithControllers(ResponseEntityController.class); MockHttpServletRequest request = new MockHttpServletRequest("OPTIONS", "/baz"); MockHttpServletResponse response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals(200, response.getStatus()); assertEquals("GET,HEAD", response.getHeader("Allow")); assertTrue(response.getContentAsByteArray().length == 0); } @Test public void dataClassBinding() throws ServletException, IOException { initServletWithControllers(DataClassController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/bind"); request.addParameter("param1", "value1"); request.addParameter("param2", "2"); MockHttpServletResponse response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("value1-2-0", response.getContentAsString()); } @Test public void dataClassBindingWithAdditionalSetter() throws ServletException, IOException { initServletWithControllers(DataClassController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/bind"); request.addParameter("param1", "value1"); request.addParameter("param2", "2"); request.addParameter("param3", "3"); MockHttpServletResponse response = new MockHttpServletResponse(); getServlet().service(request, response); assertEquals("value1-2-3", response.getContentAsString()); } @Controller static class ControllerWithEmptyValueMapping { @RequestMapping("") public void myPath2(HttpServletResponse response) throws IOException { throw new IllegalStateException("test"); } @RequestMapping("/bar") public void myPath3(HttpServletResponse response) throws IOException { response.getWriter().write("testX"); } @ExceptionHandler public void myPath2(Exception ex, HttpServletResponse response) throws IOException { response.getWriter().write(ex.getMessage()); } } @Controller private static class ControllerWithErrorThrown { @RequestMapping("") public void myPath2(HttpServletResponse response) throws IOException { throw new AssertionError("test"); } @RequestMapping("/bar") public void myPath3(HttpServletResponse response) throws IOException { response.getWriter().write("testX"); } @ExceptionHandler public void myPath2(Error err, HttpServletResponse response) throws IOException { response.getWriter().write(err.getMessage()); } } @Controller static class MyAdaptedController { @RequestMapping("/myPath1.do") public void myHandle(HttpServletRequest request, HttpServletResponse response) throws IOException { response.getWriter().write("test"); } @RequestMapping("/myPath2.do") public void myHandle(@RequestParam("param1") String p1, @RequestParam("param2") int p2, @RequestHeader("header1") long h1, @CookieValue(name = "cookie1") Cookie c1, HttpServletResponse response) throws IOException { response.getWriter().write("test-" + p1 + "-" + p2 + "-" + h1 + "-" + c1.getValue()); } @RequestMapping("/myPath3") public void myHandle(TestBean tb, HttpServletResponse response) throws IOException { response.getWriter().write("test-" + tb.getName() + "-" + tb.getAge()); } @RequestMapping("/myPath4.do") public void myHandle(TestBean tb, Errors errors, HttpServletResponse response) throws IOException { response.getWriter().write("test-" + tb.getName() + "-" + errors.getFieldError("age").getCode()); } } @Controller @RequestMapping("/*.do") static class MyAdaptedController2 { @RequestMapping public void myHandle(HttpServletRequest request, HttpServletResponse response) throws IOException { response.getWriter().write("test"); } @RequestMapping("/myPath2.do") public void myHandle(@RequestParam("param1") String p1, int param2, HttpServletResponse response, @RequestHeader("header1") String h1, @CookieValue("cookie1") String c1) throws IOException { response.getWriter().write("test-" + p1 + "-" + param2 + "-" + h1 + "-" + c1); } @RequestMapping("/myPath3") public void myHandle(TestBean tb, HttpServletResponse response) throws IOException { response.getWriter().write("test-" + tb.getName() + "-" + tb.getAge()); } @RequestMapping("/myPath4.*") public void myHandle(TestBean tb, Errors errors, HttpServletResponse response) throws IOException { response.getWriter().write("test-" + tb.getName() + "-" + errors.getFieldError("age").getCode()); } } @Controller static class MyAdaptedControllerBase<T> { @RequestMapping("/myPath2.do") public void myHandle(@RequestParam("param1") T p1, int param2, @RequestHeader Integer header1, @CookieValue int cookie1, HttpServletResponse response) throws IOException { response.getWriter().write("test-" + p1 + "-" + param2 + "-" + header1 + "-" + cookie1); } @InitBinder public void initBinder(@RequestParam("param1") String p1, @RequestParam(value="paramX", required=false) String px, int param2) { assertNull(px); } @ModelAttribute public void modelAttribute(@RequestParam("param1") String p1, @RequestParam(value="paramX", required=false) String px, int param2) { assertNull(px); } } @RequestMapping("/*.do") static class MyAdaptedController3 extends MyAdaptedControllerBase<String> { @RequestMapping public void myHandle(HttpServletRequest request, HttpServletResponse response) throws IOException { response.getWriter().write("test"); } @Override public void myHandle(@RequestParam("param1") String p1, int param2, @RequestHeader Integer header1, @CookieValue int cookie1, HttpServletResponse response) throws IOException { response.getWriter().write("test-" + p1 + "-" + param2 + "-" + header1 + "-" + cookie1); } @RequestMapping("/myPath3") public void myHandle(TestBean tb, HttpServletResponse response) throws IOException { response.getWriter().write("test-" + tb.getName() + "-" + tb.getAge()); } @RequestMapping("/myPath4.*") public void myHandle(TestBean tb, Errors errors, HttpServletResponse response) throws IOException { response.getWriter().write("test-" + tb.getName() + "-" + errors.getFieldError("age").getCode()); } @Override @InitBinder public void initBinder(@RequestParam("param1") String p1, @RequestParam(value="paramX", required=false) String px, int param2) { assertNull(px); } @Override @ModelAttribute public void modelAttribute(@RequestParam("param1") String p1, @RequestParam(value="paramX", required=false) String px, int param2) { assertNull(px); } } @Controller @RequestMapping(method = RequestMethod.GET) static class EmptyParameterListHandlerMethodController { static boolean called; @RequestMapping("/emptyParameterListHandler") public void emptyParameterListHandler() { EmptyParameterListHandlerMethodController.called = true; } @RequestMapping("/nonEmptyParameterListHandler") public void nonEmptyParameterListHandler(HttpServletResponse response) { } } @Controller @RequestMapping("/myPage") @SessionAttributes(names = { "object1", "object2" }) public static class MySessionAttributesController { @RequestMapping(method = RequestMethod.GET) public String get(Model model) { model.addAttribute("object1", new Object()); model.addAttribute("object2", new Object()); return "page1"; } @RequestMapping(method = RequestMethod.POST) public String post(@ModelAttribute("object1") Object object1) { //do something with object1 return "page2"; } } @RequestMapping("/myPage") @SessionAttributes({"object1", "object2"}) @Controller public interface MySessionAttributesControllerIfc { @RequestMapping(method = RequestMethod.GET) String get(Model model); @RequestMapping(method = RequestMethod.POST) String post(@ModelAttribute("object1") Object object1); } public static class MySessionAttributesControllerImpl implements MySessionAttributesControllerIfc { @Override public String get(Model model) { model.addAttribute("object1", new Object()); model.addAttribute("object2", new Object()); return "page1"; } @Override public String post(@ModelAttribute("object1") Object object1) { //do something with object1 return "page2"; } } @RequestMapping("/myPage") @SessionAttributes({"object1", "object2"}) public interface MyParameterizedControllerIfc<T> { @ModelAttribute("testBeanList") List<TestBean> getTestBeans(); @RequestMapping(method = RequestMethod.GET) String get(Model model); } public interface MyEditableParameterizedControllerIfc<T> extends MyParameterizedControllerIfc<T> { @RequestMapping(method = RequestMethod.POST) String post(@ModelAttribute("object1") T object); } @Controller public static class MyParameterizedControllerImpl implements MyEditableParameterizedControllerIfc<TestBean> { @Override public List<TestBean> getTestBeans() { List<TestBean> list = new LinkedList<>(); list.add(new TestBean("tb1")); list.add(new TestBean("tb2")); return list; } @Override public String get(Model model) { model.addAttribute("object1", new TestBean()); model.addAttribute("object2", new TestBean()); return "page1"; } @Override public String post(TestBean object) { //do something with object1 return "page2"; } } @Controller public static class MyParameterizedControllerImplWithOverriddenMappings implements MyEditableParameterizedControllerIfc<TestBean> { @Override @ModelAttribute("testBeanList") public List<TestBean> getTestBeans() { List<TestBean> list = new LinkedList<>(); list.add(new TestBean("tb1")); list.add(new TestBean("tb2")); return list; } @Override @RequestMapping(method = RequestMethod.GET) public String get(Model model) { model.addAttribute("object1", new TestBean()); model.addAttribute("object2", new TestBean()); return "page1"; } @Override @RequestMapping(method = RequestMethod.POST) public String post(@ModelAttribute("object1") TestBean object1) { //do something with object1 return "page2"; } } @Controller public static class MyFormController { @ModelAttribute("testBeanList") public List<TestBean> getTestBeans() { List<TestBean> list = new LinkedList<>(); list.add(new TestBean("tb1")); list.add(new TestBean("tb2")); return list; } @RequestMapping("/myPath.do") public String myHandle(@ModelAttribute("myCommand") TestBean tb, BindingResult errors, ModelMap model) { FieldError error = errors.getFieldError("age"); assertNotNull("Must have field error for age property", error); assertEquals("value2", error.getRejectedValue()); if (!model.containsKey("myKey")) { model.addAttribute("myKey", "myValue"); } return "myView"; } } public static class ValidTestBean extends TestBean { @NotNull private String validCountry; public void setValidCountry(String validCountry) { this.validCountry = validCountry; } public String getValidCountry() { return this.validCountry; } } @Controller public static class MyModelFormController { @ModelAttribute public List<TestBean> getTestBeans() { List<TestBean> list = new LinkedList<>(); list.add(new TestBean("tb1")); list.add(new TestBean("tb2")); return list; } @RequestMapping("/myPath.do") @ModelAttribute("yourKey") public String myHandle(@ModelAttribute("myCommand") TestBean tb, BindingResult errors, Model model) { if (!model.containsAttribute("myKey")) { model.addAttribute("myKey", "myValue"); } return "yourValue"; } } @Controller static class MyCommandProvidingFormController<T, TB, TB2> extends MyFormController { @SuppressWarnings("unused") @ModelAttribute("myCommand") private ValidTestBean createTestBean(@RequestParam T defaultName, Map<String, Object> model, @RequestParam Date date) { model.put("myKey", "myOriginalValue"); ValidTestBean tb = new ValidTestBean(); tb.setName(defaultName.getClass().getSimpleName() + ":" + defaultName.toString()); return tb; } @Override @RequestMapping("/myPath.do") public String myHandle(@ModelAttribute("myCommand") @Valid TestBean tb, BindingResult errors, ModelMap model) { if (!errors.hasFieldErrors("validCountry")) { throw new IllegalStateException("Declarative validation not applied"); } return super.myHandle(tb, errors, model); } @RequestMapping("/myOtherPath.do") public String myOtherHandle(TB tb, BindingResult errors, ExtendedModelMap model, MySpecialArg arg) { TestBean tbReal = (TestBean) tb; tbReal.setName("myName"); assertTrue(model.get("ITestBean") instanceof DerivedTestBean); assertNotNull(arg); return super.myHandle(tbReal, errors, model); } @RequestMapping("/myThirdPath.do") public String myThirdHandle(TB tb, Model model) { model.addAttribute("testBean", new TestBean("special", 99)); return "myView"; } @SuppressWarnings("unchecked") @ModelAttribute protected TB2 getModelAttr() { return (TB2) new DerivedTestBean(); } } static class MySpecialArg { public MySpecialArg(String value) { } } @Controller static class MyTypedCommandProvidingFormController extends MyCommandProvidingFormController<Integer, TestBean, ITestBean> { } @Controller static class MyBinderInitializingCommandProvidingFormController extends MyCommandProvidingFormController<String, TestBean, ITestBean> { @SuppressWarnings("unused") @InitBinder private void initBinder(WebDataBinder binder) { binder.initBeanPropertyAccess(); binder.setRequiredFields("sex"); LocalValidatorFactoryBean vf = new LocalValidatorFactoryBean(); vf.afterPropertiesSet(); binder.setValidator(vf); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); dateFormat.setLenient(false); binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false)); } @Override @RequestMapping("/myPath.do") public String myHandle(@ModelAttribute("myCommand") @Valid TestBean tb, BindingResult errors, ModelMap model) { if (!errors.hasFieldErrors("sex")) { throw new IllegalStateException("requiredFields not applied"); } return super.myHandle(tb, errors, model); } } @Controller static class MySpecificBinderInitializingCommandProvidingFormController extends MyCommandProvidingFormController<String, TestBean, ITestBean> { @SuppressWarnings("unused") @InitBinder({"myCommand", "date"}) private void initBinder(WebDataBinder binder, String date, @RequestParam("date") String[] date2) { LocalValidatorFactoryBean vf = new LocalValidatorFactoryBean(); vf.afterPropertiesSet(); binder.setValidator(vf); assertEquals("2007-10-02", date); assertEquals(1, date2.length); assertEquals("2007-10-02", date2[0]); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); dateFormat.setLenient(false); binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false)); } } static class MyWebBindingInitializer implements WebBindingInitializer { @Override public void initBinder(WebDataBinder binder) { LocalValidatorFactoryBean vf = new LocalValidatorFactoryBean(); vf.afterPropertiesSet(); binder.setValidator(vf); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); dateFormat.setLenient(false); binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false)); } } static class MySpecialArgumentResolver implements WebArgumentResolver { @Override public Object resolveArgument(MethodParameter methodParameter, NativeWebRequest webRequest) { if (methodParameter.getParameterType().equals(MySpecialArg.class)) { return new MySpecialArg("myValue"); } return UNRESOLVED; } } @Controller @RequestMapping("/myPath.do") static class MyParameterDispatchingController implements Serializable { private static final long serialVersionUID = 1L; @Autowired private transient ServletContext servletContext; @Autowired private transient ServletConfig servletConfig; @Autowired private HttpSession session; @Autowired private HttpServletRequest request; @Autowired private WebRequest webRequest; @RequestMapping public void myHandle(HttpServletResponse response, HttpServletRequest request) throws IOException { if (this.servletContext == null || this.servletConfig == null || this.session == null || this.request == null || this.webRequest == null) { throw new IllegalStateException(); } response.getWriter().write("myView"); request.setAttribute("servletContext", this.servletContext); request.setAttribute("servletConfig", this.servletConfig); request.setAttribute("sessionId", this.session.getId()); request.setAttribute("requestUri", this.request.getRequestURI()); request.setAttribute("locale", this.webRequest.getLocale()); } @RequestMapping(params = {"view", "!lang"}) public void myOtherHandle(HttpServletResponse response) throws IOException { response.getWriter().write("myOtherView"); } @RequestMapping(method = RequestMethod.GET, params = {"view=my", "lang=de"}) public void myLangHandle(HttpServletResponse response) throws IOException { response.getWriter().write("myLangView"); } @RequestMapping(method = {RequestMethod.POST, RequestMethod.GET}, params = "surprise") public void mySurpriseHandle(HttpServletResponse response) throws IOException { response.getWriter().write("mySurpriseView"); } } @Controller @RequestMapping(value = "/myPath.do", params = {"active"}) static class MyConstrainedParameterDispatchingController { @RequestMapping(params = {"view", "!lang"}) public void myOtherHandle(HttpServletResponse response) throws IOException { response.getWriter().write("myOtherView"); } @RequestMapping(method = RequestMethod.GET, params = {"view=my", "lang=de"}) public void myLangHandle(HttpServletResponse response) throws IOException { response.getWriter().write("myLangView"); } } @Controller @RequestMapping("/myApp/*") static class MyRelativePathDispatchingController { @RequestMapping public void myHandle(HttpServletResponse response) throws IOException { response.getWriter().write("myView"); } @RequestMapping("*Other") public void myOtherHandle(HttpServletResponse response) throws IOException { response.getWriter().write("myOtherView"); } @RequestMapping("myLang") public void myLangHandle(HttpServletResponse response) throws IOException { response.getWriter().write("myLangView"); } @RequestMapping("surprise") public void mySurpriseHandle(HttpServletResponse response) throws IOException { response.getWriter().write("mySurpriseView"); } } @Controller static class MyRelativeMethodPathDispatchingController { @RequestMapping("*/myHandle") // was **/myHandle public void myHandle(HttpServletResponse response) throws IOException { response.getWriter().write("myView"); } @RequestMapping("/*/*Other") // was /**/*Other public void myOtherHandle(HttpServletResponse response) throws IOException { response.getWriter().write("myOtherView"); } @RequestMapping("*/myLang") // was **/myLang public void myLangHandle(HttpServletResponse response) throws IOException { response.getWriter().write("myLangView"); } @RequestMapping("/*/surprise") // was /**/surprise public void mySurpriseHandle(HttpServletResponse response) throws IOException { response.getWriter().write("mySurpriseView"); } } @Controller static class MyNullCommandController { @ModelAttribute public TestBean getTestBean() { return null; } @ModelAttribute public Principal getPrincipal() { return new TestPrincipal(); } @RequestMapping("/myPath") public void handle(@ModelAttribute TestBean testBean, Errors errors, @ModelAttribute TestPrincipal modelPrinc, OtherPrincipal requestPrinc, Writer writer) throws IOException { assertNull(testBean); assertNotNull(modelPrinc); assertNotNull(requestPrinc); assertFalse(errors.hasErrors()); errors.reject("myCode"); writer.write("myView"); } } static class TestPrincipal implements Principal { @Override public String getName() { return "test"; } } static class OtherPrincipal implements Principal { @Override public String getName() { return "other"; } } static class TestViewResolver implements ViewResolver { @Override public View resolveViewName(final String viewName, Locale locale) throws Exception { return new View() { @Override public String getContentType() { return null; } @Override @SuppressWarnings({"unchecked", "deprecation", "rawtypes"}) public void render(Map model, HttpServletRequest request, HttpServletResponse response) throws Exception { TestBean tb = (TestBean) model.get("testBean"); if (tb == null) { tb = (TestBean) model.get("myCommand"); } if (tb.getName() != null && tb.getName().endsWith("myDefaultName")) { assertEquals(107, tb.getDate().getYear()); } Errors errors = (Errors) model.get(BindingResult.MODEL_KEY_PREFIX + "testBean"); if (errors == null) { errors = (Errors) model.get(BindingResult.MODEL_KEY_PREFIX + "myCommand"); } if (errors.hasFieldErrors("date")) { throw new IllegalStateException(); } if (model.containsKey("ITestBean")) { assertTrue(model.get(BindingResult.MODEL_KEY_PREFIX + "ITestBean") instanceof Errors); } List<TestBean> testBeans = (List<TestBean>) model.get("testBeanList"); if (errors.hasFieldErrors("age")) { response.getWriter() .write(viewName + "-" + tb.getName() + "-" + errors.getFieldError("age").getCode() + "-" + testBeans.get(0).getName() + "-" + model.get("myKey") + (model.containsKey("yourKey") ? "-" + model.get("yourKey") : "")); } else { response.getWriter().write(viewName + "-" + tb.getName() + "-" + tb.getAge() + "-" + errors.getFieldValue("name") + "-" + errors.getFieldValue("age")); } } }; } } public static class ModelExposingViewResolver implements ViewResolver { @Override public View resolveViewName(final String viewName, Locale locale) throws Exception { return new View() { @Override public String getContentType() { return null; } @Override public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) { request.setAttribute("viewName", viewName); request.getSession().setAttribute("model", model); } }; } } public static class ParentController { @RequestMapping(method = RequestMethod.GET) public void doGet(HttpServletRequest req, HttpServletResponse resp) { } } @Controller @RequestMapping("/child/test") public static class ChildController extends ParentController { @RequestMapping(method = RequestMethod.GET) public void doGet(HttpServletRequest req, HttpServletResponse resp, @RequestParam("childId") String id) { } } @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Controller public @interface MyControllerAnnotation { } @MyControllerAnnotation public static class CustomAnnotationController { @RequestMapping("/myPath.do") public void myHandle() { } } @Controller public static class RequiredParamController { @RequestMapping("/myPath.do") public void myHandle(@RequestParam(value = "id", required = true) int id, @RequestHeader(value = "header", required = true) String header) { } } @Controller public static class OptionalParamController { @RequestMapping("/myPath.do") public void myHandle(@RequestParam(required = false) String id, @RequestParam(required = false) boolean flag, @RequestHeader(value = "header", required = false) String header, HttpServletResponse response) throws IOException { response.getWriter().write(String.valueOf(id) + "-" + flag + "-" + String.valueOf(header)); } } @Controller public static class DefaultValueParamController { @RequestMapping("/myPath.do") public void myHandle(@RequestParam(value = "id", defaultValue = "foo") String id, @RequestParam(value = "otherId", defaultValue = "") String id2, @RequestHeader(defaultValue = "bar") String header, HttpServletResponse response) throws IOException { response.getWriter().write(String.valueOf(id) + "-" + String.valueOf(id2) + "-" + String.valueOf(header)); } } @Controller public static class DefaultExpressionValueParamController { @RequestMapping("/myPath.do") public void myHandle(@RequestParam(value = "id", defaultValue = "${myKey}") String id, @RequestHeader(defaultValue = "#{systemProperties.myHeader}") String header, @Value("#{request.contextPath}") String contextPath, HttpServletResponse response) throws IOException { response.getWriter().write(String.valueOf(id) + "-" + String.valueOf(header) + "-" + contextPath); } } @Controller public static class NestedSetController { @RequestMapping("/myPath.do") public void myHandle(GenericBean<?> gb, HttpServletResponse response) throws Exception { response.getWriter().write(gb.getTestBeanSet().toString() + "-" + gb.getTestBeanSet().iterator().next().getClass().getName()); } } public static class TestBeanConverter implements Converter<String, ITestBean> { @Override public ITestBean convert(String source) { return new TestBean(source); } } @Controller public static class PathVariableWithCustomConverterController { @RequestMapping("/myPath/{id}") public void myHandle(@PathVariable("id") ITestBean bean) throws Exception { } } public static class AnnotatedExceptionRaisingConverter implements Converter<String, ITestBean> { @Override public ITestBean convert(String source) { throw new NotFoundException(); } @ResponseStatus(HttpStatus.NOT_FOUND) @SuppressWarnings("serial") private static class NotFoundException extends RuntimeException { } } @Controller public static class MethodNotAllowedController { @RequestMapping(value = "/myPath.do", method = RequestMethod.DELETE) public void delete() { } @RequestMapping(value = "/myPath.do", method = RequestMethod.HEAD) public void head() { } @RequestMapping(value = "/myPath.do", method = RequestMethod.OPTIONS) public void options() { } @RequestMapping(value = "/myPath.do", method = RequestMethod.POST) public void post() { } @RequestMapping(value = "/myPath.do", method = RequestMethod.PUT) public void put() { } @RequestMapping(value = "/myPath.do", method = RequestMethod.TRACE) public void trace() { } @RequestMapping(value = "/otherPath.do", method = RequestMethod.GET) public void get() { } } @Controller public static class PathOrderingController { @RequestMapping(value = {"/dir/myPath1.do", "/*/*.do"}) public void method1(Writer writer) throws IOException { writer.write("method1"); } @RequestMapping("/dir/*.do") public void method2(Writer writer) throws IOException { writer.write("method2"); } } @Controller public static class RequestResponseBodyController { @RequestMapping(value = "/something", method = RequestMethod.PUT) @ResponseBody public String handle(@RequestBody String body) throws IOException { return body; } @RequestMapping(value = "/something", method = RequestMethod.PATCH) @ResponseBody public String handlePartialUpdate(@RequestBody String content) throws IOException { return content; } } @Controller public static class RequestResponseBodyProducesController { @RequestMapping(value = "/something", method = RequestMethod.PUT, produces = "text/plain") @ResponseBody public String handle(@RequestBody String body) throws IOException { return body; } } @Controller public static class ResponseBodyVoidController { @RequestMapping("/something") @ResponseBody public void handle() throws IOException { } } @Controller public static class RequestBodyArgMismatchController { @RequestMapping(value = "/something", method = RequestMethod.PUT) public void handle(@RequestBody A a) throws IOException { } } @XmlRootElement public static class A { } @XmlRootElement public static class B { } public static class NotReadableMessageConverter implements HttpMessageConverter<Object> { @Override public boolean canRead(Class<?> clazz, MediaType mediaType) { return true; } @Override public boolean canWrite(Class<?> clazz, MediaType mediaType) { return true; } @Override public List<MediaType> getSupportedMediaTypes() { return Collections.singletonList(new MediaType("application", "pdf")); } @Override public Object read(Class<?> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException { throw new HttpMessageNotReadableException("Could not read"); } @Override public void write(Object o, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException { throw new UnsupportedOperationException("Not implemented"); } } public static class SimpleMessageConverter implements HttpMessageConverter<Object> { private final List<MediaType> supportedMediaTypes; public SimpleMessageConverter(MediaType... supportedMediaTypes) { this.supportedMediaTypes = Arrays.asList(supportedMediaTypes); } @Override public boolean canRead(Class<?> clazz, MediaType mediaType) { return supportedMediaTypes.contains(mediaType); } @Override public boolean canWrite(Class<?> clazz, MediaType mediaType) { return supportedMediaTypes.contains(mediaType); } @Override public List<MediaType> getSupportedMediaTypes() { return supportedMediaTypes; } @Override public Object read(Class<?> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException { return null; } @Override public void write(Object o, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException { outputMessage.getHeaders().setContentType(contentType); outputMessage.getBody(); // force a header write } } @Controller public static class ContentTypeHeadersController { @RequestMapping(value = "/something", headers = "content-type=application/pdf") public void handlePdf(Writer writer) throws IOException { writer.write("pdf"); } @RequestMapping(value = "/something", headers = "content-type=text/*") public void handleHtml(Writer writer) throws IOException { writer.write("text"); } } @Controller public static class ConsumesController { @RequestMapping(value = "/something", consumes = "application/pdf") public void handlePdf(Writer writer) throws IOException { writer.write("pdf"); } @RequestMapping(value = "/something", consumes = "text/*") public void handleHtml(Writer writer) throws IOException { writer.write("text"); } } @Controller public static class NegatedContentTypeHeadersController { @RequestMapping(value = "/something", headers = "content-type=application/pdf") public void handlePdf(Writer writer) throws IOException { writer.write("pdf"); } @RequestMapping(value = "/something", headers = "content-type!=application/pdf") public void handleNonPdf(Writer writer) throws IOException { writer.write("non-pdf"); } } @Controller public static class AcceptHeadersController { @RequestMapping(value = "/something", headers = "accept=text/html") public void handleHtml(Writer writer) throws IOException { writer.write("html"); } @RequestMapping(value = "/something", headers = "accept=application/xml") public void handleXml(Writer writer) throws IOException { writer.write("xml"); } } @Controller public static class ProducesController { @RequestMapping(value = "/something", produces = "text/html") public void handleHtml(Writer writer) throws IOException { writer.write("html"); } @RequestMapping(value = "/something", produces = "application/xml") public void handleXml(Writer writer) throws IOException { writer.write("xml"); } } @Controller public static class ResponseStatusController { @RequestMapping("/something") @ResponseStatus(code = HttpStatus.CREATED, reason = "It's alive!") public void handle(Writer writer) throws IOException { writer.write("something"); } } @Controller public static class ModelAndViewResolverController { @RequestMapping("/") public MySpecialArg handle() { return new MySpecialArg("foo"); } } public static class MyModelAndViewResolver implements ModelAndViewResolver { @Override @SuppressWarnings("rawtypes") public ModelAndView resolveModelAndView(Method handlerMethod, Class<?> handlerType, Object returnValue, ExtendedModelMap implicitModel, NativeWebRequest webRequest) { if (returnValue instanceof MySpecialArg) { return new ModelAndView(new View() { @Override public String getContentType() { return "text/html"; } @Override public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception { response.getWriter().write("myValue"); } }); } return UNRESOLVED; } } @Controller @RequestMapping("/test*") static class AmbiguousParamsController { @RequestMapping(method = RequestMethod.GET) public void noParams(Writer writer) throws IOException { writer.write("noParams"); } @RequestMapping(params = "myParam") public void param(@RequestParam("myParam") int myParam, Writer writer) throws IOException { writer.write("myParam-" + myParam); } } @Controller static class AmbiguousPathAndRequestMethodController { @RequestMapping(value = "/bug/EXISTING", method = RequestMethod.POST) public void directMatch(Writer writer) throws IOException { writer.write("Direct"); } @RequestMapping(value = "/bug/{type}", method = RequestMethod.GET) public void patternMatch(Writer writer) throws IOException { writer.write("Pattern"); } } @Controller @RequestMapping("/test*") public static class BindingCookieValueController { @InitBinder public void initBinder(WebDataBinder binder) { binder.initBeanPropertyAccess(); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); dateFormat.setLenient(false); binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false)); } @RequestMapping(method = RequestMethod.GET) public void handle(@CookieValue("date") Date date, Writer writer) throws IOException { assertEquals("Invalid path variable value", new GregorianCalendar(2008, 10, 18).getTime(), date); writer.write("test-" + new SimpleDateFormat("yyyy").format(date)); } } public interface TestController<T> { ModelAndView method(T object); } public static class MyEntity { } @Controller public static class TestControllerImpl implements TestController<MyEntity> { @Override @RequestMapping("/method") public ModelAndView method(MyEntity object) { return new ModelAndView("/something"); } } @Controller public static class RequestParamMapController { @RequestMapping("/map") public void map(@RequestParam Map<String, String> params, Writer writer) throws IOException { for (Iterator<Map.Entry<String, String>> it = params.entrySet().iterator(); it.hasNext();) { Map.Entry<String, String> entry = it.next(); writer.write(entry.getKey() + "=" + entry.getValue()); if (it.hasNext()) { writer.write(','); } } } @RequestMapping("/multiValueMap") public void multiValueMap(@RequestParam MultiValueMap<String, String> params, Writer writer) throws IOException { for (Iterator<Map.Entry<String, List<String>>> it1 = params.entrySet().iterator(); it1.hasNext();) { Map.Entry<String, List<String>> entry = it1.next(); writer.write(entry.getKey() + "=["); for (Iterator<String> it2 = entry.getValue().iterator(); it2.hasNext();) { String value = it2.next(); writer.write(value); if (it2.hasNext()) { writer.write(','); } } writer.write(']'); if (it1.hasNext()) { writer.write(','); } } } } @Controller public static class RequestHeaderMapController { @RequestMapping("/map") public void map(@RequestHeader Map<String, String> headers, Writer writer) throws IOException { for (Iterator<Map.Entry<String, String>> it = headers.entrySet().iterator(); it.hasNext();) { Map.Entry<String, String> entry = it.next(); writer.write(entry.getKey() + "=" + entry.getValue()); if (it.hasNext()) { writer.write(','); } } } @RequestMapping("/multiValueMap") public void multiValueMap(@RequestHeader MultiValueMap<String, String> headers, Writer writer) throws IOException { for (Iterator<Map.Entry<String, List<String>>> it1 = headers.entrySet().iterator(); it1.hasNext();) { Map.Entry<String, List<String>> entry = it1.next(); writer.write(entry.getKey() + "=["); for (Iterator<String> it2 = entry.getValue().iterator(); it2.hasNext();) { String value = it2.next(); writer.write(value); if (it2.hasNext()) { writer.write(','); } } writer.write(']'); if (it1.hasNext()) { writer.write(','); } } } @RequestMapping("/httpHeaders") public void httpHeaders(@RequestHeader HttpHeaders headers, Writer writer) throws IOException { assertEquals("Invalid Content-Type", new MediaType("text", "html"), headers.getContentType()); multiValueMap(headers, writer); } } @Controller public interface IMyController { @RequestMapping("/handle") void handle(Writer writer, @RequestParam(value="p", required=false) String param) throws IOException; } @Controller public static class IMyControllerImpl implements IMyController { @Override public void handle(Writer writer, @RequestParam(value="p", required=false) String param) throws IOException { writer.write("handle " + param); } } public static abstract class MyAbstractController { @RequestMapping("/handle") public abstract void handle(Writer writer) throws IOException; } @Controller public static class MyAbstractControllerImpl extends MyAbstractController { @Override public void handle(Writer writer) throws IOException { writer.write("handle"); } } @Controller public static class TrailingSlashController { @RequestMapping(value = "/", method = RequestMethod.GET) public void root(Writer writer) throws IOException { writer.write("root"); } @RequestMapping(value = "/{templatePath}/", method = RequestMethod.GET) public void templatePath(Writer writer) throws IOException { writer.write("templatePath"); } } @Controller public static class ResponseEntityController { @RequestMapping(path = "/foo", method = RequestMethod.POST) public ResponseEntity<String> foo(HttpEntity<byte[]> requestEntity) throws Exception { assertNotNull(requestEntity); assertEquals("MyValue", requestEntity.getHeaders().getFirst("MyRequestHeader")); String body = new String(requestEntity.getBody(), "UTF-8"); assertEquals("Hello World", body); URI location = new URI("/foo"); return ResponseEntity.created(location).header("MyResponseHeader", "MyValue").body(body); } @RequestMapping(path = "/bar", method = RequestMethod.GET) public ResponseEntity<Void> bar() { return ResponseEntity.notFound().header("MyResponseHeader", "MyValue").build(); } @RequestMapping(path = "/baz", method = RequestMethod.GET) public ResponseEntity<String> baz() { return ResponseEntity.ok().header("MyResponseHeader", "MyValue").body("body"); } @RequestMapping(path = "/stores", method = RequestMethod.HEAD) public ResponseEntity<Void> headResource() { return ResponseEntity.ok().header("h1", "v1").build(); } @RequestMapping(path = "/stores", method = RequestMethod.GET) public ResponseEntity<String> getResource() { return ResponseEntity.ok().body("body"); } } @Controller public static class CustomMapEditorController { @InitBinder public void initBinder(WebDataBinder binder) { binder.initBeanPropertyAccess(); binder.registerCustomEditor(Map.class, new CustomMapEditor()); } @SuppressWarnings("rawtypes") @RequestMapping("/handle") public void handle(@RequestParam("map") Map map, Writer writer) throws IOException { writer.write("test-" + map); } } public static class CustomMapEditor extends PropertyEditorSupport { @Override public void setAsText(String text) throws IllegalArgumentException { if (StringUtils.hasText(text)) { setValue(Collections.singletonMap("foo", text)); } else { setValue(null); } } } @Controller public static class MultipartController { @InitBinder public void initBinder(WebDataBinder binder) { binder.registerCustomEditor(String.class, new StringMultipartFileEditor()); } @RequestMapping("/singleString") public void processMultipart(@RequestParam("content") String content, HttpServletResponse response) throws IOException { response.getWriter().write(content); } @RequestMapping("/stringArray") public void processMultipart(@RequestParam("content") String[] content, HttpServletResponse response) throws IOException { response.getWriter().write(StringUtils.arrayToDelimitedString(content, "-")); } } @Controller public static class CsvController { @RequestMapping("/singleInteger") public void processCsv(@RequestParam("content") Integer content, HttpServletResponse response) throws IOException { response.getWriter().write(content.toString()); } @RequestMapping("/integerArray") public void processCsv(@RequestParam("content") Integer[] content, HttpServletResponse response) throws IOException { response.getWriter().write(StringUtils.arrayToDelimitedString(content, "-")); } } @Controller @RequestMapping("/t1") protected static class NoPathGetAndM2PostController { @RequestMapping(method = RequestMethod.GET) public void handle1(Writer writer) throws IOException { writer.write("handle1"); } @RequestMapping(value = "/m2", method = RequestMethod.POST) public void handle2(Writer writer) throws IOException { writer.write("handle2"); } } @Controller static class HeadersConditionController { @RequestMapping(value = "/", method = RequestMethod.GET) public String home() { return "home"; } @RequestMapping(value = "/", method = RequestMethod.GET, headers="Accept=application/json") @ResponseBody public String homeJson() { return "homeJson"; } } @Controller static class RedirectAttributesController { @InitBinder public void initBinder(WebDataBinder dataBinder) { dataBinder.setRequiredFields("name"); } @GetMapping("/messages/{id}") public void message(ModelMap model, Writer writer) throws IOException { writer.write("Got: " + model.get("successMessage")); } @PostMapping("/messages") public String sendMessage(TestBean testBean, BindingResult result, RedirectAttributes attributes) { if (result.hasErrors()) { return "messages/new"; } attributes.addAttribute("id", "1").addAttribute("name", "value"); attributes.addFlashAttribute("successMessage", "yay!"); return "redirect:/messages/{id}"; } @PostMapping("/messages-response-entity") public ResponseEntity<Void> sendMessage(RedirectAttributes attributes) { attributes.addFlashAttribute("successMessage", "yay!"); URI location = URI.create("/messages/1?name=value"); return ResponseEntity.status(HttpStatus.FOUND).location(location).build(); } } @Controller static class PrototypeController { private int count; @InitBinder public void initBinder(WebDataBinder dataBinder) { this.count++; } @ModelAttribute public void populate(Model model) { this.count++; } @RequestMapping("/") public void message(int param, Writer writer) throws IOException { this.count++; writer.write("count:" + this.count); } } @RestController static class ThisWillActuallyRun { @RequestMapping(value = "/", method = RequestMethod.GET) public String home() { return "Hello World!"; } } @Controller static class HttpHeadersResponseController { @RequestMapping(value = "", method = RequestMethod.POST) @ResponseStatus(HttpStatus.CREATED) public HttpHeaders create() throws URISyntaxException { HttpHeaders headers = new HttpHeaders(); headers.setLocation(new URI("/test/items/123")); return headers; } @RequestMapping(value = "empty", method = RequestMethod.POST) @ResponseStatus(HttpStatus.CREATED) public HttpHeaders createNoHeader() throws URISyntaxException { return new HttpHeaders(); } } @RestController public static class TextRestController { @RequestMapping(path = "/a1", method = RequestMethod.GET) public String a1(@RequestBody String body) { return body; } @RequestMapping(path = "/a2.html", method = RequestMethod.GET) public String a2(@RequestBody String body) { return body; } @RequestMapping(path = "/a3", method = RequestMethod.GET, produces = "text/html") public String a3(@RequestBody String body) throws IOException { return body; } @RequestMapping(path = "/a4.css", method = RequestMethod.GET) public String a4(@RequestBody String body) { return body; } } @Controller public static class ModelAndViewController { @RequestMapping("/path") public ModelAndView methodWithHttpStatus(MyEntity object) { return new ModelAndView("view", HttpStatus.UNPROCESSABLE_ENTITY); } @RequestMapping("/exception") public void raiseException() throws Exception { throw new TestException(); } @ExceptionHandler(TestException.class) public ModelAndView handleException() { return new ModelAndView("view", HttpStatus.UNPROCESSABLE_ENTITY); } @SuppressWarnings("serial") private static class TestException extends Exception { } } public static class DataClass { public final String param1; public final int param2; public int param3; @ConstructorProperties({"param1", "param2"}) public DataClass(String param1, int p2) { this.param1 = param1; this.param2 = p2; } public void setParam3(int param3) { this.param3 = param3; } } @RestController public static class DataClassController { @RequestMapping("/bind") public String handle(DataClass data) { return data.param1 + "-" + data.param2 + "-" + data.param3; } } }