Merge branch '3.5.x'

This commit is contained in:
Andy Wilkinson
2025-11-10 10:39:32 +00:00
11 changed files with 26 additions and 56 deletions
@@ -64,6 +64,7 @@ import org.springframework.boot.loader.tools.ReachabilityMetadataProperties;
import org.springframework.util.Assert;
import org.springframework.util.StreamUtils;
import org.springframework.util.StringUtils;
import org.springframework.util.function.ThrowingSupplier;
/**
* A {@link CopyAction} for creating a Spring Boot zip archive (typically a jar or war).
@@ -325,7 +326,7 @@ class BootZipCopyAction implements CopyAction {
private void writeJarModeLibrary(String location, JarModeLibrary library) throws IOException {
String name = location + library.getName();
writeEntry(name, ZipEntryContentWriter.fromInputStream(library.openStream()), false,
(entry) -> prepareStoredEntry(library.openStream(), false, entry));
(entry) -> prepareStoredEntry(library::openStream, false, entry));
if (BootZipCopyAction.this.layerResolver != null) {
Layer layer = BootZipCopyAction.this.layerResolver.getLayer(library);
Assert.state(this.layerIndex != null, "'layerIndex' must not be null");
@@ -429,12 +430,12 @@ class BootZipCopyAction implements CopyAction {
}
private void prepareStoredEntry(FileCopyDetails details, ZipArchiveEntry archiveEntry) throws IOException {
prepareStoredEntry(details.open(), BootZipCopyAction.this.requiresUnpack.isSatisfiedBy(details),
prepareStoredEntry(details::open, BootZipCopyAction.this.requiresUnpack.isSatisfiedBy(details),
archiveEntry);
}
private void prepareStoredEntry(InputStream input, boolean unpack, ZipArchiveEntry archiveEntry)
throws IOException {
private void prepareStoredEntry(ThrowingSupplier<InputStream> input, boolean unpack,
ZipArchiveEntry archiveEntry) throws IOException {
new StoredEntryPreparator(input, unpack).prepareStoredEntry(archiveEntry);
}
@@ -564,10 +565,10 @@ class BootZipCopyAction implements CopyAction {
private long size;
StoredEntryPreparator(InputStream inputStream, boolean unpack) throws IOException {
StoredEntryPreparator(ThrowingSupplier<InputStream> input, boolean unpack) throws IOException {
this.unpack = unpack;
try (inputStream) {
load(inputStream);
try (InputStream stream = input.get()) {
load(stream);
}
}
@@ -76,7 +76,7 @@ class DockerRegistryConfigAuthenticationTests {
}
""")
@Test
void getAuthHeaderWhenAuthForDockerDomain(@ResourcesRoot Path directory) throws Exception {
void getAuthHeaderWhenAuthForDockerDomain(@ResourcesRoot Path directory) {
this.environment.put("DOCKER_CONFIG", directory.toString());
ImageReference imageReference = ImageReference.of("docker.io/ubuntu:latest");
String authHeader = getAuthHeader(imageReference);
@@ -99,7 +99,7 @@ class DockerRegistryConfigAuthenticationTests {
}
""")
@Test
void getAuthHeaderWhenAuthForLegacyDockerDomain(@ResourcesRoot Path directory) throws Exception {
void getAuthHeaderWhenAuthForLegacyDockerDomain(@ResourcesRoot Path directory) {
this.environment.put("DOCKER_CONFIG", directory.toString());
ImageReference imageReference = ImageReference.of("index.docker.io/ubuntu:latest");
String authHeader = getAuthHeader(imageReference);
@@ -121,7 +121,7 @@ class DockerRegistryConfigAuthenticationTests {
}
""")
@Test
void getAuthHeaderWhenAuthForCustomDomain(@ResourcesRoot Path directory) throws Exception {
void getAuthHeaderWhenAuthForCustomDomain(@ResourcesRoot Path directory) {
this.environment.put("DOCKER_CONFIG", directory.toString());
ImageReference imageReference = ImageReference.of("my-registry.example.com/ubuntu:latest");
String authHeader = getAuthHeader(imageReference);
@@ -143,7 +143,7 @@ class DockerRegistryConfigAuthenticationTests {
}
""")
@Test
void getAuthHeaderWhenAuthForCustomDomainWithLegacyFormat(@ResourcesRoot Path directory) throws Exception {
void getAuthHeaderWhenAuthForCustomDomainWithLegacyFormat(@ResourcesRoot Path directory) {
this.environment.put("DOCKER_CONFIG", directory.toString());
ImageReference imageReference = ImageReference.of("my-registry.example.com/ubuntu:latest");
String authHeader = getAuthHeader(imageReference);
@@ -160,7 +160,7 @@ class DockerRegistryConfigAuthenticationTests {
}
""")
@Test
void getAuthHeaderWhenEmptyConfigDirectoryReturnsFallback(@ResourcesRoot Path directory) throws Exception {
void getAuthHeaderWhenEmptyConfigDirectoryReturnsFallback(@ResourcesRoot Path directory) {
this.environment.put("DOCKER_CONFIG", directory.toString());
ImageReference imageReference = ImageReference.of("docker.io/ubuntu:latest");
String authHeader = getAuthHeader(imageReference, DockerRegistryAuthentication.EMPTY_USER);
@@ -173,7 +173,7 @@ class GraphQlWebMvcSecurityAutoConfigurationTests {
static class SecurityConfig {
@Bean
DefaultSecurityFilterChain springWebFilterChain(HttpSecurity http) throws Exception {
DefaultSecurityFilterChain springWebFilterChain(HttpSecurity http) {
return http.csrf(CsrfConfigurer::disable)
// Demonstrate that method security works
// Best practice to use both for defense in depth
@@ -41,7 +41,6 @@ import org.springframework.boot.actuate.endpoint.EndpointId;
import org.springframework.boot.actuate.endpoint.ExposableEndpoint;
import org.springframework.boot.actuate.endpoint.OperationResponseBody;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.jackson.EndpointJackson2ObjectMapper;
import org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver;
import org.springframework.boot.actuate.endpoint.web.EndpointMapping;
import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;
@@ -109,7 +108,7 @@ class JerseyWebEndpointManagementContextConfiguration {
}
@Bean
@ConditionalOnBean(EndpointJackson2ObjectMapper.class)
@ConditionalOnBean(org.springframework.boot.actuate.endpoint.jackson.EndpointJackson2ObjectMapper.class)
@SuppressWarnings("removal")
ResourceConfigCustomizer endpointJackson2ObjectMapperResourceConfigCustomizer(
org.springframework.boot.actuate.endpoint.jackson.EndpointJackson2ObjectMapper endpointJackson2ObjectMapper) {
@@ -19,13 +19,9 @@ package org.springframework.boot.jetty.autoconfigure;
import org.eclipse.jetty.util.VirtualThreads;
import org.eclipse.jetty.util.thread.VirtualThreadPool;
import org.springframework.boot.context.properties.bind.Bindable;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.boot.jetty.ConfigurableJettyWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.Ordered;
import org.springframework.core.env.Environment;
import org.springframework.util.Assert;
/**
@@ -36,16 +32,7 @@ import org.springframework.util.Assert;
* @since 4.0.0
*/
public class JettyVirtualThreadsWebServerFactoryCustomizer
implements WebServerFactoryCustomizer<ConfigurableJettyWebServerFactory>, Ordered, EnvironmentAware {
private final JettyServerProperties jettyProperties;
private final boolean bind;
public JettyVirtualThreadsWebServerFactoryCustomizer(JettyServerProperties jettyProperties) {
this.jettyProperties = jettyProperties;
this.bind = false;
}
implements WebServerFactoryCustomizer<ConfigurableJettyWebServerFactory>, Ordered {
@Override
public void customize(ConfigurableJettyWebServerFactory factory) {
@@ -60,11 +47,4 @@ public class JettyVirtualThreadsWebServerFactoryCustomizer
return JettyWebServerFactoryCustomizer.ORDER + 1;
}
@Override
public void setEnvironment(Environment environment) {
if (this.bind) {
Binder.get(environment).bind("server.jetty", Bindable.ofInstance(this.jettyProperties));
}
}
}
@@ -38,22 +38,16 @@ import org.springframework.core.env.Environment;
@Configuration(proxyBeanMethods = false)
public class JettyWebServerConfiguration {
private final JettyServerProperties jettyProperties;
JettyWebServerConfiguration(JettyServerProperties jettyProperties) {
this.jettyProperties = jettyProperties;
}
@Bean
JettyWebServerFactoryCustomizer jettyWebServerFactoryCustomizer(Environment environment,
ServerProperties serverProperties) {
return new JettyWebServerFactoryCustomizer(environment, serverProperties, this.jettyProperties);
ServerProperties serverProperties, JettyServerProperties jettyProperties) {
return new JettyWebServerFactoryCustomizer(environment, serverProperties, jettyProperties);
}
@Bean
@ConditionalOnThreading(Threading.VIRTUAL)
JettyVirtualThreadsWebServerFactoryCustomizer jettyVirtualThreadsWebServerFactoryCustomizer() {
return new JettyVirtualThreadsWebServerFactoryCustomizer(this.jettyProperties);
return new JettyVirtualThreadsWebServerFactoryCustomizer();
}
}
@@ -38,9 +38,7 @@ class JettyVirtualThreadsWebServerFactoryCustomizerTests {
@Test
@EnabledForJreRange(min = JRE.JAVA_21)
void shouldConfigureVirtualThreads() {
JettyServerProperties properties = new JettyServerProperties();
JettyVirtualThreadsWebServerFactoryCustomizer customizer = new JettyVirtualThreadsWebServerFactoryCustomizer(
properties);
JettyVirtualThreadsWebServerFactoryCustomizer customizer = new JettyVirtualThreadsWebServerFactoryCustomizer();
ConfigurableJettyWebServerFactory factory = mock(ConfigurableJettyWebServerFactory.class);
customizer.customize(factory);
then(factory).should().setThreadPool(assertArg((threadPool) -> {
@@ -19,7 +19,6 @@ package org.springframework.boot.webflux.test.autoconfigure;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.test.json.JsonCompareMode;
import org.springframework.test.web.reactive.server.WebTestClient;
@@ -35,9 +34,6 @@ class WebFluxTestJsonComponentIntegrationTests {
@Autowired
private WebTestClient webClient;
@Autowired
private ConfigurableApplicationContext context;
@Test
void shouldFindJsonComponent() {
this.webClient.post()
@@ -23,7 +23,6 @@ import reactor.core.publisher.Mono;
import tools.jackson.databind.module.SimpleModule;
import org.springframework.boot.jackson.JacksonComponent;
import org.springframework.boot.jackson2.JsonComponent;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.FilterType;
import org.springframework.core.type.classreading.MetadataReader;
@@ -209,7 +208,7 @@ class WebFluxTypeExcludeFilterTests {
}
@JsonComponent
@org.springframework.boot.jackson2.JsonComponent
@SuppressWarnings("removal")
static class ExampleJsonComponent {
@@ -22,7 +22,6 @@ import org.junit.jupiter.api.Test;
import tools.jackson.databind.module.SimpleModule;
import org.springframework.boot.jackson.JacksonComponent;
import org.springframework.boot.jackson2.JsonComponent;
import org.springframework.boot.webmvc.autoconfigure.WebMvcRegistrations;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.FilterType;
@@ -224,7 +223,7 @@ class WebMvcTypeExcludeFilterTests {
}
@JsonComponent
@org.springframework.boot.jackson2.JsonComponent
@SuppressWarnings("removal")
static class ExampleJsonComponent {
@@ -165,6 +165,7 @@ public enum TestImage {
* {@link org.testcontainers.containers.MongoDBContainer}.
* @deprecated since 4.0.0 for removal in 4.2.0 in favor of {@link #MONGODB}
*/
@SuppressWarnings("deprecation")
@Deprecated(since = "3.4.0", forRemoval = true)
MONGODB_DEPRECATED("mongo", "5.0.17", () -> org.testcontainers.containers.MongoDBContainer.class,
(container) -> ((org.testcontainers.containers.MongoDBContainer) container).withStartupAttempts(5)
@@ -194,6 +195,7 @@ public enum TestImage {
* {@link org.testcontainers.containers.Neo4jContainer}.
* @deprecated since 4.0.0 for removal in 4.2.0 in favor of {@link #NEO4J}
*/
@SuppressWarnings({ "deprecation", "rawtypes" })
@Deprecated(since = "3.4.0", forRemoval = true)
NEO4J_DEPRECATED("neo4j", "5.26.11", () -> org.testcontainers.containers.Neo4jContainer.class,
(container) -> ((org.testcontainers.containers.Neo4jContainer) container).withStartupAttempts(5)
@@ -236,6 +238,7 @@ public enum TestImage {
* {@link org.testcontainers.containers.PulsarContainer}.
* @deprecated since 4.0.0 for removal in 4.2.0 in favor of {@link #PULSAR}
*/
@SuppressWarnings("deprecation")
@Deprecated(since = "3.4.0", forRemoval = true)
PULSAR_DEPRECATED("apachepulsar/pulsar", "3.3.3", () -> org.testcontainers.containers.PulsarContainer.class,
(container) -> ((org.testcontainers.containers.PulsarContainer) container).withStartupAttempts(2)
@@ -252,6 +255,7 @@ public enum TestImage {
* {@link org.testcontainers.containers.RabbitMQContainer}.
* @deprecated since 4.0.0 for removal in 4.2.0 in favor of {@link #RABBITMQ}
*/
@SuppressWarnings("deprecation")
@Deprecated(since = "3.4.0", forRemoval = true)
RABBITMQ_DEPRECATED("rabbitmq", "3.11-alpine", () -> org.testcontainers.containers.RabbitMQContainer.class,
(container) -> ((org.testcontainers.containers.RabbitMQContainer) container)