From 4a7bc3d096ebaf11905bc2229371b31b00c03212 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Fri, 20 Nov 2020 10:35:30 +0000 Subject: [PATCH] Require bean name match for Locale(Context)Resolver to back off Web MVC and WebFlux look up by name the Locale(Context)Resolver beans that they use. Previously, the auto-configured resolvers for MVC and WebFlux would back off when any bean of the required type was defined, irrespective of its name. If the name of the user's bean didn't match the name used by MVC and WebFlux to find the custom resolver, the custom resolver would be ignored and MVC and WebFlux would use their defaults. There was no indication of this happening in the condition evaluation report as all it would show is that the auto-configured resolver had backed off in favour of the custom resolver. It wouldn't show anything to explain why the custom resolver had not been used. This commit updates the auto-configured resolvers to be conditional on a missing bean of the name required by MVC and WebFlux. If the user then defines a custom resolver with a different name, the condition evaluation report will show that the auto-configured resolver remained as the bean name didn't match. Fixes gh-24209 --- .../reactive/WebFluxAutoConfiguration.java | 3 +- .../web/servlet/WebMvcAutoConfiguration.java | 2 +- .../WebFluxAutoConfigurationTests.java | 37 ++++++++++++++----- .../servlet/WebMvcAutoConfigurationTests.java | 31 ++++++++++++++++ 4 files changed, 62 insertions(+), 11 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfiguration.java index 2be93494b6..41349b5848 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfiguration.java @@ -70,6 +70,7 @@ import org.springframework.web.reactive.result.method.annotation.ArgumentResolve import org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerAdapter; import org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerMapping; import org.springframework.web.reactive.result.view.ViewResolver; +import org.springframework.web.server.adapter.WebHttpHandlerBuilder; import org.springframework.web.server.i18n.AcceptHeaderLocaleContextResolver; import org.springframework.web.server.i18n.FixedLocaleContextResolver; import org.springframework.web.server.i18n.LocaleContextResolver; @@ -289,7 +290,7 @@ public class WebFluxAutoConfiguration { @Bean @Override - @ConditionalOnMissingBean + @ConditionalOnMissingBean(name = WebHttpHandlerBuilder.LOCALE_CONTEXT_RESOLVER_BEAN_NAME) public LocaleContextResolver localeContextResolver() { if (this.webProperties.getLocaleResolver() == WebProperties.LocaleResolver.FIXED) { return new FixedLocaleContextResolver(this.webProperties.getLocale()); 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 40c8ea4fb7..c720732caa 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 @@ -441,7 +441,7 @@ public class WebMvcAutoConfiguration { @Override @Bean - @ConditionalOnMissingBean + @ConditionalOnMissingBean(name = DispatcherServlet.LOCALE_RESOLVER_BEAN_NAME) @SuppressWarnings("deprecation") public LocaleResolver localeResolver() { if (this.webProperties.getLocaleResolver() == WebProperties.LocaleResolver.FIXED) { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfigurationTests.java index 51c88e647f..421fed5cb4 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfigurationTests.java @@ -79,6 +79,7 @@ import org.springframework.web.reactive.result.method.annotation.RequestMappingH import org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerMapping; import org.springframework.web.reactive.result.view.ViewResolutionResultHandler; import org.springframework.web.reactive.result.view.ViewResolver; +import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.i18n.AcceptHeaderLocaleContextResolver; import org.springframework.web.server.i18n.FixedLocaleContextResolver; import org.springframework.web.server.i18n.LocaleContextResolver; @@ -531,10 +532,25 @@ class WebFluxAutoConfigurationTests { } @Test - void customLocaleContextResolver() { - this.contextRunner.withUserConfiguration(LocaleContextResolverConfiguration.class) - .run((context) -> assertThat(context).hasSingleBean(LocaleContextResolver.class) - .hasBean("customLocaleContextResolver")); + void customLocaleContextResolverWithMatchingNameReplacedAutoConfiguredLocaleContextResolver() { + this.contextRunner + .withBean("localeContextResolver", CustomLocaleContextResolver.class, CustomLocaleContextResolver::new) + .run((context) -> { + assertThat(context).hasSingleBean(LocaleContextResolver.class); + assertThat(context.getBean("localeContextResolver")) + .isInstanceOf(CustomLocaleContextResolver.class); + }); + } + + @Test + void customLocaleContextResolverWithDifferentNameDoesNotReplaceAutoConfiguredLocaleContextResolver() { + this.contextRunner.withBean("customLocaleContextResolver", CustomLocaleContextResolver.class, + CustomLocaleContextResolver::new).run((context) -> { + assertThat(context.getBean("customLocaleContextResolver")) + .isInstanceOf(CustomLocaleContextResolver.class); + assertThat(context.getBean("localeContextResolver")) + .isInstanceOf(AcceptHeaderLocaleContextResolver.class); + }); } private Map getHandlerMap(ApplicationContext context) { @@ -767,12 +783,15 @@ class WebFluxAutoConfigurationTests { } - @Configuration(proxyBeanMethods = false) - static class LocaleContextResolverConfiguration { + static class CustomLocaleContextResolver implements LocaleContextResolver { - @Bean - LocaleContextResolver customLocaleContextResolver() { - return new AcceptHeaderLocaleContextResolver(); + @Override + public LocaleContext resolveLocaleContext(ServerWebExchange exchange) { + return () -> Locale.ENGLISH; + } + + @Override + public void setLocaleContext(ServerWebExchange exchange, LocaleContext localeContext) { } } 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 2ebebee25d..94d2dd5944 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 @@ -344,6 +344,24 @@ class WebMvcAutoConfigurationTests { }); } + @Test + void customLocaleResolverWithMatchingNameReplacesAutoConfiguredLocaleResolver() { + this.contextRunner.withBean("localeResolver", CustomLocaleResolver.class, CustomLocaleResolver::new) + .run((context) -> { + assertThat(context).hasSingleBean(LocaleResolver.class); + assertThat(context.getBean("localeResolver")).isInstanceOf(CustomLocaleResolver.class); + }); + } + + @Test + void customLocaleResolverWithDifferentNameDoesNotReplaceAutoConfiguredLocaleResolver() { + this.contextRunner.withBean("customLocaleResolver", CustomLocaleResolver.class, CustomLocaleResolver::new) + .run((context) -> { + assertThat(context.getBean("customLocaleResolver")).isInstanceOf(CustomLocaleResolver.class); + assertThat(context.getBean("localeResolver")).isInstanceOf(AcceptHeaderLocaleResolver.class); + }); + } + @Test void defaultDateFormat() { this.contextRunner.run((context) -> { @@ -1376,4 +1394,17 @@ class WebMvcAutoConfigurationTests { } + static class CustomLocaleResolver implements LocaleResolver { + + @Override + public Locale resolveLocale(HttpServletRequest request) { + return Locale.ENGLISH; + } + + @Override + public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) { + } + + } + }