Polishing

(cherry picked from commit 96f1a0e)
This commit is contained in:
Juergen Hoeller
2016-08-18 10:50:56 +02:00
parent 1295f62319
commit 71fd621a1b
5 changed files with 140 additions and 141 deletions

View File

@@ -164,10 +164,10 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv
private List<Object> interceptors;
private ContentNegotiationManager contentNegotiationManager;
private PathMatchConfigurer pathMatchConfigurer;
private ContentNegotiationManager contentNegotiationManager;
private List<HttpMessageConverter<?>> messageConverters;
@@ -186,6 +186,7 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv
this.servletContext = servletContext;
}
/**
* Return a {@link RequestMappingHandlerMapping} ordered at 0 for mapping
* requests to annotated controllers.
@@ -207,11 +208,13 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv
if (configurer.isUseTrailingSlashMatch() != null) {
handlerMapping.setUseTrailingSlashMatch(configurer.isUseTrailingSlashMatch());
}
if (configurer.getPathMatcher() != null) {
handlerMapping.setPathMatcher(configurer.getPathMatcher());
UrlPathHelper pathHelper = configurer.getUrlPathHelper();
if (pathHelper != null) {
handlerMapping.setUrlPathHelper(pathHelper);
}
if (configurer.getUrlPathHelper() != null) {
handlerMapping.setUrlPathHelper(configurer.getUrlPathHelper());
PathMatcher pathMatcher = configurer.getPathMatcher();
if (pathMatcher != null) {
handlerMapping.setPathMatcher(pathMatcher);
}
return handlerMapping;
@@ -240,48 +243,6 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv
protected void addInterceptors(InterceptorRegistry registry) {
}
/**
* Return a {@link ContentNegotiationManager} instance to use to determine
* requested {@linkplain MediaType media types} in a given request.
*/
@Bean
public ContentNegotiationManager mvcContentNegotiationManager() {
if (this.contentNegotiationManager == null) {
ContentNegotiationConfigurer configurer = new ContentNegotiationConfigurer(this.servletContext);
configurer.mediaTypes(getDefaultMediaTypes());
configureContentNegotiation(configurer);
try {
this.contentNegotiationManager = configurer.getContentNegotiationManager();
}
catch (Exception ex) {
throw new BeanInitializationException("Could not create ContentNegotiationManager", ex);
}
}
return this.contentNegotiationManager;
}
protected Map<String, MediaType> getDefaultMediaTypes() {
Map<String, MediaType> map = new HashMap<String, MediaType>();
if (romePresent) {
map.put("atom", MediaType.APPLICATION_ATOM_XML);
map.put("rss", MediaType.valueOf("application/rss+xml"));
}
if (jaxb2Present) {
map.put("xml", MediaType.APPLICATION_XML);
}
if (jackson2Present || jacksonPresent) {
map.put("json", MediaType.APPLICATION_JSON);
}
return map;
}
/**
* Override this method to configure content negotiation.
* @see DefaultServletHandlerConfigurer
*/
protected void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
}
/**
* Callback for building the {@link PathMatchConfigurer}.
* Delegates to {@link #configurePathMatch}.
@@ -312,12 +273,8 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv
*/
@Bean
public PathMatcher mvcPathMatcher() {
if (getPathMatchConfigurer().getPathMatcher() != null) {
return getPathMatchConfigurer().getPathMatcher();
}
else {
return new AntPathMatcher();
}
PathMatcher pathMatcher = getPathMatchConfigurer().getPathMatcher();
return (pathMatcher != null ? pathMatcher : new AntPathMatcher());
}
/**
@@ -329,12 +286,50 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv
*/
@Bean
public UrlPathHelper mvcUrlPathHelper() {
if (getPathMatchConfigurer().getUrlPathHelper() != null) {
return getPathMatchConfigurer().getUrlPathHelper();
UrlPathHelper pathHelper = getPathMatchConfigurer().getUrlPathHelper();
return (pathHelper != null ? pathHelper : new UrlPathHelper());
}
/**
* Return a {@link ContentNegotiationManager} instance to use to determine
* requested {@linkplain MediaType media types} in a given request.
*/
@Bean
public ContentNegotiationManager mvcContentNegotiationManager() {
if (this.contentNegotiationManager == null) {
ContentNegotiationConfigurer configurer = new ContentNegotiationConfigurer(this.servletContext);
configurer.mediaTypes(getDefaultMediaTypes());
configureContentNegotiation(configurer);
try {
this.contentNegotiationManager = configurer.getContentNegotiationManager();
}
catch (Exception ex) {
throw new BeanInitializationException("Could not create ContentNegotiationManager", ex);
}
}
else {
return new UrlPathHelper();
return this.contentNegotiationManager;
}
protected Map<String, MediaType> getDefaultMediaTypes() {
Map<String, MediaType> map = new HashMap<String, MediaType>(4);
if (romePresent) {
map.put("atom", MediaType.APPLICATION_ATOM_XML);
map.put("rss", MediaType.valueOf("application/rss+xml"));
}
if (jaxb2Present) {
map.put("xml", MediaType.APPLICATION_XML);
}
if (jackson2Present || jacksonPresent) {
map.put("json", MediaType.APPLICATION_JSON);
}
return map;
}
/**
* Override this method to configure content negotiation.
* @see DefaultServletHandlerConfigurer
*/
protected void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
}
/**
@@ -450,7 +445,6 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv
AsyncSupportConfigurer configurer = new AsyncSupportConfigurer();
configureAsyncSupport(configurer);
if (configurer.getTaskExecutor() != null) {
adapter.setTaskExecutor(configurer.getTaskExecutor());
}
@@ -475,6 +469,20 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv
return initializer;
}
/**
* Override this method to provide a custom {@link MessageCodesResolver}.
*/
protected MessageCodesResolver getMessageCodesResolver() {
return null;
}
/**
* Override this method to configure asynchronous request processing options.
* @see AsyncSupportConfigurer
*/
protected void configureAsyncSupport(AsyncSupportConfigurer configurer) {
}
/**
* Return a {@link FormattingConversionService} for use with annotated
* controller methods and the {@code spring:eval} JSP tag.
@@ -487,6 +495,12 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv
return conversionService;
}
/**
* Override this method to add custom {@link Converter}s and {@link Formatter}s.
*/
protected void addFormatters(FormatterRegistry registry) {
}
/**
* Return a global {@link Validator} instance for example for validating
* {@code @ModelAttribute} and {@code @RequestBody} method arguments.
@@ -511,7 +525,7 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv
catch (LinkageError ex) {
throw new BeanInitializationException("Could not load default validator class", ex);
}
validator = (Validator) BeanUtils.instantiate(clazz);
validator = (Validator) BeanUtils.instantiateClass(clazz);
}
else {
validator = new NoOpValidator();
@@ -527,13 +541,6 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv
return null;
}
/**
* Override this method to provide a custom {@link MessageCodesResolver}.
*/
protected MessageCodesResolver getMessageCodesResolver() {
return null;
}
/**
* Add custom {@link HandlerMethodArgumentResolver}s to use in addition to
* the ones registered by default.
@@ -625,19 +632,6 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv
}
}
/**
* Override this method to add custom {@link Converter}s and {@link Formatter}s.
*/
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.
@@ -670,11 +664,9 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv
public HandlerExceptionResolver handlerExceptionResolver() {
List<HandlerExceptionResolver> exceptionResolvers = new ArrayList<HandlerExceptionResolver>();
configureHandlerExceptionResolvers(exceptionResolvers);
if (exceptionResolvers.isEmpty()) {
addDefaultHandlerExceptionResolvers(exceptionResolvers);
}
HandlerExceptionResolverComposite composite = new HandlerExceptionResolverComposite();
composite.setOrder(0);
composite.setExceptionResolvers(exceptionResolvers);

View File

@@ -61,14 +61,6 @@ public interface WebMvcConfigurer {
*/
void configureMessageConverters(List<HttpMessageConverter<?>> converters);
/**
* Provide a custom {@link Validator} instead of the one created by default.
* The default implementation, assuming JSR-303 is on the classpath, is:
* {@link org.springframework.validation.beanvalidation.LocalValidatorFactoryBean}.
* Leave the return value as {@code null} to keep the default.
*/
Validator getValidator();
/**
* Configure content negotiation options.
*/
@@ -79,7 +71,6 @@ public interface WebMvcConfigurer {
*/
void configureAsyncSupport(AsyncSupportConfigurer configurer);
/**
* Helps with configuring HandlerMappings path matching options such as trailing slash match,
* suffix registration, path matcher and path helper.
@@ -126,13 +117,6 @@ public interface WebMvcConfigurer {
*/
void addInterceptors(InterceptorRegistry registry);
/**
* Provide a custom {@link MessageCodesResolver} for building message codes
* from data binding and validation error codes. Leave the return value as
* {@code null} to keep the default.
*/
MessageCodesResolver getMessageCodesResolver();
/**
* Add view controllers to create a direct mapping between a URL path and
* view name without the need for a controller in between.
@@ -154,4 +138,19 @@ public interface WebMvcConfigurer {
*/
void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer);
/**
* Provide a custom {@link Validator} instead of the one created by default.
* The default implementation, assuming JSR-303 is on the classpath, is:
* {@link org.springframework.validation.beanvalidation.LocalValidatorFactoryBean}.
* Leave the return value as {@code null} to keep the default.
*/
Validator getValidator();
/**
* Provide a custom {@link MessageCodesResolver} for building message codes
* from data binding and validation error codes. Leave the return value as
* {@code null} to keep the default.
*/
MessageCodesResolver getMessageCodesResolver();
}

View File

@@ -28,7 +28,7 @@ import org.springframework.web.servlet.HandlerExceptionResolver;
/**
* An implementation of {@link WebMvcConfigurer} with empty methods allowing
* sub-classes to override only the methods they're interested in.
* subclasses to override only the methods they're interested in.
*
* @author Rossen Stoyanchev
* @since 3.1
@@ -49,14 +49,6 @@ public abstract class WebMvcConfigurerAdapter implements WebMvcConfigurer {
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
}
/**
* {@inheritDoc}
* <p>This implementation returns {@code null}
*/
public Validator getValidator() {
return null;
}
/**
* {@inheritDoc}
* <p>This implementation is empty.
@@ -99,14 +91,6 @@ public abstract class WebMvcConfigurerAdapter implements WebMvcConfigurer {
public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
}
/**
* {@inheritDoc}
* <p>This implementation is empty.
*/
public MessageCodesResolver getMessageCodesResolver() {
return null;
}
/**
* {@inheritDoc}
* <p>This implementation is empty.
@@ -135,4 +119,20 @@ public abstract class WebMvcConfigurerAdapter implements WebMvcConfigurer {
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
}
/**
* {@inheritDoc}
* <p>This implementation returns {@code null}.
*/
public Validator getValidator() {
return null;
}
/**
* {@inheritDoc}
* <p>This implementation returns {@code null}.
*/
public MessageCodesResolver getMessageCodesResolver() {
return null;
}
}

View File

@@ -21,6 +21,7 @@ import java.util.List;
import org.springframework.format.FormatterRegistry;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.MessageCodesResolver;
import org.springframework.validation.Validator;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
@@ -28,7 +29,7 @@ import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.servlet.HandlerExceptionResolver;
/**
* An {@link WebMvcConfigurer} implementation that delegates to other {@link WebMvcConfigurer} instances.
* A {@link WebMvcConfigurer} that delegates to one or more others.
*
* @author Rossen Stoyanchev
* @since 3.1
@@ -37,12 +38,14 @@ class WebMvcConfigurerComposite implements WebMvcConfigurer {
private final List<WebMvcConfigurer> delegates = new ArrayList<WebMvcConfigurer>();
public void addWebMvcConfigurers(List<WebMvcConfigurer> configurers) {
if (configurers != null) {
if (!CollectionUtils.isEmpty(configurers)) {
this.delegates.addAll(configurers);
}
}
public void addFormatters(FormatterRegistry registry) {
for (WebMvcConfigurer delegate : this.delegates) {
delegate.addFormatters(registry);
@@ -126,6 +129,17 @@ class WebMvcConfigurerComposite implements WebMvcConfigurer {
return selectSingleInstance(candidates, Validator.class);
}
public MessageCodesResolver getMessageCodesResolver() {
List<MessageCodesResolver> candidates = new ArrayList<MessageCodesResolver>();
for (WebMvcConfigurer configurer : this.delegates) {
MessageCodesResolver messageCodesResolver = configurer.getMessageCodesResolver();
if (messageCodesResolver != null) {
candidates.add(messageCodesResolver);
}
}
return selectSingleInstance(candidates, MessageCodesResolver.class);
}
private <T> T selectSingleInstance(List<T> instances, Class<T> instanceType) {
if (instances.size() > 1) {
throw new IllegalStateException(
@@ -139,15 +153,4 @@ class WebMvcConfigurerComposite implements WebMvcConfigurer {
}
}
public MessageCodesResolver getMessageCodesResolver() {
List<MessageCodesResolver> candidates = new ArrayList<MessageCodesResolver>();
for (WebMvcConfigurer configurer : this.delegates) {
MessageCodesResolver messageCodesResolver = configurer.getMessageCodesResolver();
if (messageCodesResolver != null) {
candidates.add(messageCodesResolver);
}
}
return selectSingleInstance(candidates, MessageCodesResolver.class);
}
}

View File

@@ -17,7 +17,7 @@
package org.springframework.web.servlet.config.annotation;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.junit.Before;
@@ -26,6 +26,7 @@ import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.core.convert.ConversionService;
import org.springframework.format.support.FormattingConversionService;
import org.springframework.http.converter.HttpMessageConverter;
@@ -88,10 +89,10 @@ public class DelegatingWebMvcConfigurationTests {
delegatingConfig = new DelegatingWebMvcConfiguration();
}
@Test
public void requestMappingHandlerAdapter() throws Exception {
delegatingConfig.setConfigurers(Arrays.asList(webMvcConfigurer));
delegatingConfig.setConfigurers(Collections.singletonList(webMvcConfigurer));
RequestMappingHandlerAdapter adapter = delegatingConfig.requestMappingHandlerAdapter();
ConfigurableWebBindingInitializer initializer = (ConfigurableWebBindingInitializer) adapter.getWebBindingInitializer();
@@ -132,7 +133,7 @@ public class DelegatingWebMvcConfigurationTests {
public void getCustomValidator() {
given(webMvcConfigurer.getValidator()).willReturn(new LocalValidatorFactoryBean());
delegatingConfig.setConfigurers(Arrays.asList(webMvcConfigurer));
delegatingConfig.setConfigurers(Collections.singletonList(webMvcConfigurer));
delegatingConfig.mvcValidator();
verify(webMvcConfigurer).getValidator();
@@ -142,7 +143,7 @@ public class DelegatingWebMvcConfigurationTests {
public void getCustomMessageCodesResolver() {
given(webMvcConfigurer.getMessageCodesResolver()).willReturn(new DefaultMessageCodesResolver());
delegatingConfig.setConfigurers(Arrays.asList(webMvcConfigurer));
delegatingConfig.setConfigurers(Collections.singletonList(webMvcConfigurer));
delegatingConfig.getMessageCodesResolver();
verify(webMvcConfigurer).getMessageCodesResolver();
@@ -150,8 +151,7 @@ public class DelegatingWebMvcConfigurationTests {
@Test
public void handlerExceptionResolver() throws Exception {
delegatingConfig.setConfigurers(Arrays.asList(webMvcConfigurer));
delegatingConfig.setConfigurers(Collections.singletonList(webMvcConfigurer));
delegatingConfig.handlerExceptionResolver();
verify(webMvcConfigurer).configureMessageConverters(converters.capture());
@@ -177,7 +177,7 @@ public class DelegatingWebMvcConfigurationTests {
delegatingConfig.setConfigurers(configurers);
HandlerExceptionResolverComposite composite =
(HandlerExceptionResolverComposite) delegatingConfig.handlerExceptionResolver();
(HandlerExceptionResolverComposite) delegatingConfig.handlerExceptionResolver();
assertEquals("Only one custom converter is expected", 1, composite.getExceptionResolvers().size());
}
@@ -200,11 +200,16 @@ public class DelegatingWebMvcConfigurationTests {
RequestMappingHandlerMapping handlerMapping = delegatingConfig.requestMappingHandlerMapping();
assertNotNull(handlerMapping);
assertTrue(handlerMapping.useRegisteredSuffixPatternMatch());
assertTrue(handlerMapping.useSuffixPatternMatch());
assertFalse(handlerMapping.useTrailingSlashMatch());
assertSame(pathHelper, handlerMapping.getUrlPathHelper());
assertSame(pathMatcher, handlerMapping.getPathMatcher());
assertEquals("PathMatchConfigurer should configure RegisteredSuffixPatternMatch",
true, handlerMapping.useRegisteredSuffixPatternMatch());
assertEquals("PathMatchConfigurer should configure SuffixPatternMatch",
true, handlerMapping.useSuffixPatternMatch());
assertEquals("PathMatchConfigurer should configure TrailingSlashMatch",
false, handlerMapping.useTrailingSlashMatch());
assertEquals("PathMatchConfigurer should configure UrlPathHelper",
pathHelper, handlerMapping.getUrlPathHelper());
assertEquals("PathMatchConfigurer should configure PathMatcher",
pathMatcher, handlerMapping.getPathMatcher());
}
}