Add async options to MVC namespace and Java config

The MVC Java config method to implement is
WebMvcConfigurer.configureAsyncSupport(AsyncSupportConfigurer)

The MVC namespace element is:
<mvc:annotation-driven>
  <mvc:async-support default-timeout="2500" task-executor="myExecutor" />
</mvc:annotation-driven>

Issue: SPR-9694
This commit is contained in:
Rossen Stoyanchev
2012-08-17 17:05:16 -04:00
parent 4f55518290
commit 9c8c967caa
14 changed files with 552 additions and 257 deletions

View File

@@ -45,6 +45,7 @@ import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.mock.web.MockRequestDispatcher;
import org.springframework.mock.web.MockServletContext;
import org.springframework.scheduling.concurrent.ConcurrentTaskExecutor;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.validation.Errors;
@@ -451,7 +452,7 @@ public class MvcNamespaceTests {
}
@Test
public void testCustomContentNegotiationManager() throws Exception {
public void testContentNegotiationManager() throws Exception {
loadBeanDefinitions("mvc-config-content-negotiation-manager.xml", 12);
RequestMappingHandlerMapping mapping = appContext.getBean(RequestMappingHandlerMapping.class);
@@ -462,6 +463,16 @@ public class MvcNamespaceTests {
assertEquals(Arrays.asList(MediaType.valueOf("application/rss+xml")), manager.resolveMediaTypes(webRequest));
}
@Test
public void testAsyncSupportOptions() throws Exception {
loadBeanDefinitions("mvc-config-async-support.xml", 13);
RequestMappingHandlerAdapter adapter = appContext.getBean(RequestMappingHandlerAdapter.class);
assertNotNull(adapter);
assertEquals(ConcurrentTaskExecutor.class, new DirectFieldAccessor(adapter).getPropertyValue("taskExecutor").getClass());
assertEquals(2500L, new DirectFieldAccessor(adapter).getPropertyValue("asyncRequestTimeout"));
}
private void loadBeanDefinitions(String fileName, int expectedBeanCount) {
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(appContext);

View File

@@ -21,6 +21,7 @@ import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
@@ -54,14 +55,14 @@ import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolv
*/
public class DelegatingWebMvcConfigurationTests {
private DelegatingWebMvcConfiguration mvcConfiguration;
private DelegatingWebMvcConfiguration delegatingConfig;
private WebMvcConfigurer configurer;
private WebMvcConfigurer webMvcConfigurer;
@Before
public void setUp() {
configurer = EasyMock.createMock(WebMvcConfigurer.class);
mvcConfiguration = new DelegatingWebMvcConfiguration();
webMvcConfigurer = EasyMock.createMock(WebMvcConfigurer.class);
delegatingConfig = new DelegatingWebMvcConfiguration();
}
@Test
@@ -71,18 +72,20 @@ public class DelegatingWebMvcConfigurationTests {
Capture<FormattingConversionService> conversionService = new Capture<FormattingConversionService>();
Capture<List<HandlerMethodArgumentResolver>> resolvers = new Capture<List<HandlerMethodArgumentResolver>>();
Capture<List<HandlerMethodReturnValueHandler>> handlers = new Capture<List<HandlerMethodReturnValueHandler>>();
Capture<AsyncSupportConfigurer> asyncConfigurer = new Capture<AsyncSupportConfigurer>();
configurer.configureMessageConverters(capture(converters));
configurer.configureContentNegotiation(capture(contentNegotiationConfigurer));
expect(configurer.getValidator()).andReturn(null);
expect(configurer.getMessageCodesResolver()).andReturn(null);
configurer.addFormatters(capture(conversionService));
configurer.addArgumentResolvers(capture(resolvers));
configurer.addReturnValueHandlers(capture(handlers));
replay(configurer);
webMvcConfigurer.configureMessageConverters(capture(converters));
webMvcConfigurer.configureContentNegotiation(capture(contentNegotiationConfigurer));
expect(webMvcConfigurer.getValidator()).andReturn(null);
expect(webMvcConfigurer.getMessageCodesResolver()).andReturn(null);
webMvcConfigurer.addFormatters(capture(conversionService));
webMvcConfigurer.addArgumentResolvers(capture(resolvers));
webMvcConfigurer.addReturnValueHandlers(capture(handlers));
webMvcConfigurer.configureAsyncSupport(capture(asyncConfigurer));
replay(webMvcConfigurer);
mvcConfiguration.setConfigurers(Arrays.asList(configurer));
RequestMappingHandlerAdapter adapter = mvcConfiguration.requestMappingHandlerAdapter();
delegatingConfig.setConfigurers(Arrays.asList(webMvcConfigurer));
RequestMappingHandlerAdapter adapter = delegatingConfig.requestMappingHandlerAdapter();
ConfigurableWebBindingInitializer initializer = (ConfigurableWebBindingInitializer) adapter.getWebBindingInitializer();
assertSame(conversionService.getValue(), initializer.getConversionService());
@@ -91,8 +94,9 @@ public class DelegatingWebMvcConfigurationTests {
assertEquals(0, resolvers.getValue().size());
assertEquals(0, handlers.getValue().size());
assertEquals(converters.getValue(), adapter.getMessageConverters());
assertNotNull(asyncConfigurer);
verify(configurer);
verify(webMvcConfigurer);
}
@Test
@@ -104,33 +108,33 @@ public class DelegatingWebMvcConfigurationTests {
converters.add(new StringHttpMessageConverter());
}
});
mvcConfiguration = new DelegatingWebMvcConfiguration();
mvcConfiguration.setConfigurers(configurers);
delegatingConfig = new DelegatingWebMvcConfiguration();
delegatingConfig.setConfigurers(configurers);
RequestMappingHandlerAdapter adapter = mvcConfiguration.requestMappingHandlerAdapter();
RequestMappingHandlerAdapter adapter = delegatingConfig.requestMappingHandlerAdapter();
assertEquals("Only one custom converter should be registered", 1, adapter.getMessageConverters().size());
}
@Test
public void getCustomValidator() {
expect(configurer.getValidator()).andReturn(new LocalValidatorFactoryBean());
replay(configurer);
expect(webMvcConfigurer.getValidator()).andReturn(new LocalValidatorFactoryBean());
replay(webMvcConfigurer);
mvcConfiguration.setConfigurers(Arrays.asList(configurer));
mvcConfiguration.mvcValidator();
delegatingConfig.setConfigurers(Arrays.asList(webMvcConfigurer));
delegatingConfig.mvcValidator();
verify(configurer);
verify(webMvcConfigurer);
}
@Test
public void getCustomMessageCodesResolver() {
expect(configurer.getMessageCodesResolver()).andReturn(new DefaultMessageCodesResolver());
replay(configurer);
expect(webMvcConfigurer.getMessageCodesResolver()).andReturn(new DefaultMessageCodesResolver());
replay(webMvcConfigurer);
mvcConfiguration.setConfigurers(Arrays.asList(configurer));
mvcConfiguration.getMessageCodesResolver();
delegatingConfig.setConfigurers(Arrays.asList(webMvcConfigurer));
delegatingConfig.getMessageCodesResolver();
verify(configurer);
verify(webMvcConfigurer);
}
@Test
@@ -139,13 +143,13 @@ public class DelegatingWebMvcConfigurationTests {
Capture<List<HandlerExceptionResolver>> exceptionResolvers = new Capture<List<HandlerExceptionResolver>>();
Capture<ContentNegotiationConfigurer> contentNegotiationConfigurer = new Capture<ContentNegotiationConfigurer>();
configurer.configureMessageConverters(capture(converters));
configurer.configureContentNegotiation(capture(contentNegotiationConfigurer));
configurer.configureHandlerExceptionResolvers(capture(exceptionResolvers));
replay(configurer);
webMvcConfigurer.configureMessageConverters(capture(converters));
webMvcConfigurer.configureContentNegotiation(capture(contentNegotiationConfigurer));
webMvcConfigurer.configureHandlerExceptionResolvers(capture(exceptionResolvers));
replay(webMvcConfigurer);
mvcConfiguration.setConfigurers(Arrays.asList(configurer));
mvcConfiguration.handlerExceptionResolver();
delegatingConfig.setConfigurers(Arrays.asList(webMvcConfigurer));
delegatingConfig.handlerExceptionResolver();
assertEquals(3, exceptionResolvers.getValue().size());
assertTrue(exceptionResolvers.getValue().get(0) instanceof ExceptionHandlerExceptionResolver);
@@ -153,7 +157,7 @@ public class DelegatingWebMvcConfigurationTests {
assertTrue(exceptionResolvers.getValue().get(2) instanceof DefaultHandlerExceptionResolver);
assertTrue(converters.getValue().size() > 0);
verify(configurer);
verify(webMvcConfigurer);
}
@Test
@@ -165,10 +169,10 @@ public class DelegatingWebMvcConfigurationTests {
exceptionResolvers.add(new DefaultHandlerExceptionResolver());
}
});
mvcConfiguration.setConfigurers(configurers);
delegatingConfig.setConfigurers(configurers);
HandlerExceptionResolverComposite composite =
(HandlerExceptionResolverComposite) mvcConfiguration.handlerExceptionResolver();
(HandlerExceptionResolverComposite) delegatingConfig.handlerExceptionResolver();
assertEquals("Only one custom converter is expected", 1, composite.getExceptionResolvers().size());
}

View File

@@ -0,0 +1,294 @@
/*
* Copyright 2002-2012 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.config.annotation;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import java.util.Arrays;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.DirectFieldAccessor;
import org.springframework.beans.TestBean;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.io.FileSystemResourceLoader;
import org.springframework.format.FormatterRegistry;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockServletContext;
import org.springframework.scheduling.concurrent.ConcurrentTaskExecutor;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BeanPropertyBindingResult;
import org.springframework.validation.DefaultMessageCodesResolver;
import org.springframework.validation.Errors;
import org.springframework.validation.MessageCodesResolver;
import org.springframework.validation.Validator;
import org.springframework.web.accept.ContentNegotiationManager;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.support.ConfigurableWebBindingInitializer;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.context.support.StaticWebApplicationContext;
import org.springframework.web.method.annotation.ModelAttributeMethodProcessor;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.HandlerExecutionChain;
import org.springframework.web.servlet.handler.AbstractHandlerMapping;
import org.springframework.web.servlet.handler.ConversionServiceExposingInterceptor;
import org.springframework.web.servlet.handler.HandlerExceptionResolverComposite;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
/**
* A test fixture with a sub-class of {@link WebMvcConfigurationSupport} that
* implements the various {@link WebMvcConfigurer} extension points.
*
* @author Rossen Stoyanchev
*/
public class WebMvcConfigurationSupportExtensionTests {
private TestWebMvcConfigurationSupport webConfig;
private StaticWebApplicationContext webAppContext;
@Before
public void setUp() {
this.webAppContext = new StaticWebApplicationContext();
this.webAppContext.setServletContext(new MockServletContext(new FileSystemResourceLoader()));
this.webAppContext.registerSingleton("controller", TestController.class);
this.webConfig = new TestWebMvcConfigurationSupport();
this.webConfig.setApplicationContext(this.webAppContext);
this.webConfig.setServletContext(this.webAppContext.getServletContext());
}
@Test
public void handlerMappings() throws Exception {
RequestMappingHandlerMapping rmHandlerMapping = webConfig.requestMappingHandlerMapping();
rmHandlerMapping.setApplicationContext(webAppContext);
rmHandlerMapping.afterPropertiesSet();
HandlerExecutionChain chain = rmHandlerMapping.getHandler(new MockHttpServletRequest("GET", "/"));
assertNotNull(chain.getInterceptors());
assertEquals(2, chain.getInterceptors().length);
assertEquals(LocaleChangeInterceptor.class, chain.getInterceptors()[0].getClass());
assertEquals(ConversionServiceExposingInterceptor.class, chain.getInterceptors()[1].getClass());
AbstractHandlerMapping handlerMapping = (AbstractHandlerMapping) webConfig.viewControllerHandlerMapping();
handlerMapping.setApplicationContext(webAppContext);
assertNotNull(handlerMapping);
assertEquals(1, handlerMapping.getOrder());
HandlerExecutionChain handler = handlerMapping.getHandler(new MockHttpServletRequest("GET", "/path"));
assertNotNull(handler.getHandler());
handlerMapping = (AbstractHandlerMapping) webConfig.resourceHandlerMapping();
handlerMapping.setApplicationContext(webAppContext);
assertNotNull(handlerMapping);
assertEquals(Integer.MAX_VALUE-1, handlerMapping.getOrder());
handler = handlerMapping.getHandler(new MockHttpServletRequest("GET", "/resources/foo.gif"));
assertNotNull(handler.getHandler());
handlerMapping = (AbstractHandlerMapping) webConfig.defaultServletHandlerMapping();
handlerMapping.setApplicationContext(webAppContext);
assertNotNull(handlerMapping);
assertEquals(Integer.MAX_VALUE, handlerMapping.getOrder());
handler = handlerMapping.getHandler(new MockHttpServletRequest("GET", "/anyPath"));
assertNotNull(handler.getHandler());
}
@Test
public void requestMappingHandlerAdapter() throws Exception {
RequestMappingHandlerAdapter adapter = webConfig.requestMappingHandlerAdapter();
// ConversionService
String actual = webConfig.mvcConversionService().convert(new TestBean(), String.class);
assertEquals("converted", actual);
// Message converters
assertEquals(1, adapter.getMessageConverters().size());
// Custom argument resolvers and return value handlers
@SuppressWarnings("unchecked")
List<HandlerMethodArgumentResolver> argResolvers= (List<HandlerMethodArgumentResolver>)
new DirectFieldAccessor(adapter).getPropertyValue("customArgumentResolvers");
assertEquals(1, argResolvers.size());
@SuppressWarnings("unchecked")
List<HandlerMethodReturnValueHandler> handlers = (List<HandlerMethodReturnValueHandler>)
new DirectFieldAccessor(adapter).getPropertyValue("customReturnValueHandlers");
assertEquals(1, handlers.size());
// Async support options
assertEquals(ConcurrentTaskExecutor.class, new DirectFieldAccessor(adapter).getPropertyValue("taskExecutor").getClass());
assertEquals(2500L, new DirectFieldAccessor(adapter).getPropertyValue("asyncRequestTimeout"));
assertEquals(false, new DirectFieldAccessor(adapter).getPropertyValue("ignoreDefaultModelOnRedirect"));
}
@Test
public void webBindingInitializer() throws Exception {
RequestMappingHandlerAdapter adapter = webConfig.requestMappingHandlerAdapter();
ConfigurableWebBindingInitializer initializer = (ConfigurableWebBindingInitializer) adapter.getWebBindingInitializer();
assertNotNull(initializer);
BeanPropertyBindingResult bindingResult = new BeanPropertyBindingResult(null, "");
initializer.getValidator().validate(null, bindingResult);
assertEquals("invalid", bindingResult.getAllErrors().get(0).getCode());
String[] codes = initializer.getMessageCodesResolver().resolveMessageCodes("invalid", null);
assertEquals("custom.invalid", codes[0]);
}
@Test
public void contentNegotiation() throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo.json");
NativeWebRequest webRequest = new ServletWebRequest(request);
ContentNegotiationManager manager = webConfig.requestMappingHandlerMapping().getContentNegotiationManager();
assertEquals(Arrays.asList(MediaType.APPLICATION_JSON), manager.resolveMediaTypes(webRequest));
request.setRequestURI("/foo.xml");
assertEquals(Arrays.asList(MediaType.APPLICATION_XML), manager.resolveMediaTypes(webRequest));
request.setRequestURI("/foo.rss");
assertEquals(Arrays.asList(MediaType.valueOf("application/rss+xml")), manager.resolveMediaTypes(webRequest));
request.setRequestURI("/foo.atom");
assertEquals(Arrays.asList(MediaType.APPLICATION_ATOM_XML), manager.resolveMediaTypes(webRequest));
request.setRequestURI("/foo");
request.setParameter("f", "json");
assertEquals(Arrays.asList(MediaType.APPLICATION_JSON), manager.resolveMediaTypes(webRequest));
}
@Test
public void exceptionResolvers() throws Exception {
HandlerExceptionResolverComposite composite = (HandlerExceptionResolverComposite) webConfig.handlerExceptionResolver();
assertEquals(1, composite.getExceptionResolvers().size());
}
@Controller
private static class TestController {
@RequestMapping("/")
public void handle() {
}
}
/**
* Since WebMvcConfigurationSupport does not implement WebMvcConfigurer, the purpose
* of this test class is also to ensure the two are in sync with each other. Effectively
* that ensures that application config classes that use the combo {@code @EnableWebMvc}
* plus WebMvcConfigurer can switch to extending WebMvcConfigurationSupport directly for
* more advanced configuration needs.
*/
private class TestWebMvcConfigurationSupport extends WebMvcConfigurationSupport implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new Converter<TestBean, String>() {
public String convert(TestBean source) {
return "converted";
}
});
}
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(new MappingJackson2HttpMessageConverter());
}
@Override
public Validator getValidator() {
return new Validator() {
public void validate(Object target, Errors errors) {
errors.reject("invalid");
}
public boolean supports(Class<?> clazz) {
return true;
}
};
}
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.setFavorParameter(true).setParameterName("f");
}
@Override
public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
configurer.setDefaultTimeout(2500).setTaskExecutor(new ConcurrentTaskExecutor());
}
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(new ModelAttributeMethodProcessor(true));
}
@Override
public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) {
returnValueHandlers.add(new ModelAttributeMethodProcessor(true));
}
@Override
public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
exceptionResolvers.add(new SimpleMappingExceptionResolver());
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LocaleChangeInterceptor());
}
@SuppressWarnings("serial")
@Override
public MessageCodesResolver getMessageCodesResolver() {
return new DefaultMessageCodesResolver() {
@Override
public String[] resolveMessageCodes(String errorCode, String objectName) {
return new String[] { "custom." + errorCode };
}
};
}
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/path");
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("src/test/java");
}
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable("default");
}
}
}

View File

@@ -21,64 +21,44 @@ import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.DirectFieldAccessor;
import org.springframework.beans.TestBean;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.io.FileSystemResourceLoader;
import org.springframework.format.FormatterRegistry;
import org.springframework.format.support.FormattingConversionService;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockServletContext;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BeanPropertyBindingResult;
import org.springframework.validation.DefaultMessageCodesResolver;
import org.springframework.validation.Errors;
import org.springframework.validation.MessageCodesResolver;
import org.springframework.validation.Validator;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import org.springframework.web.accept.ContentNegotiationManager;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.support.ConfigurableWebBindingInitializer;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.context.support.StaticWebApplicationContext;
import org.springframework.web.method.annotation.ModelAttributeMethodProcessor;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.HandlerExecutionChain;
import org.springframework.web.servlet.handler.AbstractHandlerMapping;
import org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping;
import org.springframework.web.servlet.handler.ConversionServiceExposingInterceptor;
import org.springframework.web.servlet.handler.HandlerExceptionResolverComposite;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
/**
* A test fixture for {@link WebMvcConfigurationSupport}.
* A test fixture with an {@link WebMvcConfigurationSupport} instance.
*
* @author Rossen Stoyanchev
*/
public class WebMvcConfigurationSupportTests {
private TestWebMvcConfiguration mvcConfiguration;
private WebMvcConfigurationSupport mvcConfiguration;
@Before
public void setUp() {
mvcConfiguration = new TestWebMvcConfiguration();
mvcConfiguration = new WebMvcConfigurationSupport();
}
@Test
@@ -157,8 +137,6 @@ public class WebMvcConfigurationSupportTests {
Validator validator = initializer.getValidator();
assertNotNull(validator);
assertTrue(validator instanceof LocalValidatorFactoryBean);
assertEquals(false, new DirectFieldAccessor(adapter).getPropertyValue("ignoreDefaultModelOnRedirect"));
}
@Test
@@ -173,94 +151,6 @@ public class WebMvcConfigurationSupportTests {
assertEquals(expectedResolvers.size(), compositeResolver.getExceptionResolvers().size());
}
@Test
public void webMvcConfigurerExtensionHooks() throws Exception {
StaticWebApplicationContext appCxt = new StaticWebApplicationContext();
appCxt.setServletContext(new MockServletContext(new FileSystemResourceLoader()));
appCxt.registerSingleton("controller", TestController.class);
WebConfig webConfig = new WebConfig();
webConfig.setApplicationContext(appCxt);
webConfig.setServletContext(appCxt.getServletContext());
String actual = webConfig.mvcConversionService().convert(new TestBean(), String.class);
assertEquals("converted", actual);
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo.json");
NativeWebRequest webRequest = new ServletWebRequest(request);
ContentNegotiationManager manager = webConfig.requestMappingHandlerMapping().getContentNegotiationManager();
assertEquals(Arrays.asList(MediaType.APPLICATION_JSON), manager.resolveMediaTypes(webRequest));
request.setRequestURI("/foo.xml");
assertEquals(Arrays.asList(MediaType.APPLICATION_XML), manager.resolveMediaTypes(webRequest));
request.setRequestURI("/foo.rss");
assertEquals(Arrays.asList(MediaType.valueOf("application/rss+xml")), manager.resolveMediaTypes(webRequest));
request.setRequestURI("/foo.atom");
assertEquals(Arrays.asList(MediaType.APPLICATION_ATOM_XML), manager.resolveMediaTypes(webRequest));
request.setRequestURI("/foo");
request.setParameter("f", "json");
assertEquals(Arrays.asList(MediaType.APPLICATION_JSON), manager.resolveMediaTypes(webRequest));
RequestMappingHandlerAdapter adapter = webConfig.requestMappingHandlerAdapter();
assertEquals(1, adapter.getMessageConverters().size());
ConfigurableWebBindingInitializer initializer = (ConfigurableWebBindingInitializer) adapter.getWebBindingInitializer();
assertNotNull(initializer);
BeanPropertyBindingResult bindingResult = new BeanPropertyBindingResult(null, "");
initializer.getValidator().validate(null, bindingResult);
assertEquals("invalid", bindingResult.getAllErrors().get(0).getCode());
String[] codes = initializer.getMessageCodesResolver().resolveMessageCodes("invalid", null);
assertEquals("custom.invalid", codes[0]);
@SuppressWarnings("unchecked")
List<HandlerMethodArgumentResolver> argResolvers= (List<HandlerMethodArgumentResolver>)
new DirectFieldAccessor(adapter).getPropertyValue("customArgumentResolvers");
assertEquals(1, argResolvers.size());
@SuppressWarnings("unchecked")
List<HandlerMethodReturnValueHandler> handlers = (List<HandlerMethodReturnValueHandler>)
new DirectFieldAccessor(adapter).getPropertyValue("customReturnValueHandlers");
assertEquals(1, handlers.size());
HandlerExceptionResolverComposite composite = (HandlerExceptionResolverComposite) webConfig.handlerExceptionResolver();
assertEquals(1, composite.getExceptionResolvers().size());
RequestMappingHandlerMapping rmHandlerMapping = webConfig.requestMappingHandlerMapping();
rmHandlerMapping.setApplicationContext(appCxt);
rmHandlerMapping.afterPropertiesSet();
HandlerExecutionChain chain = rmHandlerMapping.getHandler(new MockHttpServletRequest("GET", "/"));
assertNotNull(chain.getInterceptors());
assertEquals(2, chain.getInterceptors().length);
assertEquals(LocaleChangeInterceptor.class, chain.getInterceptors()[0].getClass());
assertEquals(ConversionServiceExposingInterceptor.class, chain.getInterceptors()[1].getClass());
AbstractHandlerMapping handlerMapping = (AbstractHandlerMapping) webConfig.viewControllerHandlerMapping();
handlerMapping.setApplicationContext(appCxt);
assertNotNull(handlerMapping);
assertEquals(1, handlerMapping.getOrder());
HandlerExecutionChain handler = handlerMapping.getHandler(new MockHttpServletRequest("GET", "/path"));
assertNotNull(handler.getHandler());
handlerMapping = (AbstractHandlerMapping) webConfig.resourceHandlerMapping();
handlerMapping.setApplicationContext(appCxt);
assertNotNull(handlerMapping);
assertEquals(Integer.MAX_VALUE-1, handlerMapping.getOrder());
handler = handlerMapping.getHandler(new MockHttpServletRequest("GET", "/resources/foo.gif"));
assertNotNull(handler.getHandler());
handlerMapping = (AbstractHandlerMapping) webConfig.defaultServletHandlerMapping();
handlerMapping.setApplicationContext(appCxt);
assertNotNull(handlerMapping);
assertEquals(Integer.MAX_VALUE, handlerMapping.getOrder());
handler = handlerMapping.getHandler(new MockHttpServletRequest("GET", "/anyPath"));
assertNotNull(handler.getHandler());
}
@Controller
private static class TestController {
@@ -270,96 +160,4 @@ public class WebMvcConfigurationSupportTests {
}
}
private static class TestWebMvcConfiguration extends WebMvcConfigurationSupport {
}
/**
* Since WebMvcConfigurationSupport does not implement WebMvcConfigurer, the purpose
* of this test class is also to ensure the two are in sync with each other. Effectively
* that ensures that application config classes that use the combo {@code @EnableWebMvc}
* plus WebMvcConfigurer can switch to extending WebMvcConfigurationSupport directly for
* more advanced configuration needs.
*/
private class WebConfig extends WebMvcConfigurationSupport implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new Converter<TestBean, String>() {
public String convert(TestBean source) {
return "converted";
}
});
}
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(new MappingJackson2HttpMessageConverter());
}
@Override
public Validator getValidator() {
return new Validator() {
public void validate(Object target, Errors errors) {
errors.reject("invalid");
}
public boolean supports(Class<?> clazz) {
return true;
}
};
}
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.setFavorParameter(true).setParameterName("f");
}
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(new ModelAttributeMethodProcessor(true));
}
@Override
public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) {
returnValueHandlers.add(new ModelAttributeMethodProcessor(true));
}
@Override
public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
exceptionResolvers.add(new SimpleMappingExceptionResolver());
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LocaleChangeInterceptor());
}
@SuppressWarnings("serial")
@Override
public MessageCodesResolver getMessageCodesResolver() {
return new DefaultMessageCodesResolver() {
@Override
public String[] resolveMessageCodes(String errorCode, String objectName) {
return new String[] { "custom." + errorCode };
}
};
}
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/path");
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("src/test/java");
}
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable("default");
}
}
}