Move spring.codec properties to spring.http.codecs
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Waiting to run Details
Build and Deploy Snapshot / Trigger Docs Build (push) Blocked by required conditions Details
Build and Deploy Snapshot / Verify (push) Blocked by required conditions Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[early-access:true toolchain:true version:24], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[early-access:true toolchain:true version:24], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:22], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:22], map[id:windows-latest name:Windows]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:23], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Waiting to run Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:23], map[id:windows-latest name:Windows]) (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:false version:17]) (push) Waiting to run Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Waiting to run Details

Closes gh-44925
This commit is contained in:
Andy Wilkinson 2025-04-01 15:36:11 +01:00
parent 5e8812abb1
commit f039c73db7
7 changed files with 179 additions and 50 deletions

View File

@ -87,7 +87,6 @@ public abstract class DocumentConfigurationProperties extends DefaultTask {
config.accept("spring.autoconfigure");
config.accept("spring.banner");
config.accept("spring.beaninfo");
config.accept("spring.codec");
config.accept("spring.config");
config.accept("spring.info");
config.accept("spring.jmx");

View File

@ -16,7 +16,9 @@
package org.springframework.boot.autoconfigure.codec;
import org.springframework.boot.autoconfigure.http.codec.HttpCodecsProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.DeprecatedConfigurationProperty;
import org.springframework.util.unit.DataSize;
/**
@ -24,8 +26,10 @@ import org.springframework.util.unit.DataSize;
*
* @author Brian Clozel
* @since 2.2.1
* @deprecated since 3.5.0 for removal in 4.0.0 in favor of {@link HttpCodecsProperties}
*/
@ConfigurationProperties("spring.codec")
@Deprecated(since = "3.5.0", forRemoval = true)
public class CodecProperties {
/**
@ -41,6 +45,7 @@ public class CodecProperties {
*/
private DataSize maxInMemorySize;
@DeprecatedConfigurationProperty(since = "3.5.0", replacement = "spring.http.codec.log-request-details")
public boolean isLogRequestDetails() {
return this.logRequestDetails;
}
@ -49,6 +54,7 @@ public class CodecProperties {
this.logRequestDetails = logRequestDetails;
}
@DeprecatedConfigurationProperty(since = "3.5.0", replacement = "spring.http.codec.max-in-memory-size")
public DataSize getMaxInMemorySize() {
return this.maxInMemorySize;
}

View File

@ -20,7 +20,6 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.codec.CodecProperties;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
@ -29,7 +28,9 @@ import org.springframework.boot.context.properties.PropertyMapper;
import org.springframework.boot.web.codec.CodecCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.Environment;
import org.springframework.http.codec.CodecConfigurer;
import org.springframework.http.codec.json.Jackson2JsonDecoder;
import org.springframework.http.codec.json.Jackson2JsonEncoder;
@ -47,7 +48,6 @@ import org.springframework.web.reactive.function.client.WebClient;
*/
@AutoConfiguration(after = JacksonAutoConfiguration.class)
@ConditionalOnClass({ CodecConfigurer.class, WebClient.class })
@EnableConfigurationProperties(CodecProperties.class)
public class CodecsAutoConfiguration {
private static final MimeType[] EMPTY_MIME_TYPES = {};
@ -69,21 +69,48 @@ public class CodecsAutoConfiguration {
}
@SuppressWarnings("removal")
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties({ org.springframework.boot.autoconfigure.codec.CodecProperties.class,
HttpCodecsProperties.class })
static class DefaultCodecsConfiguration {
@Bean
@Order(0)
CodecCustomizer defaultCodecCustomizer(CodecProperties codecProperties) {
return (configurer) -> {
DefaultCodecCustomizer defaultCodecCustomizer(
org.springframework.boot.autoconfigure.codec.CodecProperties codecProperties,
HttpCodecsProperties httpCodecProperties, Environment environment) {
return new DefaultCodecCustomizer(
httpCodecProperties.isLogRequestDetails(codecProperties::isLogRequestDetails),
httpCodecProperties.getMaxInMemorySize(codecProperties::getMaxInMemorySize));
}
static final class DefaultCodecCustomizer implements CodecCustomizer, Ordered {
private final boolean logRequestDetails;
private final DataSize maxInMemorySize;
DefaultCodecCustomizer(boolean logRequestDetails, DataSize maxInMemorySize) {
this.logRequestDetails = logRequestDetails;
this.maxInMemorySize = maxInMemorySize;
}
@Override
public void customize(CodecConfigurer configurer) {
PropertyMapper map = PropertyMapper.get();
CodecConfigurer.DefaultCodecs defaultCodecs = configurer.defaultCodecs();
defaultCodecs.enableLoggingRequestDetails(codecProperties.isLogRequestDetails());
map.from(codecProperties.getMaxInMemorySize())
defaultCodecs.enableLoggingRequestDetails(this.logRequestDetails);
map.from(this.maxInMemorySize)
.whenNonNull()
.asInt(DataSize::toBytes)
.to(defaultCodecs::maxInMemorySize);
};
}
@Override
public int getOrder() {
return 0;
}
}
}

View File

@ -0,0 +1,79 @@
/*
* 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.codec;
import java.util.function.Supplier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.util.unit.DataSize;
/**
* {@link ConfigurationProperties Properties} for reactive HTTP codecs.
*
* @author Brian Clozel
* @author Andy Wilkinson
* @since 3.5.0
*/
@ConfigurationProperties("spring.http.codecs")
public class HttpCodecsProperties {
/**
* Whether to log form data at DEBUG level, and headers at TRACE level.
*/
private boolean logRequestDetails;
@Deprecated(since = "3.5.0", forRemoval = true)
private boolean logRequestDetailsBound = false;
/**
* Limit on the number of bytes that can be buffered whenever the input stream needs
* to be aggregated. This applies only to the auto-configured WebFlux server and
* WebClient instances. By default this is not set, in which case individual codec
* defaults apply. Most codecs are limited to 256K by default.
*/
private DataSize maxInMemorySize;
@Deprecated(since = "3.5.0", forRemoval = true)
private boolean maxInMemorySizeBound = false;
public boolean isLogRequestDetails() {
return this.logRequestDetails;
}
boolean isLogRequestDetails(Supplier<Boolean> fallback) {
return this.logRequestDetailsBound ? this.logRequestDetails : fallback.get();
}
public void setLogRequestDetails(boolean logRequestDetails) {
this.logRequestDetails = logRequestDetails;
this.logRequestDetailsBound = true;
}
public DataSize getMaxInMemorySize() {
return this.maxInMemorySize;
}
DataSize getMaxInMemorySize(Supplier<DataSize> fallback) {
return this.maxInMemorySizeBound ? this.maxInMemorySize : fallback.get();
}
public void setMaxInMemorySize(DataSize maxInMemorySize) {
this.maxInMemorySize = maxInMemorySize;
this.maxInMemorySizeBound = true;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* 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.
@ -16,22 +16,21 @@
package org.springframework.boot.autoconfigure.http.codec;
import java.lang.reflect.Method;
import java.util.List;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.codec.CodecProperties;
import org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.boot.web.codec.CodecCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.core.Ordered;
import org.springframework.http.codec.CodecConfigurer;
import org.springframework.http.codec.CodecConfigurer.DefaultCodecs;
import org.springframework.http.codec.support.DefaultClientCodecConfigurer;
import org.springframework.util.ReflectionUtils;
import static org.assertj.core.api.Assertions.assertThat;
@ -48,34 +47,58 @@ class CodecsAutoConfigurationTests {
@Test
void autoConfigShouldProvideALoggingRequestDetailsCustomizer() {
this.contextRunner.run((context) -> {
CodecCustomizer customizer = context.getBean(CodecCustomizer.class);
CodecConfigurer configurer = new DefaultClientCodecConfigurer();
customizer.customize(configurer);
assertThat(configurer.defaultCodecs()).hasFieldOrPropertyWithValue("enableLoggingRequestDetails", false);
});
this.contextRunner.run((context) -> assertThat(defaultCodecs(context))
.hasFieldOrPropertyWithValue("enableLoggingRequestDetails", false));
}
@Test
void loggingRequestDetailsCustomizerShouldUseHttpProperties() {
this.contextRunner.withPropertyValues("spring.codec.log-request-details=true").run((context) -> {
CodecCustomizer customizer = context.getBean(CodecCustomizer.class);
CodecConfigurer configurer = new DefaultClientCodecConfigurer();
customizer.customize(configurer);
assertThat(configurer.defaultCodecs()).hasFieldOrPropertyWithValue("enableLoggingRequestDetails", true);
});
void loggingRequestDetailsCustomizerShouldUseCodecProperties() {
this.contextRunner.withPropertyValues("spring.codec.log-request-details=true")
.run((context) -> assertThat(defaultCodecs(context))
.hasFieldOrPropertyWithValue("enableLoggingRequestDetails", true));
}
@Test
void loggingRequestDetailsCustomizerShouldUseHttpCodecsProperties() {
this.contextRunner.withPropertyValues("spring.http.codecs.log-request-details=true")
.run((context) -> assertThat(defaultCodecs(context))
.hasFieldOrPropertyWithValue("enableLoggingRequestDetails", true));
}
@Test
void logRequestDetailsShouldGivePriorityToHttpCodecProperty() {
this.contextRunner
.withPropertyValues("spring.http.codecs.log-request-details=true", "spring.codec.log-request-details=false")
.run((context) -> assertThat(defaultCodecs(context))
.hasFieldOrPropertyWithValue("enableLoggingRequestDetails", true));
}
@Test
void maxInMemorySizeShouldUseCodecProperties() {
this.contextRunner.withPropertyValues("spring.codec.max-in-memory-size=64KB")
.run((context) -> assertThat(defaultCodecs(context)).hasFieldOrPropertyWithValue("maxInMemorySize",
64 * 1024));
}
@Test
void maxInMemorySizeShouldUseHttpCodecProperties() {
this.contextRunner.withPropertyValues("spring.http.codecs.max-in-memory-size=64KB")
.run((context) -> assertThat(defaultCodecs(context)).hasFieldOrPropertyWithValue("maxInMemorySize",
64 * 1024));
}
@Test
void maxInMemorySizeShouldGivePriorityToHttpCodecProperty() {
this.contextRunner
.withPropertyValues("spring.http.codecs.max-in-memory-size=64KB", "spring.codec.max-in-memory-size=32KB")
.run((context) -> assertThat(defaultCodecs(context)).hasFieldOrPropertyWithValue("maxInMemorySize",
64 * 1024));
}
@Test
void defaultCodecCustomizerBeanShouldHaveOrderZero() {
this.contextRunner.run((context) -> {
Method customizerMethod = ReflectionUtils.findMethod(
CodecsAutoConfiguration.DefaultCodecsConfiguration.class, "defaultCodecCustomizer",
CodecProperties.class);
Integer order = new TestAnnotationAwareOrderComparator().findOrder(customizerMethod);
assertThat(order).isZero();
});
this.contextRunner
.run((context) -> assertThat(context.getBean("defaultCodecCustomizer", Ordered.class).getOrder()).isZero());
}
@Test
@ -101,21 +124,16 @@ class CodecsAutoConfigurationTests {
@Test
void maxInMemorySizeEnforcedInDefaultCodecs() {
this.contextRunner.withPropertyValues("spring.codec.max-in-memory-size=1MB").run((context) -> {
CodecCustomizer customizer = context.getBean(CodecCustomizer.class);
CodecConfigurer configurer = new DefaultClientCodecConfigurer();
customizer.customize(configurer);
assertThat(configurer.defaultCodecs()).hasFieldOrPropertyWithValue("maxInMemorySize", 1048576);
});
this.contextRunner.withPropertyValues("spring.codec.max-in-memory-size=1MB")
.run((context) -> assertThat(defaultCodecs(context)).hasFieldOrPropertyWithValue("maxInMemorySize",
1048576));
}
static class TestAnnotationAwareOrderComparator extends AnnotationAwareOrderComparator {
@Override
public Integer findOrder(Object obj) {
return super.findOrder(obj);
}
private DefaultCodecs defaultCodecs(AssertableWebApplicationContext context) {
CodecCustomizer customizer = context.getBean(CodecCustomizer.class);
CodecConfigurer configurer = new DefaultClientCodecConfigurer();
customizer.customize(configurer);
return configurer.defaultCodecs();
}
@Configuration(proxyBeanMethods = false)

View File

@ -78,7 +78,7 @@ NOTE: If you do not want property defaults to be applied you can set configprop:
Because you need more information about web requests while developing Spring MVC and Spring WebFlux applications, developer tools suggests you to enable `DEBUG` logging for the `web` logging group.
This will give you information about the incoming request, which handler is processing it, the response outcome, and other details.
If you wish to log all request details (including potentially sensitive information), you can turn on the configprop:spring.mvc.log-request-details[] or configprop:spring.codec.log-request-details[] configuration properties.
If you wish to log all request details (including potentially sensitive information), you can turn on the configprop:spring.mvc.log-request-details[] or configprop:spring.http.codecs.log-request-details[] configuration properties.

View File

@ -87,7 +87,7 @@ When not configured, the following defaults are used:
Spring WebFlux uses the javadoc:org.springframework.http.codec.HttpMessageReader[] and javadoc:org.springframework.http.codec.HttpMessageWriter[] interfaces to convert HTTP requests and responses.
They are configured with javadoc:org.springframework.http.codec.CodecConfigurer[] to have sensible defaults by looking at the libraries available in your classpath.
Spring Boot provides dedicated configuration properties for codecs, `+spring.codec.*+`.
Spring Boot provides dedicated configuration properties for codecs, `+spring.http.codecs.*+`.
It also applies further customization by using javadoc:org.springframework.boot.web.codec.CodecCustomizer[] instances.
For example, `+spring.jackson.*+` configuration keys are applied to the Jackson codec.