diff --git a/gradle.properties b/gradle.properties index eb9bbe14aff8..d4321ef602e8 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,7 +6,7 @@ org.gradle.jvmargs=-Xmx2g -Dfile.encoding=UTF-8 kotlinVersion=1.8.22 nativeBuildToolsVersion=0.9.23 -springFrameworkVersion=6.1.0-M1 +springFrameworkVersion=6.1.0-SNAPSHOT tomcatVersion=10.1.10 kotlin.stdlib.default.dependency=false diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/client/ClientHttpRequestFactories.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/client/ClientHttpRequestFactories.java index 5b85a914c039..3757d53642a6 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/client/ClientHttpRequestFactories.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/client/ClientHttpRequestFactories.java @@ -45,6 +45,7 @@ import org.springframework.http.client.AbstractClientHttpRequestFactoryWrapper; import org.springframework.http.client.ClientHttpRequestFactory; import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.http.client.JdkClientHttpRequestFactory; import org.springframework.http.client.OkHttp3ClientHttpRequestFactory; import org.springframework.http.client.SimpleClientHttpRequestFactory; import org.springframework.util.Assert; @@ -70,6 +71,10 @@ public final class ClientHttpRequestFactories { private static final boolean OKHTTP_CLIENT_PRESENT = ClassUtils.isPresent(OKHTTP_CLIENT_CLASS, null); + static final String JDK_CLIENT_CLASS = "java.net.http.HttpClient"; + + private static final boolean JDK_CLIENT_PRESENT = ClassUtils.isPresent(JDK_CLIENT_CLASS, null); + private ClientHttpRequestFactories() { } @@ -87,6 +92,9 @@ public static ClientHttpRequestFactory get(ClientHttpRequestFactorySettings sett if (OKHTTP_CLIENT_PRESENT) { return OkHttp.get(settings); } + if (JDK_CLIENT_PRESENT) { + return Jdk.get(settings); + } return Simple.get(settings); } @@ -111,6 +119,9 @@ public static T get(Class requestFactory if (requestFactoryType == OkHttp3ClientHttpRequestFactory.class) { return (T) OkHttp.get(settings); } + if (requestFactoryType == JdkClientHttpRequestFactory.class) { + return (T) Jdk.get(settings); + } if (requestFactoryType == SimpleClientHttpRequestFactory.class) { return (T) Simple.get(settings); } @@ -210,6 +221,33 @@ private static OkHttp3ClientHttpRequestFactory createRequestFactory(SslBundle ss } + /** + * Support for {@link JdkClientHttpRequestFactory}. + */ + static class Jdk { + + static JdkClientHttpRequestFactory get(ClientHttpRequestFactorySettings settings) { + java.net.http.HttpClient httpClient = createHttpClient(settings.connectTimeout(), settings.sslBundle()); + JdkClientHttpRequestFactory requestFactory = new JdkClientHttpRequestFactory(httpClient); + PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull(); + map.from(settings::readTimeout).asInt(Duration::toMillis).to(requestFactory::setReadTimeout); + return requestFactory; + } + + private static java.net.http.HttpClient createHttpClient(Duration connectTimeout, SslBundle sslBundle) { + java.net.http.HttpClient.Builder builder = java.net.http.HttpClient.newBuilder(); + if (connectTimeout != null) { + builder.connectTimeout(connectTimeout); + } + if (sslBundle != null) { + builder.sslContext(sslBundle.createSslContext()); + } + return builder.build(); + } + + + } + /** * Support for {@link SimpleClientHttpRequestFactory}. */ diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/client/ClientHttpRequestFactoriesHttpComponentsTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/client/ClientHttpRequestFactoriesHttpComponentsTests.java index 98b9095afec7..b8df330e7790 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/client/ClientHttpRequestFactoriesHttpComponentsTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/client/ClientHttpRequestFactoriesHttpComponentsTests.java @@ -39,7 +39,7 @@ class ClientHttpRequestFactoriesHttpComponentsTests @Override protected long connectTimeout(HttpComponentsClientHttpRequestFactory requestFactory) { - return (int) ReflectionTestUtils.getField(requestFactory, "connectTimeout"); + return (long) ReflectionTestUtils.getField(requestFactory, "connectTimeout"); } @Override diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/client/ClientHttpRequestFactoriesJdkClientTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/client/ClientHttpRequestFactoriesJdkClientTests.java new file mode 100644 index 000000000000..a3dd693ec7b2 --- /dev/null +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/client/ClientHttpRequestFactoriesJdkClientTests.java @@ -0,0 +1,52 @@ +/* + * Copyright 2012-2023 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.web.client; + +import java.net.http.HttpClient; +import java.time.Duration; + +import org.springframework.boot.testsupport.classpath.ClassPathExclusions; +import org.springframework.http.client.JdkClientHttpRequestFactory; +import org.springframework.test.util.ReflectionTestUtils; + +/** + * Tests for {@link ClientHttpRequestFactories} when JDK HttpClient is the + * predominant HTTP client. + * + * @author Andy Wilkinson + */ +@ClassPathExclusions({ "httpclient5-*.jar", "okhttp-*.jar" }) +class ClientHttpRequestFactoriesJdkClientTests + extends AbstractClientHttpRequestFactoriesTests { + + ClientHttpRequestFactoriesJdkClientTests() { + super(JdkClientHttpRequestFactory.class); + } + + @Override + protected long connectTimeout(JdkClientHttpRequestFactory requestFactory) { + HttpClient httpClient = (HttpClient) ReflectionTestUtils.getField(requestFactory, "httpClient"); + return httpClient.connectTimeout().map(Duration::toMillis).orElse(-1L); + } + + @Override + @SuppressWarnings("unchecked") + protected long readTimeout(JdkClientHttpRequestFactory requestFactory) { + return ((Duration) ReflectionTestUtils.getField(requestFactory, "readTimeout")).toMillis(); + } + +} diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/client/ClientHttpRequestFactoriesSimpleTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/client/ClientHttpRequestFactoriesSimpleTests.java index a9e75aa6496b..a45ea3d9f68b 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/client/ClientHttpRequestFactoriesSimpleTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/client/ClientHttpRequestFactoriesSimpleTests.java @@ -26,7 +26,7 @@ * * @author Andy Wilkinson */ -@ClassPathExclusions({ "httpclient5-*.jar", "okhttp-*.jar" }) +@ClassPathExclusions(value = {"httpclient5-*.jar", "okhttp-*.jar"}, packages = "java.net.http") class ClientHttpRequestFactoriesSimpleTests extends AbstractClientHttpRequestFactoriesTests { diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilderSimpleIntegrationTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilderSimpleIntegrationTests.java index 2c3cb5374861..682e705025dd 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilderSimpleIntegrationTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/webservices/client/HttpWebServiceMessageSenderBuilderSimpleIntegrationTests.java @@ -34,7 +34,7 @@ * * @author Stephane Nicoll */ -@ClassPathExclusions({ "httpclient5-*.jar", "okhttp*.jar" }) +@ClassPathExclusions(value = {"httpclient5-*.jar", "okhttp-*.jar"}, packages = "java.net.http") class HttpWebServiceMessageSenderBuilderSimpleIntegrationTests { private final HttpWebServiceMessageSenderBuilder builder = new HttpWebServiceMessageSenderBuilder();