From 7f509bf84e9b51416ce65a777a3b5b2521921a6f Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Wed, 30 Oct 2019 15:47:02 +0100 Subject: [PATCH] Make sure Web infrastructure uses qualified beans MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit is a follow-up of a change in Spring Framework[1] to make sure injection points that are expecting a specific bean by name use a qualifier. As a result of this change, MVC uses the dedicated MVC validator again rather than the general one auto-configured by Spring Boot. [1] https://github.com/spring-projects/spring-framework/issues/23887 Closes gh-18672 --- .../web/servlet/WebMvcAutoConfiguration.java | 19 ++++++++++-------- .../servlet/WebMvcAutoConfigurationTests.java | 20 +++++++++++++++++-- 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration.java index 36676cc9c0..ca31a0c36a 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration.java @@ -33,6 +33,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.annotation.Qualifier; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.AutoConfigureOrder; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; @@ -362,10 +363,11 @@ public class WebMvcAutoConfiguration { @Bean @Override public RequestMappingHandlerAdapter requestMappingHandlerAdapter( - ContentNegotiationManager mvcContentNegotiationManager, - FormattingConversionService mvcConversionService, Validator mvcValidator) { - RequestMappingHandlerAdapter adapter = super.requestMappingHandlerAdapter(mvcContentNegotiationManager, - mvcConversionService, mvcValidator); + @Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager, + @Qualifier("mvcConversionService") FormattingConversionService conversionService, + @Qualifier("mvcValidator") Validator validator) { + RequestMappingHandlerAdapter adapter = super.requestMappingHandlerAdapter(contentNegotiationManager, + conversionService, validator); adapter.setIgnoreDefaultModelOnRedirect( this.mvcProperties == null || this.mvcProperties.isIgnoreDefaultModelOnRedirect()); return adapter; @@ -383,11 +385,12 @@ public class WebMvcAutoConfiguration { @Primary @Override public RequestMappingHandlerMapping requestMappingHandlerMapping( - ContentNegotiationManager mvcContentNegotiationManager, - FormattingConversionService mvcConversionService, ResourceUrlProvider mvcResourceUrlProvider) { + @Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager, + @Qualifier("mvcConversionService") FormattingConversionService conversionService, + @Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) { // Must be @Primary for MvcUriComponentsBuilder to work - return super.requestMappingHandlerMapping(mvcContentNegotiationManager, mvcConversionService, - mvcResourceUrlProvider); + return super.requestMappingHandlerMapping(contentNegotiationManager, conversionService, + resourceUrlProvider); } @Bean diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfigurationTests.java index f3458166ce..16d63d8e0e 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfigurationTests.java @@ -564,15 +564,31 @@ class WebMvcAutoConfigurationTests { } @Test - void validatorWithConfigurerShouldUseSpringValidator() { + void validatorWithConfigurerAloneShouldUseSpringValidator() { this.contextRunner.withUserConfiguration(MvcValidator.class).run((context) -> { assertThat(context).doesNotHaveBean(ValidatorFactory.class); assertThat(context).doesNotHaveBean(javax.validation.Validator.class); assertThat(context).getBeanNames(Validator.class).containsOnly("mvcValidator"); - assertThat(context.getBean("mvcValidator")).isSameAs(context.getBean(MvcValidator.class).validator); + Validator expectedValidator = context.getBean(MvcValidator.class).validator; + assertThat(context.getBean("mvcValidator")).isSameAs(expectedValidator); + assertThat(context.getBean(RequestMappingHandlerAdapter.class).getWebBindingInitializer()) + .hasFieldOrPropertyWithValue("validator", expectedValidator); }); } + @Test + void validatorWithConfigurerShouldUseSpringValidator() { + this.contextRunner.withConfiguration(AutoConfigurations.of(ValidationAutoConfiguration.class)) + .withUserConfiguration(MvcValidator.class).run((context) -> { + assertThat(context).getBeanNames(javax.validation.Validator.class).containsOnly("defaultValidator"); + assertThat(context).getBeanNames(Validator.class).containsOnly("defaultValidator", "mvcValidator"); + Validator expectedValidator = context.getBean(MvcValidator.class).validator; + assertThat(context.getBean("mvcValidator")).isSameAs(expectedValidator); + assertThat(context.getBean(RequestMappingHandlerAdapter.class).getWebBindingInitializer()) + .hasFieldOrPropertyWithValue("validator", expectedValidator); + }); + } + @Test void validatorWithConfigurerDoesNotExposeJsr303() { this.contextRunner.withUserConfiguration(MvcJsr303Validator.class).run((context) -> {