From 69a8c0d871d190bfb99e13920fe1eba1b4229b6f Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Thu, 20 Apr 2017 11:57:18 -0700 Subject: [PATCH 1/2] Fix MVC validator configuration warning Replace the MVC validator post processor with an `@Import` so that a "cannot enhance @Configuration bean definition" warning does not occur. Fixes gh-8951 See gh-8495 --- .../web/WebMvcAutoConfiguration.java | 57 ++++++++----------- 1 file changed, 25 insertions(+), 32 deletions(-) diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/WebMvcAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/WebMvcAutoConfiguration.java index a51f65a06d5..7797e39bbf2 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/WebMvcAutoConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/WebMvcAutoConfiguration.java @@ -32,6 +32,7 @@ import org.apache.commons.logging.LogFactory; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.BeanFactoryUtils; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; @@ -39,11 +40,7 @@ import org.springframework.beans.factory.ListableBeanFactory; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.beans.factory.config.BeanFactoryPostProcessor; -import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.support.BeanDefinitionRegistry; -import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.AutoConfigureOrder; @@ -68,14 +65,14 @@ import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.ConfigurationCondition; import org.springframework.context.annotation.Import; +import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.context.annotation.Primary; -import org.springframework.context.annotation.Role; import org.springframework.core.Ordered; -import org.springframework.core.annotation.Order; import org.springframework.core.convert.converter.Converter; import org.springframework.core.convert.converter.GenericConverter; import org.springframework.core.io.Resource; import org.springframework.core.type.AnnotatedTypeMetadata; +import org.springframework.core.type.AnnotationMetadata; import org.springframework.format.Formatter; import org.springframework.format.FormatterRegistry; import org.springframework.format.datetime.DateFormatter; @@ -163,12 +160,6 @@ public class WebMvcAutoConfiguration { public static final String SKIP_PATH_EXTENSION_CONTENT_NEGOTIATION_ATTRIBUTE = PathExtensionContentNegotiationStrategy.class .getName() + ".SKIP"; - @Bean - @Role(BeanDefinition.ROLE_INFRASTRUCTURE) - public static MvcValidatorPostProcessor mvcValidatorAliasPostProcessor() { - return new MvcValidatorPostProcessor(); - } - @Bean @ConditionalOnMissingBean(HiddenHttpMethodFilter.class) public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() { @@ -185,7 +176,7 @@ public class WebMvcAutoConfiguration { // Defined as a nested config to ensure WebMvcConfigurerAdapter is not read when not // on the classpath @Configuration - @Import(EnableWebMvcConfiguration.class) + @Import({ EnableWebMvcConfiguration.class, MvcValidatorRegistrar.class }) @EnableConfigurationProperties({ WebMvcProperties.class, ResourceProperties.class }) public static class WebMvcAutoConfigurationAdapter extends WebMvcConfigurerAdapter { @@ -642,7 +633,7 @@ public class WebMvcAutoConfiguration { /** * Condition used to disable the default MVC validator registration. The - * {@link MvcValidatorPostProcessor} is used to configure the {@code mvcValidator} + * {@link MvcValidatorRegistrar} is actually used to register the {@code mvcValidator} * bean. */ static class DisableMvcValidatorCondition implements ConfigurationCondition { @@ -660,8 +651,8 @@ public class WebMvcAutoConfiguration { } /** - * {@link BeanFactoryPostProcessor} to deal with the MVC validator bean registration. - * Applies the following rules: + * {@link ImportBeanDefinitionRegistrar} to deal with the MVC validator bean + * registration. Applies the following rules: * */ - @Order(Ordered.LOWEST_PRECEDENCE) - static class MvcValidatorPostProcessor - implements BeanDefinitionRegistryPostProcessor { + static class MvcValidatorRegistrar + implements ImportBeanDefinitionRegistrar, BeanFactoryAware { private static final String JSR303_VALIDATOR_CLASS = "javax.validation.Validator"; + private BeanFactory beanFactory; + @Override - public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) - throws BeansException { - if (registry instanceof ListableBeanFactory) { - postProcess(registry, (ListableBeanFactory) registry); + public void setBeanFactory(BeanFactory beanFactory) throws BeansException { + this.beanFactory = beanFactory; + } + + @Override + public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, + BeanDefinitionRegistry registry) { + if (this.beanFactory instanceof ListableBeanFactory) { + registerOrAliasMvcValidator(registry, + (ListableBeanFactory) this.beanFactory); } } - @Override - public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) - throws BeansException { - } - - private void postProcess(BeanDefinitionRegistry registry, + private void registerOrAliasMvcValidator(BeanDefinitionRegistry registry, ListableBeanFactory beanFactory) { String[] validatorBeans = BeanFactoryUtils.beanNamesForTypeIncludingAncestors( beanFactory, Validator.class, false, false); if (validatorBeans.length == 0) { - registerMvcValidator(registry, beanFactory); + registerNewMvcValidator(registry, beanFactory); } else if (validatorBeans.length == 1) { registry.registerAlias(validatorBeans[0], "mvcValidator"); } else { if (!ObjectUtils.containsElement(validatorBeans, "mvcValidator")) { - registerMvcValidator(registry, beanFactory); + registerNewMvcValidator(registry, beanFactory); } } } - private void registerMvcValidator(BeanDefinitionRegistry registry, + private void registerNewMvcValidator(BeanDefinitionRegistry registry, ListableBeanFactory beanFactory) { RootBeanDefinition definition = new RootBeanDefinition(); definition.setBeanClass(getClass()); From 5f3d5fbec161191348c8c119f0a393fbde86a845 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Thu, 20 Apr 2017 13:31:04 -0700 Subject: [PATCH 2/2] Remove public "skip path extension" constant Remove the public constant to make it clearer that skipping path extensions is really an internal Spring Boot concern. See gh-8765 --- .../mvc/AbstractEndpointHandlerMapping.java | 8 ++++---- .../autoconfigure/web/WebMvcAutoConfiguration.java | 13 ++++--------- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/AbstractEndpointHandlerMapping.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/AbstractEndpointHandlerMapping.java index c0a218b57e0..cadbf6c48db 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/AbstractEndpointHandlerMapping.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/AbstractEndpointHandlerMapping.java @@ -29,7 +29,6 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.boot.actuate.endpoint.Endpoint; -import org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration; import org.springframework.context.ApplicationContext; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; @@ -295,12 +294,13 @@ public abstract class AbstractEndpointHandlerMapping private static final class SkipPathExtensionContentNegotiation extends HandlerInterceptorAdapter { + private static final String SKIP_ATTRIBUTE = PathExtensionContentNegotiationStrategy.class + .getName() + ".SKIP"; + @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { - request.setAttribute( - WebMvcAutoConfiguration.SKIP_PATH_EXTENSION_CONTENT_NEGOTIATION_ATTRIBUTE, - Boolean.TRUE); + request.setAttribute(SKIP_ATTRIBUTE, Boolean.TRUE); return true; } diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/WebMvcAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/WebMvcAutoConfiguration.java index 7797e39bbf2..c7f18be85fe 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/WebMvcAutoConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/WebMvcAutoConfiguration.java @@ -153,13 +153,6 @@ public class WebMvcAutoConfiguration { public static final String DEFAULT_SUFFIX = ""; - /** - * Attribute that can be added to the web request when the - * {@link PathExtensionContentNegotiationStrategy} should be be skipped. - */ - public static final String SKIP_PATH_EXTENSION_CONTENT_NEGOTIATION_ATTRIBUTE = PathExtensionContentNegotiationStrategy.class - .getName() + ".SKIP"; - @Bean @ConditionalOnMissingBean(HiddenHttpMethodFilter.class) public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() { @@ -610,6 +603,9 @@ public class WebMvcAutoConfiguration { static class OptionalPathExtensionContentNegotiationStrategy implements ContentNegotiationStrategy { + private static final String SKIP_ATTRIBUTE = PathExtensionContentNegotiationStrategy.class + .getName() + ".SKIP"; + private final ContentNegotiationStrategy delegate; OptionalPathExtensionContentNegotiationStrategy( @@ -620,8 +616,7 @@ public class WebMvcAutoConfiguration { @Override public List resolveMediaTypes(NativeWebRequest webRequest) throws HttpMediaTypeNotAcceptableException { - Object skip = webRequest.getAttribute( - SKIP_PATH_EXTENSION_CONTENT_NEGOTIATION_ATTRIBUTE, + Object skip = webRequest.getAttribute(SKIP_ATTRIBUTE, RequestAttributes.SCOPE_REQUEST); if (skip != null && Boolean.parseBoolean(skip.toString())) { return Collections.emptyList();