From a282710fc96cf33ec519cb85342ac67fba6abaae Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Tue, 26 Jul 2016 12:00:14 +0200 Subject: [PATCH] Add Locale to Charset Mapping for Servlet containers This commit adds a new configuration key: spring.http.encoding.mapping.= This allows to specify which default charset should be used for any given Locale, if none has been provided already in the response itself. This applies to all supported embedded servlet containers. Fixes gh-6453 --- .../web/HttpEncodingAutoConfiguration.java | 32 ++++++++++ .../web/HttpEncodingProperties.java | 16 +++++ .../HttpEncodingAutoConfigurationTests.java | 59 +++++++++++++++++-- ...tConfigurableEmbeddedServletContainer.java | 20 +++++++ .../ConfigurableEmbeddedServletContainer.java | 10 ++++ .../JettyEmbeddedServletContainerFactory.java | 5 ++ ...TomcatEmbeddedServletContainerFactory.java | 10 ++++ ...dertowEmbeddedServletContainerFactory.java | 5 ++ ...tEmbeddedServletContainerFactoryTests.java | 15 +++++ ...yEmbeddedServletContainerFactoryTests.java | 9 +++ ...tEmbeddedServletContainerFactoryTests.java | 20 +++++++ ...wEmbeddedServletContainerFactoryTests.java | 9 +++ 12 files changed, 205 insertions(+), 5 deletions(-) diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/HttpEncodingAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/HttpEncodingAutoConfiguration.java index 95930db476b..0e6e639b971 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/HttpEncodingAutoConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/HttpEncodingAutoConfiguration.java @@ -20,11 +20,15 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.boot.autoconfigure.web.HttpEncodingProperties.Type; +import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer; +import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.web.filter.OrderedCharacterEncodingFilter; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.core.Ordered; import org.springframework.web.filter.CharacterEncodingFilter; /** @@ -32,10 +36,12 @@ import org.springframework.web.filter.CharacterEncodingFilter; * in web applications. * * @author Stephane Nicoll + * @author Brian Clozel * @since 1.2.0 */ @Configuration @EnableConfigurationProperties(HttpEncodingProperties.class) +@ConditionalOnWebApplication @ConditionalOnClass(CharacterEncodingFilter.class) @ConditionalOnProperty(prefix = "spring.http.encoding", value = "enabled", matchIfMissing = true) public class HttpEncodingAutoConfiguration { @@ -56,4 +62,30 @@ public class HttpEncodingAutoConfiguration { return filter; } + @Bean + public LocaleCharsetMappingsCustomizer localeCharsetMappingsCustomizer() { + return new LocaleCharsetMappingsCustomizer(this.properties); + } + + private static class LocaleCharsetMappingsCustomizer implements EmbeddedServletContainerCustomizer, Ordered { + + private final HttpEncodingProperties properties; + + LocaleCharsetMappingsCustomizer(HttpEncodingProperties properties) { + this.properties = properties; + } + + @Override + public void customize(ConfigurableEmbeddedServletContainer container) { + if (this.properties.getMapping() != null) { + container.setLocaleCharsetMappings(this.properties.getMapping()); + } + } + + @Override + public int getOrder() { + return 0; + } + } + } diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/HttpEncodingProperties.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/HttpEncodingProperties.java index feb2db66df3..22563b78f05 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/HttpEncodingProperties.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/HttpEncodingProperties.java @@ -17,6 +17,8 @@ package org.springframework.boot.autoconfigure.web; import java.nio.charset.Charset; +import java.util.Locale; +import java.util.Map; import org.springframework.boot.context.properties.ConfigurationProperties; @@ -24,6 +26,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties; * Configuration properties for http encoding. * * @author Stephane Nicoll + * @author Brian Clozel * @since 1.2.0 */ @ConfigurationProperties(prefix = "spring.http.encoding") @@ -53,6 +56,11 @@ public class HttpEncodingProperties { */ private Boolean forceResponse; + /** + * Locale to Encoding mapping. + */ + private Map mapping; + public Charset getCharset() { return this.charset; } @@ -85,6 +93,14 @@ public class HttpEncodingProperties { this.forceResponse = forceResponse; } + public Map getMapping() { + return this.mapping; + } + + public void setMapping(Map mapping) { + this.mapping = mapping; + } + boolean shouldForce(Type type) { Boolean force = (type == Type.REQUEST ? this.forceRequest : this.forceResponse); if (force == null) { diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/HttpEncodingAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/HttpEncodingAutoConfigurationTests.java index 45bc254aefc..ac03ec2501c 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/HttpEncodingAutoConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/HttpEncodingAutoConfigurationTests.java @@ -16,8 +16,11 @@ package org.springframework.boot.autoconfigure.web; +import java.nio.charset.Charset; import java.util.ArrayList; import java.util.List; +import java.util.Locale; +import java.util.Map; import javax.servlet.Filter; @@ -27,13 +30,17 @@ import org.junit.Test; import org.junit.rules.ExpectedException; import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer; +import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizerBeanPostProcessor; +import org.springframework.boot.context.embedded.MockEmbeddedServletContainerFactory; import org.springframework.boot.test.util.EnvironmentTestUtils; import org.springframework.boot.web.filter.OrderedHiddenHttpMethodFilter; import org.springframework.boot.web.filter.OrderedHttpPutFormContentFilter; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.annotation.AnnotationAwareOrderComparator; +import org.springframework.mock.web.MockServletContext; +import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; import org.springframework.web.filter.CharacterEncodingFilter; import org.springframework.web.filter.HiddenHttpMethodFilter; @@ -49,7 +56,7 @@ public class HttpEncodingAutoConfigurationTests { @Rule public final ExpectedException thrown = ExpectedException.none(); - private AnnotationConfigApplicationContext context; + private AnnotationConfigWebApplicationContext context; @After public void close() { @@ -135,6 +142,31 @@ public class HttpEncodingAutoConfigurationTests { assertThat(beans.get(1)).isInstanceOf(HiddenHttpMethodFilter.class); } + @Test + public void noLocaleCharsetMapping() { + load(EmptyConfiguration.class); + Map beans = + this.context.getBeansOfType(EmbeddedServletContainerCustomizer.class); + assertThat(beans.size()).isEqualTo(1); + assertThat(this.context.getBean(MockEmbeddedServletContainerFactory.class) + .getLocaleCharsetMappings().size()).isEqualTo(0); + } + + @Test + public void customLocaleCharsetMappings() { + load(EmptyConfiguration.class, "spring.http.encoding.mapping.en:UTF-8", + "spring.http.encoding.mapping.fr_FR:UTF-8"); + Map beans = + this.context.getBeansOfType(EmbeddedServletContainerCustomizer.class); + assertThat(beans.size()).isEqualTo(1); + assertThat(this.context.getBean(MockEmbeddedServletContainerFactory.class) + .getLocaleCharsetMappings().size()).isEqualTo(2); + assertThat(this.context.getBean(MockEmbeddedServletContainerFactory.class) + .getLocaleCharsetMappings().get(Locale.ENGLISH)).isEqualTo(Charset.forName("UTF-8")); + assertThat(this.context.getBean(MockEmbeddedServletContainerFactory.class) + .getLocaleCharsetMappings().get(Locale.FRANCE)).isEqualTo(Charset.forName("UTF-8")); + } + private void assertCharacterEncodingFilter(CharacterEncodingFilter actual, String encoding, boolean forceRequestEncoding, boolean forceResponseEncoding) { @@ -147,12 +179,14 @@ public class HttpEncodingAutoConfigurationTests { this.context = doLoad(new Class[] { config }, environment); } - private AnnotationConfigApplicationContext doLoad(Class[] configs, + private AnnotationConfigWebApplicationContext doLoad(Class[] configs, String... environment) { - AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(); + AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext(); EnvironmentTestUtils.addEnvironment(applicationContext, environment); applicationContext.register(configs); - applicationContext.register(HttpEncodingAutoConfiguration.class); + applicationContext.register(MinimalWebAutoConfiguration.class, + HttpEncodingAutoConfiguration.class); + applicationContext.setServletContext(new MockServletContext()); applicationContext.refresh(); return applicationContext; } @@ -190,4 +224,19 @@ public class HttpEncodingAutoConfigurationTests { } + @Configuration + static class MinimalWebAutoConfiguration { + + @Bean + public MockEmbeddedServletContainerFactory mockEmbeddedServletContainerFactory() { + return new MockEmbeddedServletContainerFactory(); + } + + @Bean + public EmbeddedServletContainerCustomizerBeanPostProcessor + embeddedServletContainerCustomizerBeanPostProcessor() { + return new EmbeddedServletContainerCustomizerBeanPostProcessor(); + } + } + } diff --git a/spring-boot/src/main/java/org/springframework/boot/context/embedded/AbstractConfigurableEmbeddedServletContainer.java b/spring-boot/src/main/java/org/springframework/boot/context/embedded/AbstractConfigurableEmbeddedServletContainer.java index c22785bd617..9b0e8b01758 100644 --- a/spring-boot/src/main/java/org/springframework/boot/context/embedded/AbstractConfigurableEmbeddedServletContainer.java +++ b/spring-boot/src/main/java/org/springframework/boot/context/embedded/AbstractConfigurableEmbeddedServletContainer.java @@ -18,10 +18,14 @@ package org.springframework.boot.context.embedded; import java.io.File; import java.net.InetAddress; +import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; import java.util.LinkedHashSet; import java.util.List; +import java.util.Locale; +import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; @@ -39,6 +43,7 @@ import org.springframework.util.ClassUtils; * @author Stephane Nicoll * @author Ivan Sopov * @author Eddú Meléndez + * @author Brian Clozel * @see AbstractEmbeddedServletContainerFactory */ public abstract class AbstractConfigurableEmbeddedServletContainer @@ -81,6 +86,8 @@ public abstract class AbstractConfigurableEmbeddedServletContainer private String serverHeader; + private Map localeCharsetMappings = new HashMap(); + /** * Create a new {@link AbstractConfigurableEmbeddedServletContainer} instance. */ @@ -327,6 +334,19 @@ public abstract class AbstractConfigurableEmbeddedServletContainer this.serverHeader = serverHeader; } + /** + * Return the Locale to Charset mappings. + * @return the charset mappings + */ + public Map getLocaleCharsetMappings() { + return this.localeCharsetMappings; + } + + public void setLocaleCharsetMappings(Map localeCharsetMappings) { + Assert.notNull(localeCharsetMappings, "localeCharsetMappings must not be null"); + this.localeCharsetMappings = localeCharsetMappings; + } + /** * Utility method that can be used by subclasses wishing to combine the specified * {@link ServletContextInitializer} parameters with those defined in this instance. diff --git a/spring-boot/src/main/java/org/springframework/boot/context/embedded/ConfigurableEmbeddedServletContainer.java b/spring-boot/src/main/java/org/springframework/boot/context/embedded/ConfigurableEmbeddedServletContainer.java index cbc413761ac..c3d44e351a6 100644 --- a/spring-boot/src/main/java/org/springframework/boot/context/embedded/ConfigurableEmbeddedServletContainer.java +++ b/spring-boot/src/main/java/org/springframework/boot/context/embedded/ConfigurableEmbeddedServletContainer.java @@ -18,7 +18,10 @@ package org.springframework.boot.context.embedded; import java.io.File; import java.net.InetAddress; +import java.nio.charset.Charset; import java.util.List; +import java.util.Locale; +import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; @@ -34,6 +37,7 @@ import org.springframework.boot.web.servlet.ServletContextInitializer; * @author Andy Wilkinson * @author Stephane Nicoll * @author Eddú Meléndez + * @author Brian Clozel * @see EmbeddedServletContainerFactory * @see EmbeddedServletContainerCustomizer */ @@ -174,4 +178,10 @@ public interface ConfigurableEmbeddedServletContainer extends ErrorPageRegistry */ void setServerHeader(String serverHeader); + /** + * Sets the Locale to Charset mappings. + * @param localeCharsetMappings the Locale to Charset mappings + */ + void setLocaleCharsetMappings(Map localeCharsetMappings); + } diff --git a/spring-boot/src/main/java/org/springframework/boot/context/embedded/jetty/JettyEmbeddedServletContainerFactory.java b/spring-boot/src/main/java/org/springframework/boot/context/embedded/jetty/JettyEmbeddedServletContainerFactory.java index a80e3e22d6e..a2600c17092 100644 --- a/spring-boot/src/main/java/org/springframework/boot/context/embedded/jetty/JettyEmbeddedServletContainerFactory.java +++ b/spring-boot/src/main/java/org/springframework/boot/context/embedded/jetty/JettyEmbeddedServletContainerFactory.java @@ -25,6 +25,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.HashSet; import java.util.List; +import java.util.Locale; import java.util.Set; import javax.servlet.ServletException; @@ -354,6 +355,10 @@ public class JettyEmbeddedServletContainerFactory addJspServlet(context); context.addBean(new JasperInitializer(context), true); } + for (Locale locale : getLocaleCharsetMappings().keySet()) { + context.addLocaleEncoding(locale.toString(), + getLocaleCharsetMappings().get(locale).toString()); + } ServletContextInitializer[] initializersToUse = mergeInitializers(initializers); Configuration[] configurations = getWebAppContextConfigurations(context, initializersToUse); diff --git a/spring-boot/src/main/java/org/springframework/boot/context/embedded/tomcat/TomcatEmbeddedServletContainerFactory.java b/spring-boot/src/main/java/org/springframework/boot/context/embedded/tomcat/TomcatEmbeddedServletContainerFactory.java index 30e4c0b1921..4117307e259 100644 --- a/spring-boot/src/main/java/org/springframework/boot/context/embedded/tomcat/TomcatEmbeddedServletContainerFactory.java +++ b/spring-boot/src/main/java/org/springframework/boot/context/embedded/tomcat/TomcatEmbeddedServletContainerFactory.java @@ -26,6 +26,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Locale; import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.TimeUnit; @@ -193,6 +194,15 @@ public class TomcatEmbeddedServletContainerFactory context.setParentClassLoader( this.resourceLoader != null ? this.resourceLoader.getClassLoader() : ClassUtils.getDefaultClassLoader()); + // override defaults, see org.apache.catalina.util.CharsetMapperDefault.properties + context.addLocaleEncodingMappingParameter(Locale.ENGLISH.toString(), + DEFAULT_CHARSET.displayName()); + context.addLocaleEncodingMappingParameter(Locale.FRENCH.toString(), + DEFAULT_CHARSET.displayName()); + for (Locale locale : getLocaleCharsetMappings().keySet()) { + context.addLocaleEncodingMappingParameter(locale.toString(), + getLocaleCharsetMappings().get(locale).toString()); + } try { context.setUseRelativeRedirects(false); } diff --git a/spring-boot/src/main/java/org/springframework/boot/context/embedded/undertow/UndertowEmbeddedServletContainerFactory.java b/spring-boot/src/main/java/org/springframework/boot/context/embedded/undertow/UndertowEmbeddedServletContainerFactory.java index 689bbaf880b..b4059ca9059 100644 --- a/spring-boot/src/main/java/org/springframework/boot/context/embedded/undertow/UndertowEmbeddedServletContainerFactory.java +++ b/spring-boot/src/main/java/org/springframework/boot/context/embedded/undertow/UndertowEmbeddedServletContainerFactory.java @@ -27,6 +27,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Locale; import java.util.Set; import javax.net.ssl.KeyManager; @@ -382,6 +383,10 @@ public class UndertowEmbeddedServletContainerFactory File dir = getValidSessionStoreDir(); deployment.setSessionPersistenceManager(new FileSessionPersistence(dir)); } + for (Locale locale : getLocaleCharsetMappings().keySet()) { + deployment.addLocaleCharsetMapping(locale.toString(), + getLocaleCharsetMappings().get(locale).toString()); + } DeploymentManager manager = Servlets.newContainer().addDeployment(deployment); manager.deploy(); SessionManager sessionManager = manager.getDeployment().getSessionManager(); diff --git a/spring-boot/src/test/java/org/springframework/boot/context/embedded/AbstractEmbeddedServletContainerFactoryTests.java b/spring-boot/src/test/java/org/springframework/boot/context/embedded/AbstractEmbeddedServletContainerFactoryTests.java index c275d9663f0..d5371fd78bf 100644 --- a/spring-boot/src/test/java/org/springframework/boot/context/embedded/AbstractEmbeddedServletContainerFactoryTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/context/embedded/AbstractEmbeddedServletContainerFactoryTests.java @@ -38,6 +38,8 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Date; +import java.util.HashMap; +import java.util.Locale; import java.util.Map; import java.util.Map.Entry; import java.util.Set; @@ -870,6 +872,17 @@ public abstract class AbstractEmbeddedServletContainerFactoryTests { }); } + @Test + public void localeCharsetMappingsAreConfigured() throws Exception { + AbstractEmbeddedServletContainerFactory factory = getFactory(); + Map mappings = new HashMap(); + mappings.put(Locale.GERMAN, Charset.forName("UTF-8")); + factory.setLocaleCharsetMappings(mappings); + this.container = factory.getEmbeddedServletContainer(); + assertThat(getCharset(Locale.GERMAN).toString()).isEqualTo("UTF-8"); + assertThat(getCharset(Locale.ITALIAN)).isNull(); + } + protected abstract void addConnector(int port, AbstractEmbeddedServletContainerFactory factory); @@ -917,6 +930,8 @@ public abstract class AbstractEmbeddedServletContainerFactoryTests { return MimeMappings.DEFAULT.getAll(); } + protected abstract Charset getCharset(Locale locale); + private void addTestTxtFile(AbstractEmbeddedServletContainerFactory factory) throws IOException { FileCopyUtils.copy("test", diff --git a/spring-boot/src/test/java/org/springframework/boot/context/embedded/jetty/JettyEmbeddedServletContainerFactoryTests.java b/spring-boot/src/test/java/org/springframework/boot/context/embedded/jetty/JettyEmbeddedServletContainerFactoryTests.java index f63ab4a3def..b5aefc400bb 100644 --- a/spring-boot/src/test/java/org/springframework/boot/context/embedded/jetty/JettyEmbeddedServletContainerFactoryTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/context/embedded/jetty/JettyEmbeddedServletContainerFactoryTests.java @@ -17,8 +17,10 @@ package org.springframework.boot.context.embedded.jetty; import java.io.IOException; +import java.nio.charset.Charset; import java.util.Arrays; import java.util.HashMap; +import java.util.Locale; import java.util.Map; import java.util.concurrent.TimeUnit; @@ -326,4 +328,11 @@ public class JettyEmbeddedServletContainerFactoryTests return context.getMimeTypes().getMimeMap(); } + @Override + protected Charset getCharset(Locale locale) { + WebAppContext context = (WebAppContext) ((JettyEmbeddedServletContainer) this.container) + .getServer().getHandler(); + String charsetName = context.getLocaleEncoding(locale); + return (charsetName != null) ? Charset.forName(charsetName) : null; + } } diff --git a/spring-boot/src/test/java/org/springframework/boot/context/embedded/tomcat/TomcatEmbeddedServletContainerFactoryTests.java b/spring-boot/src/test/java/org/springframework/boot/context/embedded/tomcat/TomcatEmbeddedServletContainerFactoryTests.java index 8695ef70993..9fa1ac466d1 100644 --- a/spring-boot/src/test/java/org/springframework/boot/context/embedded/tomcat/TomcatEmbeddedServletContainerFactoryTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/context/embedded/tomcat/TomcatEmbeddedServletContainerFactoryTests.java @@ -21,6 +21,7 @@ import java.io.IOException; import java.nio.charset.Charset; import java.util.Arrays; import java.util.HashMap; +import java.util.Locale; import java.util.Map; import java.util.concurrent.TimeUnit; @@ -37,6 +38,7 @@ import org.apache.catalina.Valve; import org.apache.catalina.Wrapper; import org.apache.catalina.connector.Connector; import org.apache.catalina.startup.Tomcat; +import org.apache.catalina.util.CharsetMapper; import org.apache.catalina.valves.RemoteIpValve; import org.apache.tomcat.util.net.SSLHostConfig; import org.junit.After; @@ -430,6 +432,15 @@ public class TomcatEmbeddedServletContainerFactoryTests new InitialContext().lookup("java:comp/env"); } + @Test + public void defaultLocaleCharsetMappingsAreOverriden() throws Exception { + TomcatEmbeddedServletContainerFactory factory = getFactory(); + this.container = factory.getEmbeddedServletContainer(); + // override defaults, see org.apache.catalina.util.CharsetMapperDefault.properties + assertThat(getCharset(Locale.ENGLISH).toString()).isEqualTo("UTF-8"); + assertThat(getCharset(Locale.FRENCH).toString()).isEqualTo("UTF-8"); + } + @Override protected Wrapper getJspServlet() { Container context = ((TomcatEmbeddedServletContainer) this.container).getTomcat() @@ -446,6 +457,15 @@ public class TomcatEmbeddedServletContainerFactoryTests "mimeMappings"); } + @Override + protected Charset getCharset(Locale locale) { + Context context = (Context) ((TomcatEmbeddedServletContainer) this.container) + .getTomcat().getHost().findChildren()[0]; + CharsetMapper mapper = ((TomcatEmbeddedContext) context).getCharsetMapper(); + String charsetName = mapper.getCharset(locale); + return (charsetName != null) ? Charset.forName(charsetName) : null; + } + private void assertTimeout(TomcatEmbeddedServletContainerFactory factory, int expected) { Tomcat tomcat = getTomcat(factory); diff --git a/spring-boot/src/test/java/org/springframework/boot/context/embedded/undertow/UndertowEmbeddedServletContainerFactoryTests.java b/spring-boot/src/test/java/org/springframework/boot/context/embedded/undertow/UndertowEmbeddedServletContainerFactoryTests.java index 3d4532e7120..1f7264c070b 100644 --- a/spring-boot/src/test/java/org/springframework/boot/context/embedded/undertow/UndertowEmbeddedServletContainerFactoryTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/context/embedded/undertow/UndertowEmbeddedServletContainerFactoryTests.java @@ -19,9 +19,11 @@ package org.springframework.boot.context.embedded.undertow; import java.io.File; import java.io.IOException; import java.net.URISyntaxException; +import java.nio.charset.Charset; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; +import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.concurrent.atomic.AtomicReference; @@ -268,4 +270,11 @@ public class UndertowEmbeddedServletContainerFactoryTests return expectedMappings; } + @Override + protected Charset getCharset(Locale locale) { + DeploymentInfo info = ((DeploymentManager) ReflectionTestUtils + .getField(this.container, "manager")).getDeployment().getDeploymentInfo(); + String charsetName = info.getLocaleCharsetMapping().get(locale.toString()); + return (charsetName != null) ? Charset.forName(charsetName) : null; + } }