Add Locale to Charset Mapping for Servlet containers
This commit adds a new configuration key:
spring.http.encoding.mapping.<locale>=<charset>
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
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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<Locale, Charset> mapping;
|
||||
|
||||
public Charset getCharset() {
|
||||
return this.charset;
|
||||
}
|
||||
@@ -85,6 +93,14 @@ public class HttpEncodingProperties {
|
||||
this.forceResponse = forceResponse;
|
||||
}
|
||||
|
||||
public Map<Locale, Charset> getMapping() {
|
||||
return this.mapping;
|
||||
}
|
||||
|
||||
public void setMapping(Map<Locale, Charset> mapping) {
|
||||
this.mapping = mapping;
|
||||
}
|
||||
|
||||
boolean shouldForce(Type type) {
|
||||
Boolean force = (type == Type.REQUEST ? this.forceRequest : this.forceResponse);
|
||||
if (force == null) {
|
||||
|
||||
@@ -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<String, EmbeddedServletContainerCustomizer> 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<String, EmbeddedServletContainerCustomizer> 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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user