Skip to content

Commit 4521866

Browse files
committed
Rework server.servlet.encoding properties to clarify when they apply
Closes gh-45394
1 parent e225353 commit 4521866

File tree

10 files changed

+174
-155
lines changed

10 files changed

+174
-155
lines changed

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/http/HttpMessageConvertersAutoConfiguration.java

Lines changed: 5 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@
1616

1717
package org.springframework.boot.autoconfigure.http;
1818

19-
import org.springframework.aot.hint.RuntimeHints;
20-
import org.springframework.aot.hint.RuntimeHintsRegistrar;
2119
import org.springframework.beans.factory.ObjectProvider;
2220
import org.springframework.boot.autoconfigure.AutoConfiguration;
2321
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
@@ -27,19 +25,14 @@
2725
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
2826
import org.springframework.boot.autoconfigure.condition.NoneNestedConditions;
2927
import org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration;
30-
import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration.HttpMessageConvertersAutoConfigurationRuntimeHints;
3128
import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration.NotReactiveWebApplicationCondition;
3229
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
3330
import org.springframework.boot.autoconfigure.jsonb.JsonbAutoConfiguration;
34-
import org.springframework.boot.context.properties.bind.BindableRuntimeHintsRegistrar;
35-
import org.springframework.boot.context.properties.bind.Binder;
36-
import org.springframework.boot.web.servlet.server.Encoding;
31+
import org.springframework.boot.context.properties.EnableConfigurationProperties;
3732
import org.springframework.context.annotation.Bean;
3833
import org.springframework.context.annotation.Conditional;
3934
import org.springframework.context.annotation.Configuration;
4035
import org.springframework.context.annotation.Import;
41-
import org.springframework.context.annotation.ImportRuntimeHints;
42-
import org.springframework.core.env.Environment;
4336
import org.springframework.http.converter.HttpMessageConverter;
4437
import org.springframework.http.converter.StringHttpMessageConverter;
4538

@@ -63,7 +56,6 @@
6356
@Conditional(NotReactiveWebApplicationCondition.class)
6457
@Import({ JacksonHttpMessageConvertersConfiguration.class, GsonHttpMessageConvertersConfiguration.class,
6558
JsonbHttpMessageConvertersConfiguration.class })
66-
@ImportRuntimeHints(HttpMessageConvertersAutoConfigurationRuntimeHints.class)
6759
public class HttpMessageConvertersAutoConfiguration {
6860

6961
@Bean
@@ -74,13 +66,14 @@ public HttpMessageConverters messageConverters(ObjectProvider<HttpMessageConvert
7466

7567
@Configuration(proxyBeanMethods = false)
7668
@ConditionalOnClass(StringHttpMessageConverter.class)
69+
@EnableConfigurationProperties(HttpMessageConvertersProperties.class)
7770
protected static class StringHttpMessageConverterConfiguration {
7871

7972
@Bean
8073
@ConditionalOnMissingBean
81-
public StringHttpMessageConverter stringHttpMessageConverter(Environment environment) {
82-
Encoding encoding = Binder.get(environment).bindOrCreate("server.servlet.encoding", Encoding.class);
83-
StringHttpMessageConverter converter = new StringHttpMessageConverter(encoding.getCharset());
74+
public StringHttpMessageConverter stringHttpMessageConverter(HttpMessageConvertersProperties properties) {
75+
StringHttpMessageConverter converter = new StringHttpMessageConverter(
76+
properties.getStringEncodingCharset());
8477
converter.setWriteAcceptCharset(false);
8578
return converter;
8679
}
@@ -100,13 +93,4 @@ private static final class ReactiveWebApplication {
10093

10194
}
10295

103-
static class HttpMessageConvertersAutoConfigurationRuntimeHints implements RuntimeHintsRegistrar {
104-
105-
@Override
106-
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
107-
BindableRuntimeHintsRegistrar.forTypes(Encoding.class).registerHints(hints, classLoader);
108-
}
109-
110-
}
111-
11296
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright 2012-2025 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.autoconfigure.http;
18+
19+
import java.nio.charset.Charset;
20+
import java.nio.charset.StandardCharsets;
21+
22+
import org.springframework.boot.context.properties.ConfigurationProperties;
23+
24+
/**
25+
* {@link ConfigurationProperties @ConfigurationProperties} for HTTP message conversion.
26+
*
27+
* @author Andy Wilkinson
28+
* @since 4.0.0
29+
*/
30+
@ConfigurationProperties("spring.http.converters")
31+
public class HttpMessageConvertersProperties {
32+
33+
/**
34+
* The charset to use for String conversion.
35+
*/
36+
private Charset stringEncodingCharset = StandardCharsets.UTF_8;
37+
38+
public Charset getStringEncodingCharset() {
39+
return this.stringEncodingCharset;
40+
}
41+
42+
public void setStringEncodingCharset(Charset stringEncodingCharset) {
43+
this.stringEncodingCharset = stringEncodingCharset;
44+
}
45+
46+
}

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import java.util.HashMap;
2727
import java.util.LinkedHashMap;
2828
import java.util.List;
29+
import java.util.Locale;
2930
import java.util.Map;
3031

3132
import io.undertow.UndertowOptions;
@@ -40,7 +41,6 @@
4041
import org.springframework.boot.web.server.MimeMappings;
4142
import org.springframework.boot.web.server.Shutdown;
4243
import org.springframework.boot.web.server.Ssl;
43-
import org.springframework.boot.web.servlet.server.Encoding;
4444
import org.springframework.boot.web.servlet.server.Jsp;
4545
import org.springframework.boot.web.servlet.server.Session;
4646
import org.springframework.util.StringUtils;
@@ -266,7 +266,6 @@ public static class Servlet {
266266
*/
267267
private boolean registerDefaultServlet = false;
268268

269-
@NestedConfigurationProperty
270269
private final Encoding encoding = new Encoding();
271270

272271
@NestedConfigurationProperty
@@ -1970,4 +1969,21 @@ public enum ForwardHeadersStrategy {
19701969

19711970
}
19721971

1972+
public static class Encoding {
1973+
1974+
/**
1975+
* Mapping of locale to charset for response encoding.
1976+
*/
1977+
private Map<Locale, Charset> mapping;
1978+
1979+
public Map<Locale, Charset> getMapping() {
1980+
return this.mapping;
1981+
}
1982+
1983+
public void setMapping(Map<Locale, Charset> mapping) {
1984+
this.mapping = mapping;
1985+
}
1986+
1987+
}
1988+
19731989
}

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/HttpEncodingAutoConfiguration.java

Lines changed: 7 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -22,73 +22,34 @@
2222
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
2323
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
2424
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
25-
import org.springframework.boot.autoconfigure.web.ServerProperties;
2625
import org.springframework.boot.context.properties.EnableConfigurationProperties;
27-
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
2826
import org.springframework.boot.web.servlet.filter.OrderedCharacterEncodingFilter;
29-
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
30-
import org.springframework.boot.web.servlet.server.Encoding;
3127
import org.springframework.context.annotation.Bean;
32-
import org.springframework.core.Ordered;
3328
import org.springframework.web.filter.CharacterEncodingFilter;
3429

3530
/**
3631
* {@link EnableAutoConfiguration Auto-configuration} for configuring the encoding to use
37-
* in web applications.
32+
* in Servlet web applications.
3833
*
3934
* @author Stephane Nicoll
4035
* @author Brian Clozel
4136
* @since 2.0.0
4237
*/
4338
@AutoConfiguration
44-
@EnableConfigurationProperties(ServerProperties.class)
39+
@EnableConfigurationProperties(ServletEncodingProperties.class)
4540
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
4641
@ConditionalOnClass(CharacterEncodingFilter.class)
47-
@ConditionalOnBooleanProperty(name = "server.servlet.encoding.enabled", matchIfMissing = true)
42+
@ConditionalOnBooleanProperty(name = "spring.servlet.encoding.enabled", matchIfMissing = true)
4843
public class HttpEncodingAutoConfiguration {
4944

50-
private final Encoding properties;
51-
52-
public HttpEncodingAutoConfiguration(ServerProperties properties) {
53-
this.properties = properties.getServlet().getEncoding();
54-
}
55-
5645
@Bean
5746
@ConditionalOnMissingBean
58-
public CharacterEncodingFilter characterEncodingFilter() {
47+
public CharacterEncodingFilter characterEncodingFilter(ServletEncodingProperties properties) {
5948
CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
60-
filter.setEncoding(this.properties.getCharset().name());
61-
filter.setForceRequestEncoding(this.properties.shouldForce(Encoding.Type.REQUEST));
62-
filter.setForceResponseEncoding(this.properties.shouldForce(Encoding.Type.RESPONSE));
49+
filter.setEncoding(properties.getCharset().name());
50+
filter.setForceRequestEncoding(properties.shouldForce(ServletEncodingProperties.HttpMessageType.REQUEST));
51+
filter.setForceResponseEncoding(properties.shouldForce(ServletEncodingProperties.HttpMessageType.RESPONSE));
6352
return filter;
6453
}
6554

66-
@Bean
67-
public LocaleCharsetMappingsCustomizer localeCharsetMappingsCustomizer() {
68-
return new LocaleCharsetMappingsCustomizer(this.properties);
69-
}
70-
71-
static class LocaleCharsetMappingsCustomizer
72-
implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory>, Ordered {
73-
74-
private final Encoding properties;
75-
76-
LocaleCharsetMappingsCustomizer(Encoding properties) {
77-
this.properties = properties;
78-
}
79-
80-
@Override
81-
public void customize(ConfigurableServletWebServerFactory factory) {
82-
if (this.properties.getMapping() != null) {
83-
factory.setLocaleCharsetMappings(this.properties.getMapping());
84-
}
85-
}
86-
87-
@Override
88-
public int getOrder() {
89-
return 0;
90-
}
91-
92-
}
93-
9455
}

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/servlet/server/Encoding.java renamed to spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/ServletEncodingProperties.java

Lines changed: 11 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -14,25 +14,21 @@
1414
* limitations under the License.
1515
*/
1616

17-
package org.springframework.boot.web.servlet.server;
17+
package org.springframework.boot.autoconfigure.web.servlet;
1818

1919
import java.nio.charset.Charset;
2020
import java.nio.charset.StandardCharsets;
21-
import java.util.Locale;
22-
import java.util.Map;
2321

24-
import org.springframework.boot.context.properties.ConfigurationPropertiesSource;
22+
import org.springframework.boot.context.properties.ConfigurationProperties;
2523

2624
/**
27-
* Configuration properties for server HTTP encoding.
25+
* {@link ConfigurationProperties @ConfigurationProperties} for Servlet encoding.
2826
*
29-
* @author Phillip Webb
30-
* @author Stephane Nicoll
31-
* @author Brian Clozel
32-
* @since 2.3.0
27+
* @author Andy Wilkinson
28+
* @since 4.0.0
3329
*/
34-
@ConfigurationPropertiesSource
35-
public class Encoding {
30+
@ConfigurationProperties("spring.servlet.encoding")
31+
public class ServletEncodingProperties {
3632

3733
/**
3834
* Default HTTP encoding for Servlet applications.
@@ -62,11 +58,6 @@ public class Encoding {
6258
*/
6359
private Boolean forceResponse;
6460

65-
/**
66-
* Mapping of locale to charset for response encoding.
67-
*/
68-
private Map<Locale, Charset> mapping;
69-
7061
public Charset getCharset() {
7162
return this.charset;
7263
}
@@ -99,29 +90,21 @@ public void setForceResponse(boolean forceResponse) {
9990
this.forceResponse = forceResponse;
10091
}
10192

102-
public Map<Locale, Charset> getMapping() {
103-
return this.mapping;
104-
}
105-
106-
public void setMapping(Map<Locale, Charset> mapping) {
107-
this.mapping = mapping;
108-
}
109-
110-
public boolean shouldForce(Type type) {
111-
Boolean force = (type != Type.REQUEST) ? this.forceResponse : this.forceRequest;
93+
public boolean shouldForce(HttpMessageType type) {
94+
Boolean force = (type != HttpMessageType.REQUEST) ? this.forceResponse : this.forceRequest;
11295
if (force == null) {
11396
force = this.force;
11497
}
11598
if (force == null) {
116-
force = (type == Type.REQUEST);
99+
force = (type == HttpMessageType.REQUEST);
117100
}
118101
return force;
119102
}
120103

121104
/**
122105
* Type of HTTP message to consider for encoding configuration.
123106
*/
124-
public enum Type {
107+
public enum HttpMessageType {
125108

126109
/**
127110
* HTTP request message.

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/ServletWebServerFactoryCustomizer.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ public void customize(ConfigurableServletWebServerFactory factory) {
9696
.whenNot(CollectionUtils::isEmpty)
9797
.to(factory::setCookieSameSiteSuppliers);
9898
map.from(this.serverProperties::getMimeMappings).to(factory::addMimeMappings);
99+
map.from(this.serverProperties.getServlet().getEncoding()::getMapping).to(factory::setLocaleCharsetMappings);
99100
this.webListenerRegistrars.forEach((registrar) -> registrar.register(factory));
100101
}
101102

spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,11 +126,54 @@
126126
"name": "server.reactive.session.cookie.secure",
127127
"description": "Whether to always mark the cookie as secure."
128128
},
129+
{
130+
"name": "server.servlet.encoding.charset",
131+
"type": "java.nio.charset.Charset",
132+
"description": "Charset of HTTP requests and responses. Added to the Content-Type header if not set explicitly.",
133+
"deprecation": {
134+
"replacement": "spring.servlet.encoding.charset",
135+
"level": "error"
136+
}
137+
},
129138
{
130139
"name": "server.servlet.encoding.enabled",
131140
"type": "java.lang.Boolean",
132141
"description": "Whether to enable http encoding support.",
133-
"defaultValue": true
142+
"defaultValue": true,
143+
"deprecation": {
144+
"replacement": "spring.servlet.encoding.enabled",
145+
"level": "error"
146+
}
147+
},
148+
{
149+
"name": "server.servlet.encoding.force",
150+
"type": "java.lang.Boolean",
151+
"description": "Whether to force the encoding to the configured charset on HTTP requests and responses.",
152+
"defaultValue": false,
153+
"deprecation": {
154+
"replacement": "spring.servlet.encoding.force",
155+
"level": "error"
156+
}
157+
},
158+
{
159+
"name": "server.servlet.encoding.force-request",
160+
"type": "java.lang.Boolean",
161+
"description": "Whether to force the encoding to the configured charset on HTTP requests. Defaults to true when force has not been specified.",
162+
"defaultValue": true,
163+
"deprecation": {
164+
"replacement": "spring.servlet.encoding.force-request",
165+
"level": "error"
166+
}
167+
},
168+
{
169+
"name": "server.servlet.encoding.force-response",
170+
"type": "java.lang.Boolean",
171+
"description": "Whether to force the encoding to the configured charset on HTTP responses.",
172+
"defaultValue": false,
173+
"deprecation": {
174+
"replacement": "spring.servlet.encoding.force-response",
175+
"level": "error"
176+
}
134177
},
135178
{
136179
"name": "server.servlet.jsp.class-name",
@@ -2525,6 +2568,12 @@
25252568
"level": "error"
25262569
}
25272570
},
2571+
{
2572+
"name": "spring.servlet.encoding.enabled",
2573+
"type": "java.lang.Boolean",
2574+
"description": "Whether to enable Servlet HTTP encoding support.",
2575+
"defaultValue": true
2576+
},
25282577
{
25292578
"name": "spring.session.redis.cleanup-cron",
25302579
"defaultValue": "0 * * * * *"

0 commit comments

Comments
 (0)