Favor Duration accepting timeout method over int method

Closes gh-40635
This commit is contained in:
Moritz Halbritter 2024-05-08 14:01:09 +02:00
parent c47cdda824
commit 92f7414fad
8 changed files with 148 additions and 7 deletions

View File

@ -329,7 +329,7 @@ public final class ClientHttpRequestFactories {
*/
private static class SimpleClientHttpsRequestFactory extends SimpleClientHttpRequestFactory {
private SslBundle sslBundle;
private final SslBundle sslBundle;
SimpleClientHttpsRequestFactory(SslBundle sslBundle) {
this.sslBundle = sslBundle;
@ -385,13 +385,23 @@ public final class ClientHttpRequestFactories {
}
private static void setConnectTimeout(ClientHttpRequestFactory factory, Duration connectTimeout) {
Method method = findMethod(factory, "setConnectTimeout", int.class);
Method method = tryFindMethod(factory, "setConnectTimeout", Duration.class);
if (method != null) {
invoke(factory, method, connectTimeout);
return;
}
method = findMethod(factory, "setConnectTimeout", int.class);
int timeout = Math.toIntExact(connectTimeout.toMillis());
invoke(factory, method, timeout);
}
private static void setReadTimeout(ClientHttpRequestFactory factory, Duration readTimeout) {
Method method = findMethod(factory, "setReadTimeout", int.class);
Method method = tryFindMethod(factory, "setReadTimeout", Duration.class);
if (method != null) {
invoke(factory, method, readTimeout);
return;
}
method = findMethod(factory, "setReadTimeout", int.class);
int timeout = Math.toIntExact(readTimeout.toMillis());
invoke(factory, method, timeout);
}
@ -407,6 +417,18 @@ public final class ClientHttpRequestFactories {
return method;
}
private static Method tryFindMethod(ClientHttpRequestFactory requestFactory, String methodName,
Class<?>... parameters) {
Method method = ReflectionUtils.findMethod(requestFactory.getClass(), methodName, parameters);
if (method == null) {
return null;
}
if (method.isAnnotationPresent(Deprecated.class)) {
return null;
}
return method;
}
private static void invoke(ClientHttpRequestFactory requestFactory, Method method, Object... parameters) {
ReflectionUtils.invokeMethod(method, requestFactory, parameters);
}

View File

@ -27,6 +27,7 @@ import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.junit.jupiter.api.Assumptions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
@ -101,6 +102,26 @@ abstract class AbstractClientHttpRequestFactoriesTests<T extends ClientHttpReque
assertThat(readTimeout((T) requestFactory)).isEqualTo(Duration.ofSeconds(120).toMillis());
}
@Test
void shouldSetConnectTimeoutsWhenUsingReflective() {
Assumptions.assumeTrue(supportsSettingConnectTimeout());
ClientHttpRequestFactorySettings settings = ClientHttpRequestFactorySettings.DEFAULTS
.withConnectTimeout(Duration.ofSeconds(1));
T requestFactory = ClientHttpRequestFactories
.get(() -> ClientHttpRequestFactories.get(this.requestFactoryType, settings), settings);
assertThat(connectTimeout(requestFactory)).isEqualTo(1000);
}
@Test
void shouldSetReadTimeoutsWhenUsingReflective() {
Assumptions.assumeTrue(supportsSettingReadTimeout());
ClientHttpRequestFactorySettings settings = ClientHttpRequestFactorySettings.DEFAULTS
.withReadTimeout(Duration.ofSeconds(2));
T requestFactory = ClientHttpRequestFactories
.get(() -> ClientHttpRequestFactories.get(this.requestFactoryType, settings), settings);
assertThat(readTimeout(requestFactory)).isEqualTo(2000);
}
@ParameterizedTest
@ValueSource(strings = { "GET", "POST" })
void connectWithSslBundle(String httpMethod) throws Exception {
@ -136,8 +157,12 @@ abstract class AbstractClientHttpRequestFactoriesTests<T extends ClientHttpReque
}
}
protected abstract boolean supportsSettingConnectTimeout();
protected abstract long connectTimeout(T requestFactory);
protected abstract boolean supportsSettingReadTimeout();
protected abstract long readTimeout(T requestFactory);
public static class TestServlet extends HttpServlet {

View File

@ -53,4 +53,14 @@ class ClientHttpRequestFactoriesHttpComponentsTests
return socketConfig.getSoTimeout().toMilliseconds();
}
@Override
protected boolean supportsSettingConnectTimeout() {
return true;
}
@Override
protected boolean supportsSettingReadTimeout() {
return false;
}
}

View File

@ -45,4 +45,14 @@ class ClientHttpRequestFactoriesJettyTests
return (long) ReflectionTestUtils.getField(requestFactory, "readTimeout");
}
@Override
protected boolean supportsSettingConnectTimeout() {
return true;
}
@Override
protected boolean supportsSettingReadTimeout() {
return true;
}
}

View File

@ -61,4 +61,14 @@ class ClientHttpRequestFactoriesOkHttp3Tests
return ((OkHttpClient) ReflectionTestUtils.getField(requestFactory, "client")).readTimeoutMillis();
}
@Override
protected boolean supportsSettingConnectTimeout() {
return true;
}
@Override
protected boolean supportsSettingReadTimeout() {
return true;
}
}

View File

@ -59,4 +59,14 @@ class ClientHttpRequestFactoriesOkHttp4Tests
return ((OkHttpClient) ReflectionTestUtils.getField(requestFactory, "client")).readTimeoutMillis();
}
@Override
protected boolean supportsSettingConnectTimeout() {
return true;
}
@Override
protected boolean supportsSettingReadTimeout() {
return true;
}
}

View File

@ -44,4 +44,14 @@ class ClientHttpRequestFactoriesSimpleTests
return (int) ReflectionTestUtils.getField(requestFactory, "readTimeout");
}
@Override
protected boolean supportsSettingConnectTimeout() {
return true;
}
@Override
protected boolean supportsSettingReadTimeout() {
return true;
}
}

View File

@ -16,7 +16,6 @@
package org.springframework.boot.web.client;
import java.io.IOException;
import java.net.URI;
import java.time.Duration;
@ -162,6 +161,18 @@ class ClientHttpRequestFactoriesTests {
assertThat(requestFactory).hasFieldOrPropertyWithValue("readTimeout", 1234);
}
@Test
void reflectiveShouldFavorDurationTimeoutMethods() {
IntAndDurationTimeoutsClientHttpRequestFactory requestFactory = ClientHttpRequestFactories.get(
IntAndDurationTimeoutsClientHttpRequestFactory.class,
ClientHttpRequestFactorySettings.DEFAULTS.withConnectTimeout(Duration.ofSeconds(1))
.withReadTimeout(Duration.ofSeconds(2)));
assertThat((requestFactory).connectTimeout).isZero();
assertThat((requestFactory).readTimeout).isZero();
assertThat((requestFactory).connectTimeoutDuration).isEqualTo(Duration.ofSeconds(1));
assertThat((requestFactory).readTimeoutDuration).isEqualTo(Duration.ofSeconds(2));
}
public static class TestClientHttpRequestFactory implements ClientHttpRequestFactory {
private int connectTimeout;
@ -169,7 +180,7 @@ class ClientHttpRequestFactoriesTests {
private int readTimeout;
@Override
public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException {
public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) {
throw new UnsupportedOperationException();
}
@ -186,7 +197,7 @@ class ClientHttpRequestFactoriesTests {
public static class UnconfigurableClientHttpRequestFactory implements ClientHttpRequestFactory {
@Override
public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException {
public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) {
throw new UnsupportedOperationException();
}
@ -195,7 +206,7 @@ class ClientHttpRequestFactoriesTests {
public static class DeprecatedMethodsClientHttpRequestFactory implements ClientHttpRequestFactory {
@Override
public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException {
public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) {
throw new UnsupportedOperationException();
}
@ -213,4 +224,37 @@ class ClientHttpRequestFactoriesTests {
}
public static class IntAndDurationTimeoutsClientHttpRequestFactory implements ClientHttpRequestFactory {
private int readTimeout;
private int connectTimeout;
private Duration readTimeoutDuration;
private Duration connectTimeoutDuration;
@Override
public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) {
throw new UnsupportedOperationException();
}
public void setConnectTimeout(int timeout) {
this.connectTimeout = timeout;
}
public void setReadTimeout(int timeout) {
this.readTimeout = timeout;
}
public void setConnectTimeout(Duration timeout) {
this.connectTimeoutDuration = timeout;
}
public void setReadTimeout(Duration timeout) {
this.readTimeoutDuration = timeout;
}
}
}