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 95930db476..0e6e639b97 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 feb2db66df..22563b78f0 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 45bc254aef..ac03ec2501 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 c22785bd61..9b0e8b0175 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 cbc413761a..c3d44e351a 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 a80e3e22d6..a2600c1709 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 30e4c0b192..4117307e25 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 689bbaf880..b4059ca905 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 c275d9663f..d5371fd78b 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 f63ab4a3de..b5aefc400b 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 8695ef7099..9fa1ac466d 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 3d4532e712..1f7264c070 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; + } }