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:
parent
4f55518290
commit
9c8c967caa
|
|
@ -174,6 +174,8 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
|
|||
ManagedList<?> messageConverters = getMessageConverters(element, source, parserContext);
|
||||
ManagedList<?> argumentResolvers = getArgumentResolvers(element, source, parserContext);
|
||||
ManagedList<?> returnValueHandlers = getReturnValueHandlers(element, source, parserContext);
|
||||
String asyncTimeout = getAsyncTimeout(element, source, parserContext);
|
||||
RuntimeBeanReference asyncExecutor = getAsyncExecutor(element, source, parserContext);
|
||||
|
||||
RootBeanDefinition handlerAdapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class);
|
||||
handlerAdapterDef.setSource(source);
|
||||
|
|
@ -191,6 +193,12 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
|
|||
if (returnValueHandlers != null) {
|
||||
handlerAdapterDef.getPropertyValues().add("customReturnValueHandlers", returnValueHandlers);
|
||||
}
|
||||
if (asyncTimeout != null) {
|
||||
handlerAdapterDef.getPropertyValues().add("asyncRequestTimeout", asyncTimeout);
|
||||
}
|
||||
if (asyncExecutor != null) {
|
||||
handlerAdapterDef.getPropertyValues().add("taskExecutor", asyncExecutor);
|
||||
}
|
||||
String handlerAdapterName = parserContext.getReaderContext().registerWithGeneratedName(handlerAdapterDef);
|
||||
|
||||
RootBeanDefinition csInterceptorDef = new RootBeanDefinition(ConversionServiceExposingInterceptor.class);
|
||||
|
|
@ -318,6 +326,21 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
|
|||
}
|
||||
}
|
||||
|
||||
private String getAsyncTimeout(Element element, Object source, ParserContext parserContext) {
|
||||
Element asyncElement = DomUtils.getChildElementByTagName(element, "async-support");
|
||||
return (asyncElement != null) ? asyncElement.getAttribute("default-timeout") : null;
|
||||
}
|
||||
|
||||
private RuntimeBeanReference getAsyncExecutor(Element element, Object source, ParserContext parserContext) {
|
||||
Element asyncElement = DomUtils.getChildElementByTagName(element, "async-support");
|
||||
if (asyncElement != null) {
|
||||
if (asyncElement.hasAttribute("task-executor")) {
|
||||
return new RuntimeBeanReference(asyncElement.getAttribute("task-executor"));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private ManagedList<?> getArgumentResolvers(Element element, Object source, ParserContext parserContext) {
|
||||
Element resolversElement = DomUtils.getChildElementByTagName(element, "argument-resolvers");
|
||||
if (resolversElement != null) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* 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 java.util.concurrent.Callable;
|
||||
|
||||
import org.springframework.core.task.AsyncTaskExecutor;
|
||||
import org.springframework.core.task.SimpleAsyncTaskExecutor;
|
||||
import org.springframework.web.context.request.async.AsyncTask;
|
||||
|
||||
/**
|
||||
* Helps with configuring a options for asynchronous request processing.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.2
|
||||
*/
|
||||
public class AsyncSupportConfigurer {
|
||||
|
||||
private AsyncTaskExecutor taskExecutor;
|
||||
|
||||
private Long timeout;
|
||||
|
||||
/**
|
||||
* Set the default {@link AsyncTaskExecutor} to use when a controller method
|
||||
* returns a {@link Callable}. Controller methods can override this default on
|
||||
* a per-request basis by returning an {@link AsyncTask}.
|
||||
*
|
||||
* <p>By default a {@link SimpleAsyncTaskExecutor} instance is used and it's
|
||||
* highly recommended to change that default in production since the simple
|
||||
* executor does not re-use threads.
|
||||
*
|
||||
* @param taskExecutor the task executor instance to use by default
|
||||
*/
|
||||
public AsyncSupportConfigurer setTaskExecutor(AsyncTaskExecutor taskExecutor) {
|
||||
this.taskExecutor = taskExecutor;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the amount of time, in milliseconds, before asynchronous request
|
||||
* handling times out. In Servlet 3, the timeout begins after the main request
|
||||
* processing thread has exited and ends when the request is dispatched again
|
||||
* for further processing of the concurrently produced result.
|
||||
* <p>If this value is not set, the default timeout of the underlying
|
||||
* implementation is used, e.g. 10 seconds on Tomcat with Servlet 3.
|
||||
*
|
||||
* @param timeout the timeout value in milliseconds
|
||||
*/
|
||||
public AsyncSupportConfigurer setDefaultTimeout(long timeout) {
|
||||
this.timeout = timeout;
|
||||
return this;
|
||||
}
|
||||
|
||||
protected AsyncTaskExecutor getTaskExecutor() {
|
||||
return this.taskExecutor;
|
||||
}
|
||||
|
||||
protected Long getTimeout() {
|
||||
return this.timeout;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -60,6 +60,11 @@ public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
|
|||
this.configurers.configureContentNegotiation(configurer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
|
||||
this.configurers.configureAsyncSupport(configurer);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addViewControllers(ViewControllerRegistry registry) {
|
||||
this.configurers.addViewControllers(registry);
|
||||
|
|
|
|||
|
|
@ -354,6 +354,17 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv
|
|||
adapter.setWebBindingInitializer(webBindingInitializer);
|
||||
adapter.setCustomArgumentResolvers(argumentResolvers);
|
||||
adapter.setCustomReturnValueHandlers(returnValueHandlers);
|
||||
|
||||
AsyncSupportConfigurer configurer = new AsyncSupportConfigurer();
|
||||
configureAsyncSupport(configurer);
|
||||
|
||||
if (configurer.getTaskExecutor() != null) {
|
||||
adapter.setTaskExecutor(configurer.getTaskExecutor());
|
||||
}
|
||||
if (configurer.getTimeout() != null) {
|
||||
adapter.setAsyncRequestTimeout(configurer.getTimeout());
|
||||
}
|
||||
|
||||
return adapter;
|
||||
}
|
||||
|
||||
|
|
@ -516,6 +527,13 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv
|
|||
protected void addFormatters(FormatterRegistry registry) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Override this method to configure asynchronous request processing options.
|
||||
* @see AsyncSupportConfigurer
|
||||
*/
|
||||
public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link HttpRequestHandlerAdapter} for processing requests
|
||||
* with {@link HttpRequestHandler}s.
|
||||
|
|
|
|||
|
|
@ -74,6 +74,11 @@ public interface WebMvcConfigurer {
|
|||
*/
|
||||
void configureContentNegotiation(ContentNegotiationConfigurer configurer);
|
||||
|
||||
/**
|
||||
* Configure asynchronous request handling options.
|
||||
*/
|
||||
void configureAsyncSupport(AsyncSupportConfigurer configurer);
|
||||
|
||||
/**
|
||||
* Add resolvers to support custom controller method argument types.
|
||||
* <p>This does not override the built-in support for resolving handler
|
||||
|
|
|
|||
|
|
@ -64,6 +64,13 @@ public abstract class WebMvcConfigurerAdapter implements WebMvcConfigurer {
|
|||
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* <p>This implementation is empty.
|
||||
*/
|
||||
public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* <p>This implementation is empty.
|
||||
|
|
|
|||
|
|
@ -55,6 +55,12 @@ class WebMvcConfigurerComposite implements WebMvcConfigurer {
|
|||
}
|
||||
}
|
||||
|
||||
public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
|
||||
for (WebMvcConfigurer delegate : this.delegates) {
|
||||
delegate.configureAsyncSupport(configurer);
|
||||
}
|
||||
}
|
||||
|
||||
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
|
||||
for (WebMvcConfigurer delegate : this.delegates) {
|
||||
delegate.configureMessageConverters(converters);
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
|
@ -62,6 +63,7 @@ import org.springframework.web.bind.support.WebDataBinderFactory;
|
|||
import org.springframework.web.context.request.NativeWebRequest;
|
||||
import org.springframework.web.context.request.ServletWebRequest;
|
||||
import org.springframework.web.context.request.WebRequest;
|
||||
import org.springframework.web.context.request.async.AsyncTask;
|
||||
import org.springframework.web.context.request.async.AsyncWebRequest;
|
||||
import org.springframework.web.context.request.async.AsyncWebUtils;
|
||||
import org.springframework.web.context.request.async.WebAsyncManager;
|
||||
|
|
@ -400,26 +402,28 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter i
|
|||
}
|
||||
|
||||
/**
|
||||
* Set the AsyncTaskExecutor to use when a controller method returns a
|
||||
* {@code Callable}.
|
||||
* <p>The default instance type is a {@link SimpleAsyncTaskExecutor}.
|
||||
* It's recommended to change that default in production as the simple
|
||||
* executor does not re-use threads.
|
||||
* Set the default {@link AsyncTaskExecutor} to use when a controller method
|
||||
* return a {@link Callable}. Controller methods can override this default on
|
||||
* a per-request basis by returning an {@link AsyncTask}.
|
||||
* <p>By default a {@link SimpleAsyncTaskExecutor} instance is used.
|
||||
* It's recommended to change that default in production as the simple executor
|
||||
* does not re-use threads.
|
||||
*/
|
||||
public void setAsyncTaskExecutor(AsyncTaskExecutor taskExecutor) {
|
||||
public void setTaskExecutor(AsyncTaskExecutor taskExecutor) {
|
||||
this.taskExecutor = taskExecutor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the timeout for asynchronous request processing in milliseconds.
|
||||
* When the timeout begins depends on the underlying async technology.
|
||||
* With the Servlet 3 async support the timeout begins after the main
|
||||
* processing thread has exited and has been returned to the container pool.
|
||||
* <p>If a value is not provided, the default timeout of the underlying
|
||||
* async technology is used (10 seconds on Tomcat with Servlet 3 async).
|
||||
* Specify the amount of time, in milliseconds, before concurrent handling
|
||||
* should time out. In Servlet 3, the timeout begins after the main request
|
||||
* processing thread has exited and ends when the request is dispatched again
|
||||
* for further processing of the concurrently produced result.
|
||||
* <p>If this value is not set, the default timeout of the underlying
|
||||
* implementation is used, e.g. 10 seconds on Tomcat with Servlet 3.
|
||||
* @param timeout the timeout value in milliseconds
|
||||
*/
|
||||
public void setAsyncRequestTimeout(long asyncRequestTimeout) {
|
||||
this.asyncRequestTimeout = asyncRequestTimeout;
|
||||
public void setAsyncRequestTimeout(long timeout) {
|
||||
this.asyncRequestTimeout = timeout;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -90,6 +90,38 @@
|
|||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="async-support" minOccurs="0">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Configure options for asynchronous request processing.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="task-executor" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation source="java:org.springframework.core.task.AsyncTaskExecutor"><![CDATA[
|
||||
The bean name of a default AsyncTaskExecutor to use when a controller method returns a {@link Callable}.
|
||||
Controller methods can override this default on a per-request basis by returning an AsyncTask.
|
||||
By default a SimpleAsyncTaskExecutor is used which does not re-use threads and is not recommended for production.
|
||||
]]></xsd:documentation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:expected-type type="java:org.springframework.core.task.AsyncTaskExecutor" />
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="default-timeout" type="xsd:long">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Specify the amount of time, in milliseconds, before asynchronous request handling times out.
|
||||
In Servlet 3, the timeout begins after the main request processing thread has exited and ends when the request is dispatched again for further processing of the concurrently produced result.
|
||||
If this value is not set, the default timeout of the underlying implementation is used, e.g. 10 seconds on Tomcat with Servlet 3.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:all>
|
||||
<xsd:attribute name="conversion-service" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:mvc="http://www.springframework.org/schema/mvc"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd">
|
||||
|
||||
<mvc:annotation-driven>
|
||||
<mvc:async-support default-timeout="2500" task-executor="executor" />
|
||||
</mvc:annotation-driven>
|
||||
|
||||
<bean id="executor" class="org.springframework.scheduling.concurrent.ConcurrentTaskExecutor" />
|
||||
|
||||
</beans>
|
||||
Loading…
Reference in New Issue