Rename EnableMvcConfiguration->EnableWebMvc, refine method names in WebMvcConfigurer, fix issue with MappedInterceptors

This commit is contained in:
Rossen Stoyanchev 2011-05-11 18:02:07 +00:00
parent c8bc54e0cc
commit 726e920857
10 changed files with 250 additions and 139 deletions

View File

@ -34,7 +34,7 @@ import org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler
* by the Servlet container's default servlet.
*
* <p>It is important the configured handler remains last in the order of all {@link HandlerMapping} instances in
* the Spring MVC web application context. That is is the case if relying on @{@link EnableMvcConfiguration}.
* the Spring MVC web application context. That is is the case if relying on @{@link EnableWebMvc}.
* However, if you register your own HandlerMapping instance sure to set its "order" property to a value lower
* than that of the {@link DefaultServletHttpRequestHandler}, which is {@link Integer#MAX_VALUE}.
*

View File

@ -30,28 +30,28 @@ import org.springframework.web.servlet.DispatcherServlet;
* in @{@link Controller} classes.
* <pre>
* &#064;Configuration
* &#064;EnableMvcConfiguration
* &#064;EnableWebMvc
* &#064;ComponentScan(
* basePackageClasses = { MyMvcConfiguration.class },
* basePackageClasses = { MyConfiguration.class },
* excludeFilters = { @Filter(type = FilterType.ANNOTATION, value = Configuration.class) }
* )
* public class MyMvcConfiguration {
* public class MyConfiguration {
*
* }
* </pre>
* <p>To customize the imported configuration you simply implement {@link MvcConfigurer}, or more likely extend
* {@link MvcConfigurerSupport} overriding selected methods only. The most obvious place to do this is
* the @{@link Configuration} class that enabled the Spring MVC configuration via @{@link EnableMvcConfiguration}.
* However any @{@link Configuration} class and more generally any Spring bean can implement {@link MvcConfigurer}
* <p>To customize the imported configuration you simply implement {@link WebMvcConfigurer}, or more likely extend
* {@link WebMvcConfigurerAdapter} overriding selected methods only. The most obvious place to do this is
* the @{@link Configuration} class that enabled the Spring MVC configuration via @{@link EnableWebMvc}.
* However any @{@link Configuration} class and more generally any Spring bean can implement {@link WebMvcConfigurer}
* to be detected and given an opportunity to customize Spring MVC configuration at startup.
* <pre>
* &#064;Configuration
* &#064;EnableMvcConfiguration
* &#064;EnableWebMvc
* &#064;ComponentScan(
* basePackageClasses = { MyMvcConfiguration.class },
* basePackageClasses = { MyConfiguration.class },
* excludeFilters = { @Filter(type = FilterType.ANNOTATION, value = Configuration.class) }
* )
* public class MyMvcConfiguration extends MvcConfigurerSupport {
* public class MyConfiguration extends WebMvcConfigurerAdapter {
*
* &#064;Override
* public void registerFormatters(FormatterRegistry formatterRegistry) {
@ -68,8 +68,8 @@ import org.springframework.web.servlet.DispatcherServlet;
* }
* </pre>
*
* @see MvcConfigurer
* @see MvcConfigurerSupport
* @see WebMvcConfigurer
* @see WebMvcConfigurerAdapter
*
* @author Dave Syer
* @author Rossen Stoyanchev
@ -78,6 +78,6 @@ import org.springframework.web.servlet.DispatcherServlet;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(MvcConfiguration.class)
public @interface EnableMvcConfiguration {
@Import(WebMvcConfiguration.class)
public @interface EnableWebMvc {
}

View File

@ -24,7 +24,6 @@ import org.springframework.web.context.request.WebRequestInterceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.servlet.handler.MappedInterceptor;
import org.springframework.web.servlet.handler.MappedInterceptors;
import org.springframework.web.servlet.handler.WebRequestHandlerInterceptorAdapter;
/**
@ -117,10 +116,10 @@ public class InterceptorConfigurer {
}
/**
* Returns a {@link MappedInterceptors} instance with all registered interceptors.
* Returns all registered interceptors.
*/
protected MappedInterceptors getMappedInterceptors() {
return new MappedInterceptors(mappedInterceptors.toArray(new MappedInterceptor[mappedInterceptors.size()]));
protected MappedInterceptor[] getInterceptors() {
return mappedInterceptors.toArray(new MappedInterceptor[mappedInterceptors.size()]);
}
}

View File

@ -58,6 +58,7 @@ import org.springframework.web.servlet.HandlerMapping;
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.MappedInterceptor;
import org.springframework.web.servlet.handler.MappedInterceptors;
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
import org.springframework.web.servlet.mvc.Controller;
@ -72,10 +73,10 @@ import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolv
/**
* Provides default configuration for Spring MVC applications. Registers Spring MVC infrastructure components to be
* detected by the {@link DispatcherServlet}. Further below is a list of registered instances. This configuration is
* enabled through the {@link EnableMvcConfiguration} annotation.
* enabled through the {@link EnableWebMvc} annotation.
*
* <p>A number of options are available for customizing the default configuration provided by this class.
* See {@link EnableMvcConfiguration} and {@link MvcConfigurer} for details.
* See {@link EnableWebMvc} and {@link WebMvcConfigurer} for details.
*
* <p>Registers these handler mappings:
* <ul>
@ -87,7 +88,7 @@ import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolv
* </ul>
*
* <p><strong>Note:</strong> that the SimpleUrlHandlerMapping instances above will have empty URL maps and
* hence no effect until explicitly configured via {@link MvcConfigurer}.
* hence no effect until explicitly configured via {@link WebMvcConfigurer}.
*
* <p>Registers these handler adapters:
* <ul>
@ -110,23 +111,23 @@ import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolv
* <li>{@link MappedInterceptors} containing a list Spring MVC lifecycle interceptors.
* </ul>
*
* @see EnableMvcConfiguration
* @see MvcConfigurer
* @see EnableWebMvc
* @see WebMvcConfigurer
*
* @author Rossen Stoyanchev
* @since 3.1
*/
@Configuration
class MvcConfiguration implements ApplicationContextAware, ServletContextAware {
class WebMvcConfiguration implements ApplicationContextAware, ServletContextAware {
private final MvcConfigurerComposite configurers = new MvcConfigurerComposite();
private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();
private ServletContext servletContext;
private ApplicationContext applicationContext;
@Autowired(required = false)
public void setConfigurers(List<MvcConfigurer> configurers) {
public void setConfigurers(List<WebMvcConfigurer> configurers) {
this.configurers.addConfigurers(configurers);
}
@ -139,29 +140,41 @@ class MvcConfiguration implements ApplicationContextAware, ServletContextAware {
}
@Bean
RequestMappingHandlerMapping requestMappingHandlerMapping() {
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
RequestMappingHandlerMapping mapping = new RequestMappingHandlerMapping();
mapping.setMappedInterceptors(getMappedInterceptors());
mapping.setOrder(0);
return mapping;
}
@Bean
HandlerMapping viewControllerHandlerMapping() {
ViewControllerConfigurer configurer = new ViewControllerConfigurer();
configurer.setOrder(1);
configurers.addViewControllers(configurer);
return configurer.getHandlerMapping();
private MappedInterceptor[] getMappedInterceptors() {
InterceptorConfigurer configurer = new InterceptorConfigurer();
configurers.configureInterceptors(configurer);
configurer.addInterceptor(new ConversionServiceExposingInterceptor(conversionService()));
return configurer.getInterceptors();
}
@Bean
BeanNameUrlHandlerMapping beanNameHandlerMapping() {
public HandlerMapping viewControllerHandlerMapping() {
ViewControllerConfigurer configurer = new ViewControllerConfigurer();
configurer.setOrder(1);
configurers.configureViewControllers(configurer);
SimpleUrlHandlerMapping handlerMapping = configurer.getHandlerMapping();
handlerMapping.setMappedInterceptors(getMappedInterceptors());
return handlerMapping;
}
@Bean
public BeanNameUrlHandlerMapping beanNameHandlerMapping() {
BeanNameUrlHandlerMapping mapping = new BeanNameUrlHandlerMapping();
mapping.setOrder(2);
mapping.setMappedInterceptors(getMappedInterceptors());
return mapping;
}
@Bean
HandlerMapping resourceHandlerMapping() {
public HandlerMapping resourceHandlerMapping() {
ResourceConfigurer configurer = new ResourceConfigurer(applicationContext, servletContext);
configurer.setOrder(Integer.MAX_VALUE-1);
configurers.configureResourceHandling(configurer);
@ -169,14 +182,14 @@ class MvcConfiguration implements ApplicationContextAware, ServletContextAware {
}
@Bean
HandlerMapping defaultServletHandlerMapping() {
public HandlerMapping defaultServletHandlerMapping() {
DefaultServletHandlerConfigurer configurer = new DefaultServletHandlerConfigurer(servletContext);
configurers.configureDefaultServletHandling(configurer);
return configurer.getHandlerMapping();
}
@Bean
RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
RequestMappingHandlerAdapter adapter = new RequestMappingHandlerAdapter();
ConfigurableWebBindingInitializer bindingInitializer = new ConfigurableWebBindingInitializer();
@ -185,29 +198,32 @@ class MvcConfiguration implements ApplicationContextAware, ServletContextAware {
adapter.setWebBindingInitializer(bindingInitializer);
List<HandlerMethodArgumentResolver> argumentResolvers = new ArrayList<HandlerMethodArgumentResolver>();
configurers.addCustomArgumentResolvers(argumentResolvers);
configurers.addArgumentResolvers(argumentResolvers);
adapter.setCustomArgumentResolvers(argumentResolvers);
List<HandlerMethodReturnValueHandler> returnValueHandlers = new ArrayList<HandlerMethodReturnValueHandler>();
configurers.addCustomReturnValueHandlers(returnValueHandlers);
configurers.addReturnValueHandlers(returnValueHandlers);
adapter.setCustomReturnValueHandlers(returnValueHandlers);
List<HttpMessageConverter<?>> converters = getDefaultHttpMessageConverters();
List<HttpMessageConverter<?>> converters = new ArrayList<HttpMessageConverter<?>>();
configurers.configureMessageConverters(converters);
if (converters.size() == 0) {
addDefaultHttpMessageConverters(converters);
}
adapter.setMessageConverters(converters);
return adapter;
}
@Bean(name="mvcConversionService")
FormattingConversionService conversionService() {
public FormattingConversionService conversionService() {
FormattingConversionService conversionService = new DefaultFormattingConversionService();
configurers.registerFormatters(conversionService);
configurers.addFormatters(conversionService);
return conversionService;
}
@Bean(name="mvcValidator")
Validator validator() {
public Validator validator() {
Validator validator = configurers.getValidator();
if (validator != null) {
return validator;
@ -216,7 +232,7 @@ class MvcConfiguration implements ApplicationContextAware, ServletContextAware {
Class<?> clazz;
try {
String className = "org.springframework.validation.beanvalidation.LocalValidatorFactoryBean";
clazz = ClassUtils.forName(className, MvcConfiguration.class.getClassLoader());
clazz = ClassUtils.forName(className, WebMvcConfiguration.class.getClassLoader());
} catch (ClassNotFoundException e) {
throw new BeanInitializationException("Could not find default validator");
} catch (LinkageError e) {
@ -236,11 +252,10 @@ class MvcConfiguration implements ApplicationContextAware, ServletContextAware {
}
}
private List<HttpMessageConverter<?>> getDefaultHttpMessageConverters() {
private void addDefaultHttpMessageConverters(List<HttpMessageConverter<?>> converters) {
StringHttpMessageConverter stringConverter = new StringHttpMessageConverter();
stringConverter.setWriteAcceptCharset(false);
List<HttpMessageConverter<?>> converters = new ArrayList<HttpMessageConverter<?>>();
converters.add(new ByteArrayHttpMessageConverter());
converters.add(stringConverter);
converters.add(new ResourceHttpMessageConverter());
@ -258,27 +273,28 @@ class MvcConfiguration implements ApplicationContextAware, ServletContextAware {
converters.add(new AtomFeedHttpMessageConverter());
converters.add(new RssChannelHttpMessageConverter());
}
return converters;
}
@Bean
HttpRequestHandlerAdapter httpRequestHandlerAdapter() {
public HttpRequestHandlerAdapter httpRequestHandlerAdapter() {
return new HttpRequestHandlerAdapter();
}
@Bean
SimpleControllerHandlerAdapter simpleControllerHandlerAdapter() {
public SimpleControllerHandlerAdapter simpleControllerHandlerAdapter() {
return new SimpleControllerHandlerAdapter();
}
@Bean
HandlerExceptionResolver handlerExceptionResolver() throws Exception {
public HandlerExceptionResolver handlerExceptionResolver() throws Exception {
List<HandlerExceptionResolver> resolvers = new ArrayList<HandlerExceptionResolver>();
configurers.configureHandlerExceptionResolvers(resolvers);
if (resolvers.size() == 0) {
resolvers.add(createExceptionHandlerExceptionResolver());
resolvers.add(new ResponseStatusExceptionResolver());
resolvers.add(new DefaultHandlerExceptionResolver());
configurers.configureHandlerExceptionResolvers(resolvers);
}
HandlerExceptionResolverComposite composite = new HandlerExceptionResolverComposite();
composite.setOrder(0);
@ -288,22 +304,17 @@ class MvcConfiguration implements ApplicationContextAware, ServletContextAware {
private HandlerExceptionResolver createExceptionHandlerExceptionResolver() throws Exception {
ExceptionHandlerExceptionResolver resolver = new ExceptionHandlerExceptionResolver();
List<HttpMessageConverter<?>> converters = getDefaultHttpMessageConverters();
configurers.configureMessageConverters(converters);
resolver.setMessageConverters(converters);
resolver.setOrder(0);
List<HttpMessageConverter<?>> converters = new ArrayList<HttpMessageConverter<?>>();
configurers.configureMessageConverters(converters);
if (converters.size() == 0) {
addDefaultHttpMessageConverters(converters);
}
resolver.setMessageConverters(converters);
resolver.afterPropertiesSet();
return resolver;
}
@Bean
MappedInterceptors mappedInterceptors() {
InterceptorConfigurer configurer = new InterceptorConfigurer();
configurer.addInterceptor(new ConversionServiceExposingInterceptor(conversionService()));
configurers.addInterceptors(configurer);
return configurer.getMappedInterceptors();
}
}

View File

@ -36,12 +36,12 @@ import com.sun.corba.se.impl.presentation.rmi.ExceptionHandler;
/**
* Defines options for customizing or adding to the default Spring MVC configuration enabled through the use
* of @{@link EnableMvcConfiguration}. The @{@link Configuration} class annotated with @{@link EnableMvcConfiguration}
* of @{@link EnableWebMvc}. The @{@link Configuration} class annotated with @{@link EnableWebMvc}
* is the most obvious place to implement this interface. However all @{@link Configuration} classes and more generally
* all Spring beans that implement this interface will be detected at startup and given a chance to customize Spring
* MVC configuration provided it is enabled through @{@link EnableMvcConfiguration}.
* MVC configuration provided it is enabled through @{@link EnableWebMvc}.
*
* <p>Implementations of this interface will find it convenient to extend {@link MvcConfigurerSupport} that
* <p>Implementations of this interface will find it convenient to extend {@link WebMvcConfigurerAdapter} that
* provides default method implementations and allows overriding only methods of interest.
*
* @author Rossen Stoyanchev
@ -49,17 +49,18 @@ import com.sun.corba.se.impl.presentation.rmi.ExceptionHandler;
* @author David Syer
* @since 3.1
*/
public interface MvcConfigurer {
public interface WebMvcConfigurer {
/**
* Register application-specific {@link Converter}s and {@link Formatter}s for use in Spring MVC.
* Add {@link Converter}s and {@link Formatter}s in addition to the ones registered by default.
*/
void registerFormatters(FormatterRegistry formatterRegistry);
void addFormatters(FormatterRegistry formatterRegistry);
/**
* Customize the list of {@link HttpMessageConverter}s to use when resolving method arguments or handling
* return values from @{@link RequestMapping} and @{@link ExceptionHandler} methods.
* @param converters the list of converters, initially populated with the default set of converters
* Configure the list of {@link HttpMessageConverter}s to use when resolving method arguments or handling
* return values in @{@link RequestMapping} and @{@link ExceptionHandler} methods.
* Specifying custom converters overrides the converters registered by default.
* @param converters a list to add message converters to
*/
void configureMessageConverters(List<HttpMessageConverter<?>> converters);
@ -71,37 +72,43 @@ public interface MvcConfigurer {
Validator getValidator();
/**
* Add custom {@link HandlerMethodArgumentResolver}s to use for resolving argument values
* on @{@link RequestMapping} and @{@link ExceptionHandler} methods.
* Add custom {@link HandlerMethodArgumentResolver}s to use in addition to the ones registered by default.
* <p>Generally custom argument resolvers are invoked first. However this excludes default argument resolvers that
* rely on the presence of annotations (e.g. {@code @RequestParameter}, {@code @PathVariable}, etc.). Those
* argument resolvers are not customizable without configuring RequestMappingHandlerAdapter directly.
* @param argumentResolvers the list of custom converters, initially empty
*/
void addCustomArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers);
void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers);
/**
* Add custom {@link HandlerMethodReturnValueHandler}s to use for handling return values
* from @{@link RequestMapping} and @{@link ExceptionHandler} methods.
* Add custom {@link HandlerMethodReturnValueHandler}s to in addition to the ones registered by default.
* <p>Generally custom return value handlers are invoked first. However this excludes default return value handlers
* that rely on the presence of annotations (e.g. {@code @ResponseBody}, {@code @ModelAttribute}, etc.). Those
* handlers are not customizable without configuring RequestMappingHandlerAdapter directly.
* @param returnValueHandlers the list of custom handlers, initially empty
*/
void addCustomReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers);
void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers);
/**
* Customize the list of {@link HandlerExceptionResolver}s to use for handling controller exceptions.
* @param exceptionResolvers the list of resolvers, initially populated with the default set of resolvers
* Configure the list of {@link HandlerExceptionResolver}s to use for handling unresolved controller exceptions.
* Specifying exception resolvers overrides the ones registered by default.
* @param exceptionResolvers a list to add exception resolvers to
*/
void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers);
/**
* Add Spring MVC interceptors. Interceptors can be of type {@link HandlerInterceptor} or
* Configure the Spring MVC interceptors to use. Interceptors can be of type {@link HandlerInterceptor} or
* {@link WebRequestInterceptor}. They allow requests to be pre/post processed before/after controller
* invocation. Interceptors can be registered to apply to all requests or limited to a set of path patterns.
* @see InterceptorConfigurer
*/
void addInterceptors(InterceptorConfigurer interceptorConfigurer);
void configureInterceptors(InterceptorConfigurer interceptorConfigurer);
/**
* Map URL paths to view names. This is convenient when a request can be rendered without a controller.
* Configure the view controllers to use. A view controller is used to map a URL path directly to a view name.
* This is convenient when a request does not require controller logic.
*/
void addViewControllers(ViewControllerConfigurer viewControllerConfigurer);
void configureViewControllers(ViewControllerConfigurer viewControllerConfigurer);
/**
* Configure a handler for serving static resources such as images, js, and, css files through Spring MVC

View File

@ -22,22 +22,23 @@ import org.springframework.format.FormatterRegistry;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.validation.Validator;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.servlet.HandlerExceptionResolver;
/**
* An abstract class with empty method implementations of the {@link MvcConfigurer} interface for a simplified
* implementation of {@link MvcConfigurer} so that subclasses can override selected methods only.
* An abstract class with empty method implementations of {@link WebMvcConfigurer}.
* Subclasses can override only the methods they need.
*
* @author Rossen Stoyanchev
* @since 3.1
*/
public abstract class MvcConfigurerSupport implements MvcConfigurer {
public abstract class WebMvcConfigurerAdapter implements WebMvcConfigurer {
/**
* {@inheritDoc}
* <p>This implementation is empty.
*/
public void registerFormatters(FormatterRegistry formatterRegistry) {
public void addFormatters(FormatterRegistry formatterRegistry) {
}
/**
@ -47,13 +48,6 @@ public abstract class MvcConfigurerSupport implements MvcConfigurer {
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
}
/**
* {@inheritDoc}
* <p>This implementation is empty.
*/
public void configureValidator(Validator validator) {
}
/**
* {@inheritDoc}
* <p>This implementation returns {@code null}
@ -66,7 +60,14 @@ public abstract class MvcConfigurerSupport implements MvcConfigurer {
* {@inheritDoc}
* <p>This implementation is empty.
*/
public void addCustomArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
}
/**
* {@inheritDoc}
* <p>This implementation is empty.
*/
public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) {
}
/**
@ -80,14 +81,14 @@ public abstract class MvcConfigurerSupport implements MvcConfigurer {
* {@inheritDoc}
* <p>This implementation is empty.
*/
public void addInterceptors(InterceptorConfigurer interceptorConfigurer) {
public void configureInterceptors(InterceptorConfigurer interceptorConfigurer) {
}
/**
* {@inheritDoc}
* <p>This implementation is empty.
*/
public void addViewControllers(ViewControllerConfigurer viewControllerConfigurer) {
public void configureViewControllers(ViewControllerConfigurer viewControllerConfigurer) {
}
/**

View File

@ -29,78 +29,78 @@ import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.servlet.HandlerExceptionResolver;
/**
* An {@link MvcConfigurer} implementation that delegates to other {@link MvcConfigurer} instances.
* An {@link WebMvcConfigurer} implementation that delegates to other {@link WebMvcConfigurer} instances.
*
* @author Rossen Stoyanchev
* @since 3.1
*/
class MvcConfigurerComposite implements MvcConfigurer {
class WebMvcConfigurerComposite implements WebMvcConfigurer {
private final List<MvcConfigurer> configurers = new ArrayList<MvcConfigurer>();
private final List<WebMvcConfigurer> configurers = new ArrayList<WebMvcConfigurer>();
void addConfigurers(List<MvcConfigurer> configurers) {
public void addConfigurers(List<WebMvcConfigurer> configurers) {
if (configurers != null) {
this.configurers.addAll(configurers);
}
}
public void registerFormatters(FormatterRegistry formatterRegistry) {
for (MvcConfigurer configurer : configurers) {
configurer.registerFormatters(formatterRegistry);
public void addFormatters(FormatterRegistry formatterRegistry) {
for (WebMvcConfigurer configurer : configurers) {
configurer.addFormatters(formatterRegistry);
}
}
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
for (MvcConfigurer configurer : configurers) {
for (WebMvcConfigurer configurer : configurers) {
configurer.configureMessageConverters(converters);
}
}
public void addCustomArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
for (MvcConfigurer configurer : configurers) {
configurer.addCustomArgumentResolvers(argumentResolvers);
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
for (WebMvcConfigurer configurer : configurers) {
configurer.addArgumentResolvers(argumentResolvers);
}
}
public void addCustomReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) {
for (MvcConfigurer configurer : configurers) {
configurer.addCustomReturnValueHandlers(returnValueHandlers);
public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) {
for (WebMvcConfigurer configurer : configurers) {
configurer.addReturnValueHandlers(returnValueHandlers);
}
}
public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
for (MvcConfigurer configurer : configurers) {
for (WebMvcConfigurer configurer : configurers) {
configurer.configureHandlerExceptionResolvers(exceptionResolvers);
}
}
public void addInterceptors(InterceptorConfigurer interceptorRegistry) {
for (MvcConfigurer configurer : configurers) {
configurer.addInterceptors(interceptorRegistry);
public void configureInterceptors(InterceptorConfigurer interceptorRegistry) {
for (WebMvcConfigurer configurer : configurers) {
configurer.configureInterceptors(interceptorRegistry);
}
}
public void addViewControllers(ViewControllerConfigurer viewControllerConfigurer) {
for (MvcConfigurer configurer : configurers) {
configurer.addViewControllers(viewControllerConfigurer);
public void configureViewControllers(ViewControllerConfigurer viewControllerConfigurer) {
for (WebMvcConfigurer configurer : configurers) {
configurer.configureViewControllers(viewControllerConfigurer);
}
}
public void configureResourceHandling(ResourceConfigurer resourceConfigurer) {
for (MvcConfigurer configurer : configurers) {
for (WebMvcConfigurer configurer : configurers) {
configurer.configureResourceHandling(resourceConfigurer);
}
}
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer handlerConfigurer) {
for (MvcConfigurer configurer : configurers) {
for (WebMvcConfigurer configurer : configurers) {
configurer.configureDefaultServletHandling(handlerConfigurer);
}
}
public Validator getValidator() {
Map<MvcConfigurer, Validator> validators = new HashMap<MvcConfigurer, Validator>();
for (MvcConfigurer configurer : configurers) {
Map<WebMvcConfigurer, Validator> validators = new HashMap<WebMvcConfigurer, Validator>();
for (WebMvcConfigurer configurer : configurers) {
Validator validator = configurer.getValidator();
if (validator != null) {
validators.put(configurer, validator);

View File

@ -1,5 +1,6 @@
package org.springframework.web.servlet.handler;
import java.util.Collections;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
@ -10,7 +11,7 @@ import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
/**
* A {@link HandlerExceptionResolver} that delegates to a list of {@link HandlerExceptionResolver}s.
* A {@link HandlerExceptionResolver} that delegates to a list of other {@link HandlerExceptionResolver}s.
*
* @author Rossen Stoyanchev
* @since 3.1
@ -29,10 +30,24 @@ public class HandlerExceptionResolverComposite implements HandlerExceptionResolv
return this.order;
}
/**
* Set the list of exception resolvers to delegate to.
*/
public void setExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
this.resolvers = exceptionResolvers;
}
/**
* Return the list of exception resolvers to delegate to.
*/
public List<HandlerExceptionResolver> getExceptionResolvers() {
return Collections.unmodifiableList(resolvers);
}
/**
* Resolve the exception by iterating over the list of configured exception resolvers.
* The first one to return a ModelAndView instance wins. Otherwise {@code null} is returned.
*/
public ModelAndView resolveException(HttpServletRequest request,
HttpServletResponse response,
Object handler,

View File

@ -29,6 +29,7 @@ import org.springframework.util.AntPathMatcher;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.context.request.WebRequestInterceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.handler.MappedInterceptors;
import org.springframework.web.servlet.handler.WebRequestHandlerInterceptorAdapter;
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
import org.springframework.web.servlet.theme.ThemeChangeInterceptor;
@ -139,7 +140,8 @@ public class InterceptorConfigurerTests {
}
private HandlerInterceptor[] getInterceptorsForPath(String lookupPath) {
return configurer.getMappedInterceptors().getInterceptors(lookupPath, new AntPathMatcher());
MappedInterceptors mappedInterceptors = new MappedInterceptors(configurer.getInterceptors());
return mappedInterceptors.getInterceptors(lookupPath, new AntPathMatcher());
}
private void verifyAdaptedInterceptor(HandlerInterceptor interceptor, TestWebRequestInterceptor webInterceptor)

View File

@ -21,44 +21,55 @@ 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;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.easymock.Capture;
import org.easymock.EasyMock;
import org.junit.Before;
import org.junit.Test;
import org.springframework.format.support.FormattingConversionService;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.support.ConfigurableWebBindingInitializer;
import org.springframework.web.context.support.StaticWebApplicationContext;
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.HandlerExceptionResolverComposite;
import org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver;
import org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver;
/**
* A test fixture with an {@link MvcConfiguration} and a mock {@link MvcConfigurer} for verifying delegation.
* A test fixture for WebMvcConfiguration tests.
*
* @author Rossen Stoyanchev
*/
public class MvcConfigurationTests {
public class WebMvcConfigurationTests {
private MvcConfiguration mvcConfiguration;
private WebMvcConfiguration mvcConfiguration;
private MvcConfigurer configurer;
private WebMvcConfigurer configurer;
@Before
public void setUp() {
configurer = EasyMock.createMock(MvcConfigurer.class);
mvcConfiguration = new MvcConfiguration();
mvcConfiguration.setConfigurers(Arrays.asList(configurer));
configurer = EasyMock.createMock(WebMvcConfigurer.class);
mvcConfiguration = new WebMvcConfiguration();
}
@Test
@ -69,12 +80,13 @@ public class MvcConfigurationTests {
Capture<List<HttpMessageConverter<?>>> converters = new Capture<List<HttpMessageConverter<?>>>();
expect(configurer.getValidator()).andReturn(null);
configurer.registerFormatters(capture(conversionService));
configurer.addCustomArgumentResolvers(capture(resolvers));
configurer.addCustomReturnValueHandlers(capture(handlers));
configurer.addFormatters(capture(conversionService));
configurer.addArgumentResolvers(capture(resolvers));
configurer.addReturnValueHandlers(capture(handlers));
configurer.configureMessageConverters(capture(converters));
replay(configurer);
mvcConfiguration.setConfigurers(Arrays.asList(configurer));
RequestMappingHandlerAdapter adapter = mvcConfiguration.requestMappingHandlerAdapter();
ConfigurableWebBindingInitializer initializer = (ConfigurableWebBindingInitializer) adapter.getWebBindingInitializer();
@ -89,11 +101,30 @@ public class MvcConfigurationTests {
verify(configurer);
}
@Test
public void configureMessageConverters() {
RequestMappingHandlerAdapter adapter = mvcConfiguration.requestMappingHandlerAdapter();
assertTrue("There should be at least two default converters ", adapter.getMessageConverters().size() > 1);
List<WebMvcConfigurer> configurers = new ArrayList<WebMvcConfigurer>();
configurers.add(new WebMvcConfigurerAdapter() {
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(new StringHttpMessageConverter());
}
});
mvcConfiguration.setConfigurers(configurers );
adapter = mvcConfiguration.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);
mvcConfiguration.setConfigurers(Arrays.asList(configurer));
mvcConfiguration.validator();
verify(configurer);
@ -104,6 +135,7 @@ public class MvcConfigurationTests {
expect(configurer.getValidator()).andReturn(null);
replay(configurer);
mvcConfiguration.setConfigurers(Arrays.asList(configurer));
mvcConfiguration.validator();
verify(configurer);
@ -118,6 +150,7 @@ public class MvcConfigurationTests {
configurer.configureHandlerExceptionResolvers(capture(exceptionResolvers));
replay(configurer);
mvcConfiguration.setConfigurers(Arrays.asList(configurer));
mvcConfiguration.handlerExceptionResolver();
assertEquals(3, exceptionResolvers.getValue().size());
@ -129,4 +162,47 @@ public class MvcConfigurationTests {
verify(configurer);
}
@Test
public void configureExceptionResolvers() throws Exception {
HandlerExceptionResolverComposite composite;
composite = (HandlerExceptionResolverComposite) mvcConfiguration.handlerExceptionResolver();
assertTrue("Expected more than one exception resolver by default", composite.getExceptionResolvers().size() > 1);
List<WebMvcConfigurer> configurers = new ArrayList<WebMvcConfigurer>();
configurers.add(new WebMvcConfigurerAdapter() {
@Override
public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
exceptionResolvers.add(new DefaultHandlerExceptionResolver());
}
});
mvcConfiguration.setConfigurers(configurers);
composite = (HandlerExceptionResolverComposite) mvcConfiguration.handlerExceptionResolver();
assertEquals("Only one custom converter is expected", 1, composite.getExceptionResolvers().size());
}
@Test
public void configureInterceptors() throws Exception {
HttpServletRequest request = new MockHttpServletRequest("GET", "/");
StaticWebApplicationContext context = new StaticWebApplicationContext();
context.registerSingleton("controller", TestHandler.class);
RequestMappingHandlerMapping hm = mvcConfiguration.requestMappingHandlerMapping();
hm.setApplicationContext(context);
HandlerExecutionChain chain = hm.getHandler(request);
assertNotNull("Expected at one default converter", chain.getInterceptors());
}
@Controller
private static class TestHandler {
@SuppressWarnings("unused")
@RequestMapping("/")
public void handle() {
}
}
}