From 4521866dd7ed10b7e77e4da2cc428298526661e0 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Wed, 4 Jun 2025 20:20:12 +0100 Subject: [PATCH] Rework server.servlet.encoding properties to clarify when they apply Closes gh-45394 --- ...ttpMessageConvertersAutoConfiguration.java | 26 ++------- .../http/HttpMessageConvertersProperties.java | 46 ++++++++++++++++ .../autoconfigure/web/ServerProperties.java | 20 ++++++- .../HttpEncodingAutoConfiguration.java | 53 +++---------------- .../servlet/ServletEncodingProperties.java} | 39 ++++---------- .../ServletWebServerFactoryCustomizer.java | 1 + ...itional-spring-configuration-metadata.json | 51 +++++++++++++++++- ...ssageConvertersAutoConfigurationTests.java | 19 +------ .../HttpEncodingAutoConfigurationTests.java | 50 ++++------------- ...ervletWebServerFactoryCustomizerTests.java | 24 +++++++++ 10 files changed, 174 insertions(+), 155 deletions(-) create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/http/HttpMessageConvertersProperties.java rename spring-boot-project/{spring-boot/src/main/java/org/springframework/boot/web/servlet/server/Encoding.java => spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/ServletEncodingProperties.java} (76%) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/http/HttpMessageConvertersAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/http/HttpMessageConvertersAutoConfiguration.java index 0aaa539eb8..f5145eb145 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/http/HttpMessageConvertersAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/http/HttpMessageConvertersAutoConfiguration.java @@ -16,8 +16,6 @@ package org.springframework.boot.autoconfigure.http; -import org.springframework.aot.hint.RuntimeHints; -import org.springframework.aot.hint.RuntimeHintsRegistrar; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; @@ -27,19 +25,14 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplicat import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type; import org.springframework.boot.autoconfigure.condition.NoneNestedConditions; import org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration; -import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration.HttpMessageConvertersAutoConfigurationRuntimeHints; import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration.NotReactiveWebApplicationCondition; import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration; import org.springframework.boot.autoconfigure.jsonb.JsonbAutoConfiguration; -import org.springframework.boot.context.properties.bind.BindableRuntimeHintsRegistrar; -import org.springframework.boot.context.properties.bind.Binder; -import org.springframework.boot.web.servlet.server.Encoding; +import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; -import org.springframework.context.annotation.ImportRuntimeHints; -import org.springframework.core.env.Environment; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.StringHttpMessageConverter; @@ -63,7 +56,6 @@ import org.springframework.http.converter.StringHttpMessageConverter; @Conditional(NotReactiveWebApplicationCondition.class) @Import({ JacksonHttpMessageConvertersConfiguration.class, GsonHttpMessageConvertersConfiguration.class, JsonbHttpMessageConvertersConfiguration.class }) -@ImportRuntimeHints(HttpMessageConvertersAutoConfigurationRuntimeHints.class) public class HttpMessageConvertersAutoConfiguration { @Bean @@ -74,13 +66,14 @@ public class HttpMessageConvertersAutoConfiguration { @Configuration(proxyBeanMethods = false) @ConditionalOnClass(StringHttpMessageConverter.class) + @EnableConfigurationProperties(HttpMessageConvertersProperties.class) protected static class StringHttpMessageConverterConfiguration { @Bean @ConditionalOnMissingBean - public StringHttpMessageConverter stringHttpMessageConverter(Environment environment) { - Encoding encoding = Binder.get(environment).bindOrCreate("server.servlet.encoding", Encoding.class); - StringHttpMessageConverter converter = new StringHttpMessageConverter(encoding.getCharset()); + public StringHttpMessageConverter stringHttpMessageConverter(HttpMessageConvertersProperties properties) { + StringHttpMessageConverter converter = new StringHttpMessageConverter( + properties.getStringEncodingCharset()); converter.setWriteAcceptCharset(false); return converter; } @@ -100,13 +93,4 @@ public class HttpMessageConvertersAutoConfiguration { } - static class HttpMessageConvertersAutoConfigurationRuntimeHints implements RuntimeHintsRegistrar { - - @Override - public void registerHints(RuntimeHints hints, ClassLoader classLoader) { - BindableRuntimeHintsRegistrar.forTypes(Encoding.class).registerHints(hints, classLoader); - } - - } - } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/http/HttpMessageConvertersProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/http/HttpMessageConvertersProperties.java new file mode 100644 index 0000000000..8c25072e49 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/http/HttpMessageConvertersProperties.java @@ -0,0 +1,46 @@ +/* + * Copyright 2012-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.autoconfigure.http; + +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * {@link ConfigurationProperties @ConfigurationProperties} for HTTP message conversion. + * + * @author Andy Wilkinson + * @since 4.0.0 + */ +@ConfigurationProperties("spring.http.converters") +public class HttpMessageConvertersProperties { + + /** + * The charset to use for String conversion. + */ + private Charset stringEncodingCharset = StandardCharsets.UTF_8; + + public Charset getStringEncodingCharset() { + return this.stringEncodingCharset; + } + + public void setStringEncodingCharset(Charset stringEncodingCharset) { + this.stringEncodingCharset = stringEncodingCharset; + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java index 6f4276cdef..1ab0ebe7e6 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java @@ -26,6 +26,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; +import java.util.Locale; import java.util.Map; import io.undertow.UndertowOptions; @@ -40,7 +41,6 @@ import org.springframework.boot.web.server.Http2; import org.springframework.boot.web.server.MimeMappings; import org.springframework.boot.web.server.Shutdown; import org.springframework.boot.web.server.Ssl; -import org.springframework.boot.web.servlet.server.Encoding; import org.springframework.boot.web.servlet.server.Jsp; import org.springframework.boot.web.servlet.server.Session; import org.springframework.util.StringUtils; @@ -266,7 +266,6 @@ public class ServerProperties { */ private boolean registerDefaultServlet = false; - @NestedConfigurationProperty private final Encoding encoding = new Encoding(); @NestedConfigurationProperty @@ -1970,4 +1969,21 @@ public class ServerProperties { } + public static class Encoding { + + /** + * Mapping of locale to charset for response encoding. + */ + private Map mapping; + + public Map getMapping() { + return this.mapping; + } + + public void setMapping(Map mapping) { + this.mapping = mapping; + } + + } + } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/HttpEncodingAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/HttpEncodingAutoConfiguration.java index 77895ad442..30ab0fada1 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/HttpEncodingAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/HttpEncodingAutoConfiguration.java @@ -22,73 +22,34 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProp import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; -import org.springframework.boot.autoconfigure.web.ServerProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.boot.web.server.WebServerFactoryCustomizer; import org.springframework.boot.web.servlet.filter.OrderedCharacterEncodingFilter; -import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory; -import org.springframework.boot.web.servlet.server.Encoding; import org.springframework.context.annotation.Bean; -import org.springframework.core.Ordered; import org.springframework.web.filter.CharacterEncodingFilter; /** * {@link EnableAutoConfiguration Auto-configuration} for configuring the encoding to use - * in web applications. + * in Servlet web applications. * * @author Stephane Nicoll * @author Brian Clozel * @since 2.0.0 */ @AutoConfiguration -@EnableConfigurationProperties(ServerProperties.class) +@EnableConfigurationProperties(ServletEncodingProperties.class) @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET) @ConditionalOnClass(CharacterEncodingFilter.class) -@ConditionalOnBooleanProperty(name = "server.servlet.encoding.enabled", matchIfMissing = true) +@ConditionalOnBooleanProperty(name = "spring.servlet.encoding.enabled", matchIfMissing = true) public class HttpEncodingAutoConfiguration { - private final Encoding properties; - - public HttpEncodingAutoConfiguration(ServerProperties properties) { - this.properties = properties.getServlet().getEncoding(); - } - @Bean @ConditionalOnMissingBean - public CharacterEncodingFilter characterEncodingFilter() { + public CharacterEncodingFilter characterEncodingFilter(ServletEncodingProperties properties) { CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter(); - filter.setEncoding(this.properties.getCharset().name()); - filter.setForceRequestEncoding(this.properties.shouldForce(Encoding.Type.REQUEST)); - filter.setForceResponseEncoding(this.properties.shouldForce(Encoding.Type.RESPONSE)); + filter.setEncoding(properties.getCharset().name()); + filter.setForceRequestEncoding(properties.shouldForce(ServletEncodingProperties.HttpMessageType.REQUEST)); + filter.setForceResponseEncoding(properties.shouldForce(ServletEncodingProperties.HttpMessageType.RESPONSE)); return filter; } - @Bean - public LocaleCharsetMappingsCustomizer localeCharsetMappingsCustomizer() { - return new LocaleCharsetMappingsCustomizer(this.properties); - } - - static class LocaleCharsetMappingsCustomizer - implements WebServerFactoryCustomizer, Ordered { - - private final Encoding properties; - - LocaleCharsetMappingsCustomizer(Encoding properties) { - this.properties = properties; - } - - @Override - public void customize(ConfigurableServletWebServerFactory factory) { - if (this.properties.getMapping() != null) { - factory.setLocaleCharsetMappings(this.properties.getMapping()); - } - } - - @Override - public int getOrder() { - return 0; - } - - } - } diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/server/Encoding.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/ServletEncodingProperties.java similarity index 76% rename from spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/server/Encoding.java rename to spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/ServletEncodingProperties.java index 53f8b3a8c4..fc90522172 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/server/Encoding.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/ServletEncodingProperties.java @@ -14,25 +14,21 @@ * limitations under the License. */ -package org.springframework.boot.web.servlet.server; +package org.springframework.boot.autoconfigure.web.servlet; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; -import java.util.Locale; -import java.util.Map; -import org.springframework.boot.context.properties.ConfigurationPropertiesSource; +import org.springframework.boot.context.properties.ConfigurationProperties; /** - * Configuration properties for server HTTP encoding. + * {@link ConfigurationProperties @ConfigurationProperties} for Servlet encoding. * - * @author Phillip Webb - * @author Stephane Nicoll - * @author Brian Clozel - * @since 2.3.0 + * @author Andy Wilkinson + * @since 4.0.0 */ -@ConfigurationPropertiesSource -public class Encoding { +@ConfigurationProperties("spring.servlet.encoding") +public class ServletEncodingProperties { /** * Default HTTP encoding for Servlet applications. @@ -62,11 +58,6 @@ public class Encoding { */ private Boolean forceResponse; - /** - * Mapping of locale to charset for response encoding. - */ - private Map mapping; - public Charset getCharset() { return this.charset; } @@ -99,21 +90,13 @@ public class Encoding { this.forceResponse = forceResponse; } - public Map getMapping() { - return this.mapping; - } - - public void setMapping(Map mapping) { - this.mapping = mapping; - } - - public boolean shouldForce(Type type) { - Boolean force = (type != Type.REQUEST) ? this.forceResponse : this.forceRequest; + public boolean shouldForce(HttpMessageType type) { + Boolean force = (type != HttpMessageType.REQUEST) ? this.forceResponse : this.forceRequest; if (force == null) { force = this.force; } if (force == null) { - force = (type == Type.REQUEST); + force = (type == HttpMessageType.REQUEST); } return force; } @@ -121,7 +104,7 @@ public class Encoding { /** * Type of HTTP message to consider for encoding configuration. */ - public enum Type { + public enum HttpMessageType { /** * HTTP request message. diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/ServletWebServerFactoryCustomizer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/ServletWebServerFactoryCustomizer.java index bc1dbd4e24..4952b4d165 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/ServletWebServerFactoryCustomizer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/ServletWebServerFactoryCustomizer.java @@ -96,6 +96,7 @@ public class ServletWebServerFactoryCustomizer .whenNot(CollectionUtils::isEmpty) .to(factory::setCookieSameSiteSuppliers); map.from(this.serverProperties::getMimeMappings).to(factory::addMimeMappings); + map.from(this.serverProperties.getServlet().getEncoding()::getMapping).to(factory::setLocaleCharsetMappings); this.webListenerRegistrars.forEach((registrar) -> registrar.register(factory)); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json index d491a9bfa6..4359aaa9ca 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -126,11 +126,54 @@ "name": "server.reactive.session.cookie.secure", "description": "Whether to always mark the cookie as secure." }, + { + "name": "server.servlet.encoding.charset", + "type": "java.nio.charset.Charset", + "description": "Charset of HTTP requests and responses. Added to the Content-Type header if not set explicitly.", + "deprecation": { + "replacement": "spring.servlet.encoding.charset", + "level": "error" + } + }, { "name": "server.servlet.encoding.enabled", "type": "java.lang.Boolean", "description": "Whether to enable http encoding support.", - "defaultValue": true + "defaultValue": true, + "deprecation": { + "replacement": "spring.servlet.encoding.enabled", + "level": "error" + } + }, + { + "name": "server.servlet.encoding.force", + "type": "java.lang.Boolean", + "description": "Whether to force the encoding to the configured charset on HTTP requests and responses.", + "defaultValue": false, + "deprecation": { + "replacement": "spring.servlet.encoding.force", + "level": "error" + } + }, + { + "name": "server.servlet.encoding.force-request", + "type": "java.lang.Boolean", + "description": "Whether to force the encoding to the configured charset on HTTP requests. Defaults to true when force has not been specified.", + "defaultValue": true, + "deprecation": { + "replacement": "spring.servlet.encoding.force-request", + "level": "error" + } + }, + { + "name": "server.servlet.encoding.force-response", + "type": "java.lang.Boolean", + "description": "Whether to force the encoding to the configured charset on HTTP responses.", + "defaultValue": false, + "deprecation": { + "replacement": "spring.servlet.encoding.force-response", + "level": "error" + } }, { "name": "server.servlet.jsp.class-name", @@ -2525,6 +2568,12 @@ "level": "error" } }, + { + "name": "spring.servlet.encoding.enabled", + "type": "java.lang.Boolean", + "description": "Whether to enable Servlet HTTP encoding support.", + "defaultValue": true + }, { "name": "spring.session.redis.cleanup-cron", "defaultValue": "0 * * * * *" diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/http/HttpMessageConvertersAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/http/HttpMessageConvertersAutoConfigurationTests.java index 299847021d..2829f56ad6 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/http/HttpMessageConvertersAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/http/HttpMessageConvertersAutoConfigurationTests.java @@ -23,12 +23,9 @@ import com.google.gson.Gson; import jakarta.json.bind.Jsonb; import org.junit.jupiter.api.Test; -import org.springframework.aot.hint.RuntimeHints; -import org.springframework.aot.hint.predicate.RuntimeHintsPredicates; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration; -import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration.HttpMessageConvertersAutoConfigurationRuntimeHints; import org.springframework.boot.autoconfigure.http.JacksonHttpMessageConvertersConfiguration.MappingJackson2HttpMessageConverterConfiguration; import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration; import org.springframework.boot.autoconfigure.jsonb.JsonbAutoConfiguration; @@ -39,7 +36,6 @@ import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.boot.test.context.runner.ContextConsumer; import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner; import org.springframework.boot.test.context.runner.WebApplicationContextRunner; -import org.springframework.boot.web.servlet.server.Encoding; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.support.GenericApplicationContext; @@ -313,7 +309,7 @@ class HttpMessageConvertersAutoConfigurationTests { void whenEncodingCharsetIsConfiguredThenStringMessageConverterUsesSpecificCharset() { new WebApplicationContextRunner() .withConfiguration(AutoConfigurations.of(HttpMessageConvertersAutoConfiguration.class)) - .withPropertyValues("server.servlet.encoding.charset=UTF-16") + .withPropertyValues("spring.http.converters.string-encoding-charset=UTF-16") .run((context) -> { assertThat(context).hasSingleBean(StringHttpMessageConverter.class); assertThat(context.getBean(StringHttpMessageConverter.class).getDefaultCharset()) @@ -331,19 +327,6 @@ class HttpMessageConvertersAutoConfigurationTests { }); } - @Test - void shouldRegisterHints() { - RuntimeHints hints = new RuntimeHints(); - new HttpMessageConvertersAutoConfigurationRuntimeHints().registerHints(hints, getClass().getClassLoader()); - assertThat(RuntimeHintsPredicates.reflection().onType(Encoding.class)).accepts(hints); - assertThat(RuntimeHintsPredicates.reflection().onMethodInvocation(Encoding.class, "getCharset")).accepts(hints); - assertThat(RuntimeHintsPredicates.reflection().onMethodInvocation(Encoding.class, "setCharset")).accepts(hints); - assertThat(RuntimeHintsPredicates.reflection().onMethodInvocation(Encoding.class, "isForce")).accepts(hints); - assertThat(RuntimeHintsPredicates.reflection().onMethodInvocation(Encoding.class, "setForce")).accepts(hints); - assertThat(RuntimeHintsPredicates.reflection().onMethodInvocation(Encoding.class, "shouldForce")) - .rejects(hints); - } - private ApplicationContextRunner allOptionsRunner() { return this.contextRunner.withConfiguration(AutoConfigurations.of(GsonAutoConfiguration.class, JacksonAutoConfiguration.class, JsonbAutoConfiguration.class)); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/HttpEncodingAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/HttpEncodingAutoConfigurationTests.java index fe2e998b97..1fbcdd9b36 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/HttpEncodingAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/HttpEncodingAutoConfigurationTests.java @@ -16,11 +16,8 @@ package org.springframework.boot.autoconfigure.web.servlet; -import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; -import java.util.Locale; -import java.util.Map; import jakarta.servlet.Filter; import org.junit.jupiter.api.AfterEach; @@ -28,7 +25,6 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.boot.test.util.TestPropertyValues; -import org.springframework.boot.web.server.WebServerFactoryCustomizer; import org.springframework.boot.web.server.WebServerFactoryCustomizerBeanPostProcessor; import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebApplicationContext; import org.springframework.boot.web.servlet.filter.OrderedFormContentFilter; @@ -69,53 +65,53 @@ class HttpEncodingAutoConfigurationTests { @Test void disableConfiguration() { - load(EmptyConfiguration.class, "server.servlet.encoding.enabled:false"); + load(EmptyConfiguration.class, "spring.servlet.encoding.enabled:false"); assertThatExceptionOfType(NoSuchBeanDefinitionException.class) .isThrownBy(() -> this.context.getBean(CharacterEncodingFilter.class)); } @Test void customConfiguration() { - load(EmptyConfiguration.class, "server.servlet.encoding.charset:ISO-8859-15", - "server.servlet.encoding.force:false"); + load(EmptyConfiguration.class, "spring.servlet.encoding.charset:ISO-8859-15", + "spring.servlet.encoding.force:false"); CharacterEncodingFilter filter = this.context.getBean(CharacterEncodingFilter.class); assertCharacterEncodingFilter(filter, "ISO-8859-15", false, false); } @Test void customFilterConfiguration() { - load(FilterConfiguration.class, "server.servlet.encoding.charset:ISO-8859-15", - "server.servlet.encoding.force:false"); + load(FilterConfiguration.class, "spring.servlet.encoding.charset:ISO-8859-15", + "spring.servlet.encoding.force:false"); CharacterEncodingFilter filter = this.context.getBean(CharacterEncodingFilter.class); assertCharacterEncodingFilter(filter, "US-ASCII", false, false); } @Test void forceRequest() { - load(EmptyConfiguration.class, "server.servlet.encoding.force-request:false"); + load(EmptyConfiguration.class, "spring.servlet.encoding.force-request:false"); CharacterEncodingFilter filter = this.context.getBean(CharacterEncodingFilter.class); assertCharacterEncodingFilter(filter, "UTF-8", false, false); } @Test void forceResponse() { - load(EmptyConfiguration.class, "server.servlet.encoding.force-response:true"); + load(EmptyConfiguration.class, "spring.servlet.encoding.force-response:true"); CharacterEncodingFilter filter = this.context.getBean(CharacterEncodingFilter.class); assertCharacterEncodingFilter(filter, "UTF-8", true, true); } @Test void forceRequestOverridesForce() { - load(EmptyConfiguration.class, "server.servlet.encoding.force:true", - "server.servlet.encoding.force-request:false"); + load(EmptyConfiguration.class, "spring.servlet.encoding.force:true", + "spring.servlet.encoding.force-request:false"); CharacterEncodingFilter filter = this.context.getBean(CharacterEncodingFilter.class); assertCharacterEncodingFilter(filter, "UTF-8", false, true); } @Test void forceResponseOverridesForce() { - load(EmptyConfiguration.class, "server.servlet.encoding.force:true", - "server.servlet.encoding.force-response:false"); + load(EmptyConfiguration.class, "spring.servlet.encoding.force:true", + "spring.servlet.encoding.force-response:false"); CharacterEncodingFilter filter = this.context.getBean(CharacterEncodingFilter.class); assertCharacterEncodingFilter(filter, "UTF-8", true, false); } @@ -129,30 +125,6 @@ class HttpEncodingAutoConfigurationTests { assertThat(beans.get(1)).isInstanceOf(HiddenHttpMethodFilter.class); } - @Test - void noLocaleCharsetMapping() { - load(EmptyConfiguration.class); - Map> beans = getWebServerFactoryCustomizerBeans(); - assertThat(beans).hasSize(1); - assertThat(this.context.getBean(MockServletWebServerFactory.class).getLocaleCharsetMappings()).isEmpty(); - } - - @Test - void customLocaleCharsetMappings() { - load(EmptyConfiguration.class, "server.servlet.encoding.mapping.en:UTF-8", - "server.servlet.encoding.mapping.fr_FR:UTF-8"); - Map> beans = getWebServerFactoryCustomizerBeans(); - assertThat(beans).hasSize(1); - assertThat(this.context.getBean(MockServletWebServerFactory.class).getLocaleCharsetMappings()).hasSize(2) - .containsEntry(Locale.ENGLISH, StandardCharsets.UTF_8) - .containsEntry(Locale.FRANCE, StandardCharsets.UTF_8); - } - - @SuppressWarnings({ "unchecked", "rawtypes" }) - private Map> getWebServerFactoryCustomizerBeans() { - return (Map) this.context.getBeansOfType(WebServerFactoryCustomizer.class); - } - private void assertCharacterEncodingFilter(CharacterEncodingFilter actual, String encoding, boolean forceRequestEncoding, boolean forceResponseEncoding) { assertThat(actual.getEncoding()).isEqualTo(encoding); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/ServletWebServerFactoryCustomizerTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/ServletWebServerFactoryCustomizerTests.java index 73e1348c35..3a9d8843b2 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/ServletWebServerFactoryCustomizerTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/ServletWebServerFactoryCustomizerTests.java @@ -17,7 +17,9 @@ package org.springframework.boot.autoconfigure.web.servlet; import java.io.File; +import java.nio.charset.StandardCharsets; import java.util.HashMap; +import java.util.Locale; import java.util.Map; import org.junit.jupiter.api.BeforeEach; @@ -38,9 +40,11 @@ import org.springframework.boot.web.servlet.server.Jsp; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyMap; import static org.mockito.ArgumentMatchers.assertArg; import static org.mockito.BDDMockito.then; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; /** * Tests for {@link ServletWebServerFactoryCustomizer}. @@ -193,6 +197,26 @@ class ServletWebServerFactoryCustomizerTests { then(factory).should().setShutdown(assertArg((shutdown) -> assertThat(shutdown).isEqualTo(Shutdown.IMMEDIATE))); } + @Test + void noLocaleCharsetMapping() { + ConfigurableServletWebServerFactory factory = mock(ConfigurableServletWebServerFactory.class); + this.customizer.customize(factory); + then(factory).should(never()).setLocaleCharsetMappings(anyMap()); + } + + @Test + void customLocaleCharsetMappings() { + Map map = Map.of("server.servlet.encoding.mapping.en", "UTF-8", + "server.servlet.encoding.mapping.fr_FR", "UTF-8"); + bindProperties(map); + ConfigurableServletWebServerFactory factory = mock(ConfigurableServletWebServerFactory.class); + this.customizer.customize(factory); + then(factory).should() + .setLocaleCharsetMappings((assertArg((mappings) -> assertThat(mappings).hasSize(2) + .containsEntry(Locale.ENGLISH, StandardCharsets.UTF_8) + .containsEntry(Locale.FRANCE, StandardCharsets.UTF_8)))); + } + private void bindProperties(Map map) { ConfigurationPropertySource source = new MapConfigurationPropertySource(map); new Binder(source).bind("server", Bindable.ofInstance(this.properties));