From 740b00e3a5d5859f07ff5b66ec6d215be19cc26e Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Fri, 13 Jun 2025 12:21:21 -0700 Subject: [PATCH] Add condition for ClientHttpConnectorBuilder detection Update `ClientHttpConnectorAutoConfiguration` with a condition to ensure that `ClientHttpConnectorBuilder.detect` will return a result. Prior to this commit, when using a JDK without `java.net.http.HttpClient` access the auto-configuration would fail. Fixes gh-45955 --- .../ClientHttpConnectorAutoConfiguration.java | 2 + ...OnClientHttpConnectorBuilderDetection.java | 44 +++++++++++++++++++ ...ntHttpConnectorAutoConfigurationTests.java | 12 +++++ 3 files changed, 58 insertions(+) create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/http/client/reactive/ConditionalOnClientHttpConnectorBuilderDetection.java diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/http/client/reactive/ClientHttpConnectorAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/http/client/reactive/ClientHttpConnectorAutoConfiguration.java index 247f7c6737..6a53dda229 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/http/client/reactive/ClientHttpConnectorAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/http/client/reactive/ClientHttpConnectorAutoConfiguration.java @@ -34,6 +34,7 @@ import org.springframework.boot.http.client.reactive.ClientHttpConnectorSettings import org.springframework.boot.ssl.SslBundles; import org.springframework.boot.util.LambdaSafe; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Lazy; @@ -48,6 +49,7 @@ import org.springframework.http.client.reactive.ClientHttpConnector; */ @AutoConfiguration(after = SslAutoConfiguration.class) @ConditionalOnClass({ ClientHttpConnector.class, Mono.class }) +@Conditional(ConditionalOnClientHttpConnectorBuilderDetection.class) @EnableConfigurationProperties(HttpReactiveClientProperties.class) public class ClientHttpConnectorAutoConfiguration implements BeanClassLoaderAware { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/http/client/reactive/ConditionalOnClientHttpConnectorBuilderDetection.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/http/client/reactive/ConditionalOnClientHttpConnectorBuilderDetection.java new file mode 100644 index 0000000000..301675601e --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/http/client/reactive/ConditionalOnClientHttpConnectorBuilderDetection.java @@ -0,0 +1,44 @@ +/* + * 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.client.reactive; + +import org.springframework.boot.autoconfigure.condition.ConditionOutcome; +import org.springframework.boot.autoconfigure.condition.SpringBootCondition; +import org.springframework.boot.http.client.reactive.ClientHttpConnectorBuilder; +import org.springframework.context.annotation.Condition; +import org.springframework.context.annotation.ConditionContext; +import org.springframework.core.type.AnnotatedTypeMetadata; + +/** + * {@link Condition} that checks that {@link ClientHttpConnectorBuilder} can be detected. + * + * @author Phillip Webb + */ +class ConditionalOnClientHttpConnectorBuilderDetection extends SpringBootCondition { + + @Override + public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) { + try { + ClientHttpConnectorBuilder.detect(context.getClassLoader()); + return ConditionOutcome.match("Detected ClientHttpConnectorBuilder"); + } + catch (IllegalStateException ex) { + return ConditionOutcome.noMatch("Unable to detect ClientHttpConnectorBuilder"); + } + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/http/client/reactive/ClientHttpConnectorAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/http/client/reactive/ClientHttpConnectorAutoConfigurationTests.java index 1823cf2396..f2f42afac2 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/http/client/reactive/ClientHttpConnectorAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/http/client/reactive/ClientHttpConnectorAutoConfigurationTests.java @@ -41,6 +41,7 @@ import org.springframework.http.client.ReactorResourceFactory; import org.springframework.http.client.reactive.ClientHttpConnector; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalStateException; import static org.mockito.Mockito.mock; /** @@ -143,6 +144,17 @@ class ClientHttpConnectorAutoConfigurationTests { }); } + @Test + void shouldBeConditionalOnAtLeastOneHttpConnectorClass() { + FilteredClassLoader classLoader = new FilteredClassLoader(reactor.netty.http.client.HttpClient.class, + org.eclipse.jetty.client.HttpClient.class, org.apache.hc.client5.http.impl.async.HttpAsyncClients.class, + java.net.http.HttpClient.class); + assertThatIllegalStateException().as("enough filtering") + .isThrownBy(() -> ClientHttpConnectorBuilder.detect(classLoader)); + this.contextRunner.withClassLoader(classLoader) + .run((context) -> assertThat(context).doesNotHaveBean(ClientHttpConnectorSettings.class)); + } + private List sslPropertyValues() { List propertyValues = new ArrayList<>(); String location = "classpath:org/springframework/boot/autoconfigure/ssl/";