Reinstate support for read timeouts with RestTemplateBuilder
Refactor the way `ClientHttpRequestFactory` instances are created in order to support setting read timeouts. Prior to this commit, the reflection based approach would call `setReadTimeout`. As of Spring Framework 6.0, the `HttpComponentsClientHttpRequestFactory` class no longer supports this approach. The timeout must be set on the `HttpClientConnectionManager` used in the `HttpClient` which can be passed in to the constructor. In order to support this approach, the `ClientHttpRequestFactory` can now be created using a `Function` rather than a `Supplier`. The function accepts a `ClientHttpRequestFactorySettings` which provides the timeout settings to apply. The `ClientHttpRequestFactories` utility class provides methods to create `ClientHttpRequestFactory` instances that respect the settings. Whenever possible, these are created without using reflection. Fixes gh-32857 Co-authored-by: Phillip Webb <pwebb@vmware.com>pull/32880/head
parent
c22e76632c
commit
e6c37d698f
@ -0,0 +1,264 @@
|
||||
/*
|
||||
* Copyright 2012-2022 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.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.time.Duration;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.apache.hc.client5.http.classic.HttpClient;
|
||||
import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
|
||||
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
|
||||
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;
|
||||
import org.apache.hc.core5.http.io.SocketConfig;
|
||||
|
||||
import org.springframework.boot.context.properties.PropertyMapper;
|
||||
import org.springframework.http.client.AbstractClientHttpRequestFactoryWrapper;
|
||||
import org.springframework.http.client.ClientHttpRequestFactory;
|
||||
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
|
||||
import org.springframework.http.client.OkHttp3ClientHttpRequestFactory;
|
||||
import org.springframework.http.client.SimpleClientHttpRequestFactory;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* Utility class that can be used to create {@link ClientHttpRequestFactory} instances
|
||||
* configured using given {@link ClientHttpRequestFactorySettings}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @author Phillip Webb
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public final class ClientHttpRequestFactories {
|
||||
|
||||
static final String APACHE_HTTP_CLIENT_CLASS = "org.apache.hc.client5.http.impl.classic.HttpClients";
|
||||
|
||||
private static final boolean APACHE_HTTP_CLIENT_PRESENT = ClassUtils.isPresent(APACHE_HTTP_CLIENT_CLASS, null);
|
||||
|
||||
static final String OKHTTP_CLIENT_CLASS = "okhttp3.OkHttpClient";
|
||||
|
||||
private static final boolean OKHTTP_CLIENT_PRESENT = ClassUtils.isPresent(OKHTTP_CLIENT_CLASS, null);
|
||||
|
||||
private ClientHttpRequestFactories() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new {@link ClientHttpRequestFactory} instance using the most appropriate
|
||||
* implementation.
|
||||
* @param settings the settings to apply
|
||||
* @return a new {@link ClientHttpRequestFactory}
|
||||
*/
|
||||
public static ClientHttpRequestFactory get(ClientHttpRequestFactorySettings settings) {
|
||||
Assert.notNull(settings, "Settings must not be null");
|
||||
if (APACHE_HTTP_CLIENT_PRESENT) {
|
||||
return HttpComponents.get(settings);
|
||||
}
|
||||
if (OKHTTP_CLIENT_PRESENT) {
|
||||
return OkHttp.get(settings);
|
||||
}
|
||||
return Simple.get(settings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new {@link ClientHttpRequestFactory} of the given type, applying
|
||||
* {@link ClientHttpRequestFactorySettings} using reflection if necessary.
|
||||
* @param <T> the {@link ClientHttpRequestFactory} type
|
||||
* @param requestFactoryType the {@link ClientHttpRequestFactory} type
|
||||
* @param settings the settings to apply
|
||||
* @return a new {@link ClientHttpRequestFactory} instance
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T extends ClientHttpRequestFactory> T get(Class<T> requestFactoryType,
|
||||
ClientHttpRequestFactorySettings settings) {
|
||||
Assert.notNull(settings, "Settings must not be null");
|
||||
if (requestFactoryType == ClientHttpRequestFactory.class) {
|
||||
return (T) get(settings);
|
||||
}
|
||||
if (requestFactoryType == HttpComponentsClientHttpRequestFactory.class) {
|
||||
return (T) HttpComponents.get(settings);
|
||||
}
|
||||
if (requestFactoryType == OkHttp3ClientHttpRequestFactory.class) {
|
||||
return (T) OkHttp.get(settings);
|
||||
}
|
||||
if (requestFactoryType == SimpleClientHttpRequestFactory.class) {
|
||||
return (T) Simple.get(settings);
|
||||
}
|
||||
return get(() -> createRequestFactory(requestFactoryType), settings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new {@link ClientHttpRequestFactory} from the given supplier, applying
|
||||
* {@link ClientHttpRequestFactorySettings} using reflection.
|
||||
* @param <T> the {@link ClientHttpRequestFactory} type
|
||||
* @param requestFactorySupplier the {@link ClientHttpRequestFactory} supplier
|
||||
* @param settings the settings to apply
|
||||
* @return a new {@link ClientHttpRequestFactory} instance
|
||||
*/
|
||||
public static <T extends ClientHttpRequestFactory> T get(Supplier<T> requestFactorySupplier,
|
||||
ClientHttpRequestFactorySettings settings) {
|
||||
return Reflective.get(requestFactorySupplier, settings);
|
||||
}
|
||||
|
||||
private static <T extends ClientHttpRequestFactory> T createRequestFactory(Class<T> requestFactory) {
|
||||
try {
|
||||
Constructor<T> constructor = requestFactory.getDeclaredConstructor();
|
||||
constructor.setAccessible(true);
|
||||
return constructor.newInstance();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Support for {@link HttpComponentsClientHttpRequestFactory}.
|
||||
*/
|
||||
static class HttpComponents {
|
||||
|
||||
static HttpComponentsClientHttpRequestFactory get(ClientHttpRequestFactorySettings settings) {
|
||||
HttpComponentsClientHttpRequestFactory requestFactory = createRequestFactory(settings.readTimeout());
|
||||
PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
|
||||
map.from(settings::connectTimeout).asInt(Duration::toMillis).to(requestFactory::setConnectTimeout);
|
||||
map.from(settings::bufferRequestBody).to(requestFactory::setBufferRequestBody);
|
||||
return requestFactory;
|
||||
}
|
||||
|
||||
private static HttpComponentsClientHttpRequestFactory createRequestFactory(Duration readTimeout) {
|
||||
return (readTimeout != null) ? new HttpComponentsClientHttpRequestFactory(createHttpClient(readTimeout))
|
||||
: new HttpComponentsClientHttpRequestFactory();
|
||||
}
|
||||
|
||||
private static HttpClient createHttpClient(Duration readTimeout) {
|
||||
SocketConfig socketConfig = SocketConfig.custom()
|
||||
.setSoTimeout((int) readTimeout.toMillis(), TimeUnit.MILLISECONDS).build();
|
||||
PoolingHttpClientConnectionManager connectionManager = PoolingHttpClientConnectionManagerBuilder.create()
|
||||
.setDefaultSocketConfig(socketConfig).build();
|
||||
return HttpClientBuilder.create().setConnectionManager(connectionManager).build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Support for {@link OkHttp3ClientHttpRequestFactory}.
|
||||
*/
|
||||
static class OkHttp {
|
||||
|
||||
static OkHttp3ClientHttpRequestFactory get(ClientHttpRequestFactorySettings settings) {
|
||||
Assert.state(settings.bufferRequestBody() == null,
|
||||
() -> "OkHttp3ClientHttpRequestFactory does not support request body buffering");
|
||||
OkHttp3ClientHttpRequestFactory requestFactory = new OkHttp3ClientHttpRequestFactory();
|
||||
PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
|
||||
map.from(settings::connectTimeout).asInt(Duration::toMillis).to(requestFactory::setConnectTimeout);
|
||||
map.from(settings::readTimeout).asInt(Duration::toMillis).to(requestFactory::setReadTimeout);
|
||||
return requestFactory;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Support for {@link SimpleClientHttpRequestFactory}.
|
||||
*/
|
||||
static class Simple {
|
||||
|
||||
static SimpleClientHttpRequestFactory get(ClientHttpRequestFactorySettings settings) {
|
||||
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
|
||||
PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
|
||||
map.from(settings::readTimeout).asInt(Duration::toMillis).to(requestFactory::setReadTimeout);
|
||||
map.from(settings::connectTimeout).asInt(Duration::toMillis).to(requestFactory::setConnectTimeout);
|
||||
map.from(settings::bufferRequestBody).to(requestFactory::setBufferRequestBody);
|
||||
return requestFactory;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Support for reflective configuration of an unknown {@link ClientHttpRequestFactory}
|
||||
* implementation.
|
||||
*/
|
||||
static class Reflective {
|
||||
|
||||
static <T extends ClientHttpRequestFactory> T get(Supplier<T> requestFactorySupplier,
|
||||
ClientHttpRequestFactorySettings settings) {
|
||||
T requestFactory = requestFactorySupplier.get();
|
||||
configure(requestFactory, settings);
|
||||
return requestFactory;
|
||||
}
|
||||
|
||||
private static void configure(ClientHttpRequestFactory requestFactory,
|
||||
ClientHttpRequestFactorySettings settings) {
|
||||
ClientHttpRequestFactory unwrapped = unwrapRequestFactoryIfNecessary(requestFactory);
|
||||
PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
|
||||
map.from(settings::connectTimeout).to((connectTimeout) -> setConnectTimeout(unwrapped, connectTimeout));
|
||||
map.from(settings::readTimeout).to((readTimeout) -> setReadTimeout(unwrapped, readTimeout));
|
||||
map.from(settings::bufferRequestBody)
|
||||
.to((bufferRequestBody) -> setBufferRequestBody(unwrapped, bufferRequestBody));
|
||||
}
|
||||
|
||||
private static ClientHttpRequestFactory unwrapRequestFactoryIfNecessary(
|
||||
ClientHttpRequestFactory requestFactory) {
|
||||
if (!(requestFactory instanceof AbstractClientHttpRequestFactoryWrapper)) {
|
||||
return requestFactory;
|
||||
}
|
||||
Field field = ReflectionUtils.findField(AbstractClientHttpRequestFactoryWrapper.class, "requestFactory");
|
||||
ReflectionUtils.makeAccessible(field);
|
||||
ClientHttpRequestFactory unwrappedRequestFactory = requestFactory;
|
||||
while (unwrappedRequestFactory instanceof AbstractClientHttpRequestFactoryWrapper) {
|
||||
unwrappedRequestFactory = (ClientHttpRequestFactory) ReflectionUtils.getField(field,
|
||||
unwrappedRequestFactory);
|
||||
}
|
||||
return unwrappedRequestFactory;
|
||||
}
|
||||
|
||||
private static void setConnectTimeout(ClientHttpRequestFactory factory, Duration connectTimeout) {
|
||||
Method 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);
|
||||
int timeout = Math.toIntExact(readTimeout.toMillis());
|
||||
invoke(factory, method, timeout);
|
||||
}
|
||||
|
||||
private static void setBufferRequestBody(ClientHttpRequestFactory factory, boolean bufferRequestBody) {
|
||||
Method method = findMethod(factory, "setBufferRequestBody", boolean.class);
|
||||
invoke(factory, method, bufferRequestBody);
|
||||
}
|
||||
|
||||
private static Method findMethod(ClientHttpRequestFactory requestFactory, String methodName,
|
||||
Class<?>... parameters) {
|
||||
Method method = ReflectionUtils.findMethod(requestFactory.getClass(), methodName, parameters);
|
||||
Assert.state(method != null, () -> "Request factory %s does not have a suitable %s method"
|
||||
.formatted(requestFactory.getClass().getName(), methodName));
|
||||
Assert.state(!method.isAnnotationPresent(Deprecated.class),
|
||||
() -> "Request factory %s has the %s method marked as deprecated"
|
||||
.formatted(requestFactory.getClass().getName(), methodName));
|
||||
return method;
|
||||
}
|
||||
|
||||
private static void invoke(ClientHttpRequestFactory requestFactory, Method method, Object... parameters) {
|
||||
ReflectionUtils.invokeMethod(method, requestFactory, parameters);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright 2012-2022 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.lang.reflect.Field;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.springframework.aot.hint.ExecutableMode;
|
||||
import org.springframework.aot.hint.ReflectionHints;
|
||||
import org.springframework.aot.hint.RuntimeHints;
|
||||
import org.springframework.aot.hint.RuntimeHintsRegistrar;
|
||||
import org.springframework.aot.hint.TypeHint;
|
||||
import org.springframework.aot.hint.TypeReference;
|
||||
import org.springframework.http.client.AbstractClientHttpRequestFactoryWrapper;
|
||||
import org.springframework.http.client.ClientHttpRequestFactory;
|
||||
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
|
||||
import org.springframework.http.client.OkHttp3ClientHttpRequestFactory;
|
||||
import org.springframework.http.client.SimpleClientHttpRequestFactory;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* {@link RuntimeHintsRegistrar} for {@link ClientHttpRequestFactories}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class ClientHttpRequestFactoriesRuntimeHints implements RuntimeHintsRegistrar {
|
||||
|
||||
@Override
|
||||
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
|
||||
if (ClassUtils.isPresent("org.springframework.http.client.ClientHttpRequestFactory", classLoader)) {
|
||||
registerHints(hints.reflection(), classLoader);
|
||||
}
|
||||
}
|
||||
|
||||
private void registerHints(ReflectionHints hints, ClassLoader classLoader) {
|
||||
hints.registerField(findField(AbstractClientHttpRequestFactoryWrapper.class, "requestFactory"));
|
||||
if (ClassUtils.isPresent(ClientHttpRequestFactories.APACHE_HTTP_CLIENT_CLASS, classLoader)) {
|
||||
registerReflectionHints(hints, HttpComponentsClientHttpRequestFactory.class, this::onReachableHttpClient);
|
||||
}
|
||||
if (ClassUtils.isPresent(ClientHttpRequestFactories.OKHTTP_CLIENT_CLASS, classLoader)) {
|
||||
registerReflectionHints(hints, OkHttp3ClientHttpRequestFactory.class, this::onReachableOkHttpClient);
|
||||
}
|
||||
registerReflectionHints(hints, SimpleClientHttpRequestFactory.class, this::onReachableHttpUrlConnection);
|
||||
}
|
||||
|
||||
private void onReachableHttpUrlConnection(TypeHint.Builder typeHint) {
|
||||
typeHint.onReachableType(HttpURLConnection.class);
|
||||
}
|
||||
|
||||
private void onReachableHttpClient(TypeHint.Builder typeHint) {
|
||||
typeHint.onReachableType(TypeReference.of(ClientHttpRequestFactories.APACHE_HTTP_CLIENT_CLASS));
|
||||
}
|
||||
|
||||
private void onReachableOkHttpClient(TypeHint.Builder typeHint) {
|
||||
typeHint.onReachableType(TypeReference.of(ClientHttpRequestFactories.OKHTTP_CLIENT_CLASS));
|
||||
}
|
||||
|
||||
private void registerReflectionHints(ReflectionHints hints,
|
||||
Class<? extends ClientHttpRequestFactory> requestFactoryType, Consumer<TypeHint.Builder> hintCustomizer) {
|
||||
hints.registerType(requestFactoryType, (typeHint) -> {
|
||||
typeHint.withMethod("setConnectTimeout", TypeReference.listOf(int.class), ExecutableMode.INVOKE);
|
||||
typeHint.withMethod("setReadTimeout", TypeReference.listOf(int.class), ExecutableMode.INVOKE);
|
||||
typeHint.withMethod("setBufferRequestBody", TypeReference.listOf(boolean.class), ExecutableMode.INVOKE);
|
||||
hintCustomizer.accept(typeHint);
|
||||
});
|
||||
}
|
||||
|
||||
private Field findField(Class<?> type, String name) {
|
||||
Field field = ReflectionUtils.findField(type, name);
|
||||
Assert.state(field != null, () -> "Unable to find field '%s' on %s".formatted(type.getName(), name));
|
||||
return field;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2012-2022 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.time.Duration;
|
||||
|
||||
import org.springframework.http.client.ClientHttpRequestFactory;
|
||||
|
||||
/**
|
||||
* Settings that can be applied when creating a {@link ClientHttpRequestFactory}.
|
||||
* @param connectTimeout the connect timeout
|
||||
* @param readTimeout the read timeout
|
||||
* @param bufferRequestBody if request body buffering is used
|
||||
* @author Andy Wilkinson
|
||||
* @author Phillip Webb
|
||||
* @since 3.0.0
|
||||
* @see ClientHttpRequestFactories
|
||||
*/
|
||||
public record ClientHttpRequestFactorySettings(Duration connectTimeout, Duration readTimeout,
|
||||
Boolean bufferRequestBody) {
|
||||
|
||||
/**
|
||||
* Use defaults for the {@link ClientHttpRequestFactory} which can differ depending on
|
||||
* the implementation.
|
||||
*/
|
||||
public static final ClientHttpRequestFactorySettings DEFAULTS = new ClientHttpRequestFactorySettings(null, null,
|
||||
null);
|
||||
|
||||
/**
|
||||
* Return a new {@link ClientHttpRequestFactorySettings} instance with an updated
|
||||
* connect timeout setting .
|
||||
* @param connectTimeout the new connect timeout setting
|
||||
* @return a new {@link ClientHttpRequestFactorySettings} instance
|
||||
*/
|
||||
public ClientHttpRequestFactorySettings withConnectTimeout(Duration connectTimeout) {
|
||||
return new ClientHttpRequestFactorySettings(connectTimeout, this.readTimeout, this.bufferRequestBody);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new {@link ClientHttpRequestFactorySettings} instance with an updated read
|
||||
* timeout setting.
|
||||
* @param readTimeout the new read timeout setting
|
||||
* @return a new {@link ClientHttpRequestFactorySettings} instance
|
||||
*/
|
||||
|
||||
public ClientHttpRequestFactorySettings withReadTimeout(Duration readTimeout) {
|
||||
return new ClientHttpRequestFactorySettings(this.connectTimeout, readTimeout, this.bufferRequestBody);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new {@link ClientHttpRequestFactorySettings} instance with an updated
|
||||
* buffer request body setting.
|
||||
* @param bufferRequestBody the new buffer request body setting
|
||||
* @return a new {@link ClientHttpRequestFactorySettings} instance
|
||||
*/
|
||||
public ClientHttpRequestFactorySettings withBufferRequestBody(Boolean bufferRequestBody) {
|
||||
return new ClientHttpRequestFactorySettings(this.connectTimeout, this.readTimeout, bufferRequestBody);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright 2012-2022 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.time.Duration;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.http.client.ClientHttpRequestFactory;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Base classes for testing of {@link ClientHttpRequestFactories} with different HTTP
|
||||
* clients on the classpath.
|
||||
*
|
||||
* @param <T> the {@link ClientHttpRequestFactory} to be produced
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
abstract class AbstractClientHttpRequestFactoriesTests<T extends ClientHttpRequestFactory> {
|
||||
|
||||
private final Class<T> requestFactoryType;
|
||||
|
||||
protected AbstractClientHttpRequestFactoriesTests(Class<T> requestFactoryType) {
|
||||
this.requestFactoryType = requestFactoryType;
|
||||
}
|
||||
|
||||
@Test
|
||||
void getReturnsRequestFactoryOfExpectedType() {
|
||||
ClientHttpRequestFactory requestFactory = ClientHttpRequestFactories
|
||||
.get(ClientHttpRequestFactorySettings.DEFAULTS);
|
||||
assertThat(requestFactory).isInstanceOf(this.requestFactoryType);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getOfGeneralTypeReturnsRequestFactoryOfExpectedType() {
|
||||
ClientHttpRequestFactory requestFactory = ClientHttpRequestFactories.get(ClientHttpRequestFactory.class,
|
||||
ClientHttpRequestFactorySettings.DEFAULTS);
|
||||
assertThat(requestFactory).isInstanceOf(this.requestFactoryType);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getOfSpecificTypeReturnsRequestFactoryOfExpectedType() {
|
||||
ClientHttpRequestFactory requestFactory = ClientHttpRequestFactories.get(this.requestFactoryType,
|
||||
ClientHttpRequestFactorySettings.DEFAULTS);
|
||||
assertThat(requestFactory).isInstanceOf(this.requestFactoryType);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
void getReturnsRequestFactoryWithConfiguredConnectTimeout() {
|
||||
ClientHttpRequestFactory requestFactory = ClientHttpRequestFactories
|
||||
.get(ClientHttpRequestFactorySettings.DEFAULTS.withConnectTimeout(Duration.ofSeconds(60)));
|
||||
assertThat(connectTimeout((T) requestFactory)).isEqualTo(Duration.ofSeconds(60).toMillis());
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
void getReturnsRequestFactoryWithConfiguredReadTimeout() {
|
||||
ClientHttpRequestFactory requestFactory = ClientHttpRequestFactories
|
||||
.get(ClientHttpRequestFactorySettings.DEFAULTS.withReadTimeout(Duration.ofSeconds(120)));
|
||||
assertThat(readTimeout((T) requestFactory)).isEqualTo(Duration.ofSeconds(120).toMillis());
|
||||
}
|
||||
|
||||
protected abstract long connectTimeout(T requestFactory);
|
||||
|
||||
protected abstract long readTimeout(T requestFactory);
|
||||
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2012-2022 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.time.Duration;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.http.client.ClientHttpRequestFactory;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Base class for tests that verify the configuration of the
|
||||
* {@link ClientHttpRequestFactory} used by {@link RestTemplateBuilder}.
|
||||
*
|
||||
* @param <T> the request factory type under test
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
abstract class AbstractRestTemplateBuilderRequestFactoryConfigurationTests<T extends ClientHttpRequestFactory> {
|
||||
|
||||
private final Class<? extends ClientHttpRequestFactory> factoryType;
|
||||
|
||||
private final RestTemplateBuilder builder = new RestTemplateBuilder();
|
||||
|
||||
protected AbstractRestTemplateBuilderRequestFactoryConfigurationTests(Class<T> factoryType) {
|
||||
this.factoryType = factoryType;
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
void connectTimeoutCanBeConfiguredOnFactory() {
|
||||
ClientHttpRequestFactory requestFactory = this.builder.requestFactory(this.factoryType)
|
||||
.setConnectTimeout(Duration.ofMillis(1234)).build().getRequestFactory();
|
||||
assertThat(connectTimeout((T) requestFactory)).isEqualTo(1234);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
void readTimeoutCanBeConfiguredOnFactory() {
|
||||
ClientHttpRequestFactory requestFactory = this.builder.requestFactory(this.factoryType)
|
||||
.setReadTimeout(Duration.ofMillis(1234)).build().getRequestFactory();
|
||||
assertThat(readTimeout((T) requestFactory)).isEqualTo(1234);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
void connectTimeoutCanBeConfiguredOnDetectedFactory() {
|
||||
ClientHttpRequestFactory requestFactory = this.builder.setConnectTimeout(Duration.ofMillis(1234)).build()
|
||||
.getRequestFactory();
|
||||
assertThat(connectTimeout((T) requestFactory)).isEqualTo(1234);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
void readTimeoutCanBeConfiguredOnDetectedFactory() {
|
||||
ClientHttpRequestFactory requestFactory = this.builder.setReadTimeout(Duration.ofMillis(1234)).build()
|
||||
.getRequestFactory();
|
||||
assertThat(readTimeout((T) requestFactory)).isEqualTo(1234);
|
||||
}
|
||||
|
||||
protected abstract long connectTimeout(T requestFactory);
|
||||
|
||||
protected abstract long readTimeout(T requestFactory);
|
||||
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2012-2022 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 org.apache.hc.client5.http.classic.HttpClient;
|
||||
import org.apache.hc.core5.http.io.SocketConfig;
|
||||
|
||||
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
/**
|
||||
* Tests for {@link ClientHttpRequestFactories} when Apache Http Components is the
|
||||
* predominant HTTP client.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class ClientHttpRequestFactoriesHttpComponentsTests
|
||||
extends AbstractClientHttpRequestFactoriesTests<HttpComponentsClientHttpRequestFactory> {
|
||||
|
||||
ClientHttpRequestFactoriesHttpComponentsTests() {
|
||||
super(HttpComponentsClientHttpRequestFactory.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long connectTimeout(HttpComponentsClientHttpRequestFactory requestFactory) {
|
||||
return (int) ReflectionTestUtils.getField(requestFactory, "connectTimeout");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long readTimeout(HttpComponentsClientHttpRequestFactory requestFactory) {
|
||||
HttpClient httpClient = requestFactory.getHttpClient();
|
||||
Object connectionManager = ReflectionTestUtils.getField(httpClient, "connManager");
|
||||
SocketConfig socketConfig = (SocketConfig) ReflectionTestUtils.getField(connectionManager,
|
||||
"defaultSocketConfig");
|
||||
return socketConfig.getSoTimeout().toMilliseconds();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright 2012-2022 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.io.File;
|
||||
|
||||
import okhttp3.OkHttpClient;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.testsupport.classpath.ClassPathExclusions;
|
||||
import org.springframework.boot.testsupport.classpath.ClassPathOverrides;
|
||||
import org.springframework.http.client.OkHttp3ClientHttpRequestFactory;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
|
||||
/**
|
||||
* Tests for {@link ClientHttpRequestFactories} when OkHttp 3 is the predominant HTTP
|
||||
* client.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@ClassPathOverrides("com.squareup.okhttp3:okhttp:3.14.9")
|
||||
@ClassPathExclusions("httpclient5-*.jar")
|
||||
class ClientHttpRequestFactoriesOkHttp3Tests
|
||||
extends AbstractClientHttpRequestFactoriesTests<OkHttp3ClientHttpRequestFactory> {
|
||||
|
||||
ClientHttpRequestFactoriesOkHttp3Tests() {
|
||||
super(OkHttp3ClientHttpRequestFactory.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void okHttp3IsBeingUsed() {
|
||||
assertThat(new File(OkHttpClient.class.getProtectionDomain().getCodeSource().getLocation().getFile()).getName())
|
||||
.startsWith("okhttp-3.");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getFailsWhenBufferRequestBodyIsEnabled() {
|
||||
assertThatIllegalStateException().isThrownBy(() -> ClientHttpRequestFactories
|
||||
.get(ClientHttpRequestFactorySettings.DEFAULTS.withBufferRequestBody(true)));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long connectTimeout(OkHttp3ClientHttpRequestFactory requestFactory) {
|
||||
return ((OkHttpClient) ReflectionTestUtils.getField(requestFactory, "client")).connectTimeoutMillis();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long readTimeout(OkHttp3ClientHttpRequestFactory requestFactory) {
|
||||
return ((OkHttpClient) ReflectionTestUtils.getField(requestFactory, "client")).readTimeoutMillis();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 2012-2022 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.io.File;
|
||||
|
||||
import okhttp3.OkHttpClient;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.testsupport.classpath.ClassPathExclusions;
|
||||
import org.springframework.http.client.OkHttp3ClientHttpRequestFactory;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
|
||||
/**
|
||||
* Tests for {@link ClientHttpRequestFactories} when OkHttp 4 is the predominant HTTP
|
||||
* client.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@ClassPathExclusions("httpclient5-*.jar")
|
||||
class ClientHttpRequestFactoriesOkHttp4Tests
|
||||
extends AbstractClientHttpRequestFactoriesTests<OkHttp3ClientHttpRequestFactory> {
|
||||
|
||||
ClientHttpRequestFactoriesOkHttp4Tests() {
|
||||
super(OkHttp3ClientHttpRequestFactory.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void okHttp4IsBeingUsed() {
|
||||
assertThat(new File(OkHttpClient.class.getProtectionDomain().getCodeSource().getLocation().getFile()).getName())
|
||||
.startsWith("okhttp-4.");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getFailsWhenBufferRequestBodyIsEnabled() {
|
||||
assertThatIllegalStateException().isThrownBy(() -> ClientHttpRequestFactories
|
||||
.get(ClientHttpRequestFactorySettings.DEFAULTS.withBufferRequestBody(true)));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long connectTimeout(OkHttp3ClientHttpRequestFactory requestFactory) {
|
||||
return ((OkHttpClient) ReflectionTestUtils.getField(requestFactory, "client")).connectTimeoutMillis();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long readTimeout(OkHttp3ClientHttpRequestFactory requestFactory) {
|
||||
return ((OkHttpClient) ReflectionTestUtils.getField(requestFactory, "client")).readTimeoutMillis();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright 2012-2022 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 org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.aot.hint.RuntimeHints;
|
||||
import org.springframework.aot.hint.predicate.ReflectionHintsPredicates;
|
||||
import org.springframework.aot.hint.predicate.RuntimeHintsPredicates;
|
||||
import org.springframework.http.client.AbstractClientHttpRequestFactoryWrapper;
|
||||
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
|
||||
import org.springframework.http.client.OkHttp3ClientHttpRequestFactory;
|
||||
import org.springframework.http.client.SimpleClientHttpRequestFactory;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link ClientHttpRequestFactoriesRuntimeHints}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class ClientHttpRequestFactoriesRuntimeHintsTests {
|
||||
|
||||
@Test
|
||||
void shouldRegisterHints() {
|
||||
RuntimeHints hints = new RuntimeHints();
|
||||
new ClientHttpRequestFactoriesRuntimeHints().registerHints(hints, getClass().getClassLoader());
|
||||
ReflectionHintsPredicates reflection = RuntimeHintsPredicates.reflection();
|
||||
assertThat(reflection
|
||||
.onField(ReflectionUtils.findField(AbstractClientHttpRequestFactoryWrapper.class, "requestFactory")))
|
||||
.accepts(hints);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRegisterHttpComponentHints() {
|
||||
RuntimeHints hints = new RuntimeHints();
|
||||
new ClientHttpRequestFactoriesRuntimeHints().registerHints(hints, getClass().getClassLoader());
|
||||
ReflectionHintsPredicates reflection = RuntimeHintsPredicates.reflection();
|
||||
assertThat(reflection.onMethod(ReflectionUtils.findMethod(HttpComponentsClientHttpRequestFactory.class,
|
||||
"setConnectTimeout", int.class))).accepts(hints);
|
||||
assertThat(reflection.onMethod(
|
||||
ReflectionUtils.findMethod(HttpComponentsClientHttpRequestFactory.class, "setReadTimeout", int.class)))
|
||||
.accepts(hints);
|
||||
assertThat(reflection.onMethod(ReflectionUtils.findMethod(HttpComponentsClientHttpRequestFactory.class,
|
||||
"setBufferRequestBody", boolean.class))).accepts(hints);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRegisterOkHttpHints() {
|
||||
RuntimeHints hints = new RuntimeHints();
|
||||
new ClientHttpRequestFactoriesRuntimeHints().registerHints(hints, getClass().getClassLoader());
|
||||
ReflectionHintsPredicates reflection = RuntimeHintsPredicates.reflection();
|
||||
assertThat(reflection.onMethod(
|
||||
ReflectionUtils.findMethod(OkHttp3ClientHttpRequestFactory.class, "setConnectTimeout", int.class)))
|
||||
.accepts(hints);
|
||||
assertThat(reflection.onMethod(
|
||||
ReflectionUtils.findMethod(OkHttp3ClientHttpRequestFactory.class, "setReadTimeout", int.class)))
|
||||
.accepts(hints);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRegisterSimpleHttpHints() {
|
||||
RuntimeHints hints = new RuntimeHints();
|
||||
new ClientHttpRequestFactoriesRuntimeHints().registerHints(hints, getClass().getClassLoader());
|
||||
ReflectionHintsPredicates reflection = RuntimeHintsPredicates.reflection();
|
||||
assertThat(reflection.onMethod(
|
||||
ReflectionUtils.findMethod(SimpleClientHttpRequestFactory.class, "setConnectTimeout", int.class)))
|
||||
.accepts(hints);
|
||||
assertThat(reflection.onMethod(
|
||||
ReflectionUtils.findMethod(SimpleClientHttpRequestFactory.class, "setReadTimeout", int.class)))
|
||||
.accepts(hints);
|
||||
assertThat(reflection.onMethod(ReflectionUtils.findMethod(SimpleClientHttpRequestFactory.class,
|
||||
"setBufferRequestBody", boolean.class))).accepts(hints);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2012-2022 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 org.springframework.boot.testsupport.classpath.ClassPathExclusions;
|
||||
import org.springframework.http.client.SimpleClientHttpRequestFactory;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
/**
|
||||
* Tests for {@link ClientHttpRequestFactories} when the simple JDK-based client is the
|
||||
* predominant HTTP client.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@ClassPathExclusions({ "httpclient5-*.jar", "okhttp-*.jar" })
|
||||
class ClientHttpRequestFactoriesSimpleTests
|
||||
extends AbstractClientHttpRequestFactoriesTests<SimpleClientHttpRequestFactory> {
|
||||
|
||||
ClientHttpRequestFactoriesSimpleTests() {
|
||||
super(SimpleClientHttpRequestFactory.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long connectTimeout(SimpleClientHttpRequestFactory requestFactory) {
|
||||
return (int) ReflectionTestUtils.getField(requestFactory, "connectTimeout");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long readTimeout(SimpleClientHttpRequestFactory requestFactory) {
|
||||
return (int) ReflectionTestUtils.getField(requestFactory, "readTimeout");
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,247 @@
|
||||
/*
|
||||
* Copyright 2012-2022 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.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.time.Duration;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.client.BufferingClientHttpRequestFactory;
|
||||
import org.springframework.http.client.ClientHttpRequest;
|
||||
import org.springframework.http.client.ClientHttpRequestFactory;
|
||||
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
|
||||
import org.springframework.http.client.OkHttp3ClientHttpRequestFactory;
|
||||
import org.springframework.http.client.SimpleClientHttpRequestFactory;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
|
||||
/**
|
||||
* Tests for {@link ClientHttpRequestFactories}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class ClientHttpRequestFactoriesTests {
|
||||
|
||||
@Test
|
||||
void getReturnsRequestFactoryOfExpectedType() {
|
||||
ClientHttpRequestFactory requestFactory = ClientHttpRequestFactories
|
||||
.get(ClientHttpRequestFactorySettings.DEFAULTS);
|
||||
assertThat(requestFactory).isInstanceOf(HttpComponentsClientHttpRequestFactory.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getOfGeneralTypeReturnsRequestFactoryOfExpectedType() {
|
||||
ClientHttpRequestFactory requestFactory = ClientHttpRequestFactories.get(ClientHttpRequestFactory.class,
|
||||
ClientHttpRequestFactorySettings.DEFAULTS);
|
||||
assertThat(requestFactory).isInstanceOf(HttpComponentsClientHttpRequestFactory.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getOfSimpleFactoryReturnsSimpleFactory() {
|
||||
ClientHttpRequestFactory requestFactory = ClientHttpRequestFactories.get(SimpleClientHttpRequestFactory.class,
|
||||
ClientHttpRequestFactorySettings.DEFAULTS);
|
||||
assertThat(requestFactory).isInstanceOf(SimpleClientHttpRequestFactory.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getOfHttpComponentsFactoryReturnsHttpComponentsFactory() {
|
||||
ClientHttpRequestFactory requestFactory = ClientHttpRequestFactories
|
||||
.get(HttpComponentsClientHttpRequestFactory.class, ClientHttpRequestFactorySettings.DEFAULTS);
|
||||
assertThat(requestFactory).isInstanceOf(HttpComponentsClientHttpRequestFactory.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getOfOkHttpFactoryReturnsOkHttpFactory() {
|
||||
ClientHttpRequestFactory requestFactory = ClientHttpRequestFactories.get(OkHttp3ClientHttpRequestFactory.class,
|
||||
ClientHttpRequestFactorySettings.DEFAULTS);
|
||||
assertThat(requestFactory).isInstanceOf(OkHttp3ClientHttpRequestFactory.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getOfUnknownTypeCreatesFactory() {
|
||||
ClientHttpRequestFactory requestFactory = ClientHttpRequestFactories.get(TestClientHttpRequestFactory.class,
|
||||
ClientHttpRequestFactorySettings.DEFAULTS);
|
||||
assertThat(requestFactory).isInstanceOf(TestClientHttpRequestFactory.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getOfUnknownTypeWithConnectTimeoutCreatesFactoryAndConfiguresConnectTimeout() {
|
||||
ClientHttpRequestFactory requestFactory = ClientHttpRequestFactories.get(TestClientHttpRequestFactory.class,
|
||||
ClientHttpRequestFactorySettings.DEFAULTS.withConnectTimeout(Duration.ofSeconds(60)));
|
||||
assertThat(requestFactory).isInstanceOf(TestClientHttpRequestFactory.class);
|
||||
assertThat(((TestClientHttpRequestFactory) requestFactory).connectTimeout)
|
||||
.isEqualTo(Duration.ofSeconds(60).toMillis());
|
||||
}
|
||||
|
||||
@Test
|
||||
void getOfUnknownTypeWithReadTimeoutCreatesFactoryAndConfiguresReadTimeout() {
|
||||
ClientHttpRequestFactory requestFactory = ClientHttpRequestFactories.get(TestClientHttpRequestFactory.class,
|
||||
ClientHttpRequestFactorySettings.DEFAULTS.withReadTimeout(Duration.ofSeconds(90)));
|
||||
assertThat(requestFactory).isInstanceOf(TestClientHttpRequestFactory.class);
|
||||
assertThat(((TestClientHttpRequestFactory) requestFactory).readTimeout)
|
||||
.isEqualTo(Duration.ofSeconds(90).toMillis());
|
||||
}
|
||||
|
||||
@Test
|
||||
void getOfUnknownTypeWithBodyBufferingCreatesFactoryAndConfiguresBodyBuffering() {
|
||||
ClientHttpRequestFactory requestFactory = ClientHttpRequestFactories.get(TestClientHttpRequestFactory.class,
|
||||
ClientHttpRequestFactorySettings.DEFAULTS.withBufferRequestBody(true));
|
||||
assertThat(requestFactory).isInstanceOf(TestClientHttpRequestFactory.class);
|
||||
assertThat(((TestClientHttpRequestFactory) requestFactory).bufferRequestBody).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void getOfUnconfigurableTypeWithConnectTimeoutThrows() {
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(() -> ClientHttpRequestFactories.get(UnconfigurableClientHttpRequestFactory.class,
|
||||
ClientHttpRequestFactorySettings.DEFAULTS.withConnectTimeout(Duration.ofSeconds(60))))
|
||||
.withMessageContaining("suitable setConnectTimeout method");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getOfUnconfigurableTypeWithReadTimeoutThrows() {
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(() -> ClientHttpRequestFactories.get(UnconfigurableClientHttpRequestFactory.class,
|
||||
ClientHttpRequestFactorySettings.DEFAULTS.withReadTimeout(Duration.ofSeconds(60))))
|
||||
.withMessageContaining("suitable setReadTimeout method");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getOfUnconfigurableTypeWithBodyBufferingThrows() {
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(() -> ClientHttpRequestFactories.get(UnconfigurableClientHttpRequestFactory.class,
|
||||
ClientHttpRequestFactorySettings.DEFAULTS.withBufferRequestBody(true)))
|
||||
.withMessageContaining("suitable setBufferRequestBody method");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getOfTypeWithDeprecatedConnectTimeoutThrowsWithConnectTimeout() {
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(() -> ClientHttpRequestFactories.get(DeprecatedMethodsClientHttpRequestFactory.class,
|
||||
ClientHttpRequestFactorySettings.DEFAULTS.withConnectTimeout(Duration.ofSeconds(60))))
|
||||
.withMessageContaining("setConnectTimeout method marked as deprecated");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getOfTypeWithDeprecatedReadTimeoutThrowsWithReadTimeout() {
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(() -> ClientHttpRequestFactories.get(DeprecatedMethodsClientHttpRequestFactory.class,
|
||||
ClientHttpRequestFactorySettings.DEFAULTS.withReadTimeout(Duration.ofSeconds(60))))
|
||||
.withMessageContaining("setReadTimeout method marked as deprecated");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getOfTypeWithDeprecatedBufferRequestBodyThrowsWithBufferRequestBody() {
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(() -> ClientHttpRequestFactories.get(DeprecatedMethodsClientHttpRequestFactory.class,
|
||||
ClientHttpRequestFactorySettings.DEFAULTS.withBufferRequestBody(false)))
|
||||
.withMessageContaining("setBufferRequestBody method marked as deprecated");
|
||||
}
|
||||
|
||||
@Test
|
||||
void connectTimeoutCanBeConfiguredOnAWrappedRequestFactory() {
|
||||
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
|
||||
BufferingClientHttpRequestFactory result = ClientHttpRequestFactories.get(
|
||||
() -> new BufferingClientHttpRequestFactory(requestFactory),
|
||||
ClientHttpRequestFactorySettings.DEFAULTS.withConnectTimeout(Duration.ofMillis(1234)));
|
||||
assertThat(result).extracting("requestFactory").isSameAs(requestFactory);
|
||||
assertThat(requestFactory).hasFieldOrPropertyWithValue("connectTimeout", 1234);
|
||||
}
|
||||
|
||||
@Test
|
||||
void readTimeoutCanBeConfiguredOnAWrappedRequestFactory() {
|
||||
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
|
||||
BufferingClientHttpRequestFactory result = ClientHttpRequestFactories.get(
|
||||
() -> new BufferingClientHttpRequestFactory(requestFactory),
|
||||
ClientHttpRequestFactorySettings.DEFAULTS.withReadTimeout(Duration.ofMillis(1234)));
|
||||
assertThat(result).extracting("requestFactory").isSameAs(requestFactory);
|
||||
assertThat(requestFactory).hasFieldOrPropertyWithValue("readTimeout", 1234);
|
||||
}
|
||||
|
||||
@Test
|
||||
void bufferRequestBodyCanBeConfiguredOnAWrappedRequestFactory() {
|
||||
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
|
||||
assertThat(requestFactory).hasFieldOrPropertyWithValue("bufferRequestBody", true);
|
||||
BufferingClientHttpRequestFactory result = ClientHttpRequestFactories.get(
|
||||
() -> new BufferingClientHttpRequestFactory(requestFactory),
|
||||
ClientHttpRequestFactorySettings.DEFAULTS.withBufferRequestBody(false));
|
||||
assertThat(result).extracting("requestFactory").isSameAs(requestFactory);
|
||||
assertThat(requestFactory).hasFieldOrPropertyWithValue("bufferRequestBody", false);
|
||||
}
|
||||
|
||||
public static class TestClientHttpRequestFactory implements ClientHttpRequestFactory {
|
||||
|
||||
private int connectTimeout;
|
||||
|
||||
private int readTimeout;
|
||||
|
||||
private boolean bufferRequestBody;
|
||||
|
||||
@Override
|
||||
public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public void setConnectTimeout(int timeout) {
|
||||
this.connectTimeout = timeout;
|
||||
}
|
||||
|
||||
public void setReadTimeout(int timeout) {
|
||||
this.readTimeout = timeout;
|
||||
}
|
||||
|
||||
public void setBufferRequestBody(boolean bufferRequestBody) {
|
||||
this.bufferRequestBody = bufferRequestBody;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class UnconfigurableClientHttpRequestFactory implements ClientHttpRequestFactory {
|
||||
|
||||
@Override
|
||||
public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class DeprecatedMethodsClientHttpRequestFactory implements ClientHttpRequestFactory {
|
||||
|
||||
@Override
|
||||
public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Deprecated(since = "3.0.0", forRemoval = false)
|
||||
public void setConnectTimeout(int timeout) {
|
||||
}
|
||||
|
||||
@Deprecated(since = "3.0.0", forRemoval = false)
|
||||
public void setReadTimeout(int timeout) {
|
||||
}
|
||||
|
||||
@Deprecated(since = "3.0.0", forRemoval = false)
|
||||
public void setBufferRequestBody(boolean bufferRequestBody) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright 2012-2022 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.time.Duration;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link ClientHttpRequestFactorySettings}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class ClientHttpRequestFactorySettingsTests {
|
||||
|
||||
private static final Duration ONE_SECOND = Duration.ofSeconds(1);
|
||||
|
||||
@Test
|
||||
void defaultsHasNullValues() {
|
||||
ClientHttpRequestFactorySettings settings = ClientHttpRequestFactorySettings.DEFAULTS;
|
||||
assertThat(settings.connectTimeout()).isNull();
|
||||
assertThat(settings.readTimeout()).isNull();
|
||||
assertThat(settings.bufferRequestBody()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void withConnectTimeoutReturnsInstanceWithUpdatedConnectionTimeout() {
|
||||
ClientHttpRequestFactorySettings settings = ClientHttpRequestFactorySettings.DEFAULTS
|
||||
.withConnectTimeout(ONE_SECOND);
|
||||
assertThat(settings.connectTimeout()).isEqualTo(ONE_SECOND);
|
||||
assertThat(settings.readTimeout()).isNull();
|
||||
assertThat(settings.bufferRequestBody()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void withReadTimeoutReturnsInstanceWithUpdatedReadTimeout() {
|
||||
ClientHttpRequestFactorySettings settings = ClientHttpRequestFactorySettings.DEFAULTS
|
||||
.withReadTimeout(ONE_SECOND);
|
||||
assertThat(settings.connectTimeout()).isNull();
|
||||
assertThat(settings.readTimeout()).isEqualTo(ONE_SECOND);
|
||||
assertThat(settings.bufferRequestBody()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void withBufferRequestBodyReturnsInstanceWithUpdatedBufferRequestBody() {
|
||||
ClientHttpRequestFactorySettings settings = ClientHttpRequestFactorySettings.DEFAULTS
|
||||
.withBufferRequestBody(true);
|
||||
assertThat(settings.connectTimeout()).isNull();
|
||||
assertThat(settings.readTimeout()).isNull();
|
||||
assertThat(settings.bufferRequestBody()).isTrue();
|
||||
}
|
||||
|
||||
}
|
@ -1,66 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2022 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.time.Duration;
|
||||
|
||||
import okhttp3.OkHttpClient;
|
||||
import org.assertj.core.api.InstanceOfAssertFactories;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.testsupport.classpath.ClassPathOverrides;
|
||||
import org.springframework.http.client.ClientHttpRequestFactory;
|
||||
import org.springframework.http.client.OkHttp3ClientHttpRequestFactory;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
|
||||
/**
|
||||
* Tests for {@link RestTemplateBuilder} with OkHttp 3.x.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@ClassPathOverrides("com.squareup.okhttp3:okhttp:3.14.9")
|
||||
class RestTemplateBuilderTestsOkHttp3Tests {
|
||||
|
||||
private RestTemplateBuilder builder = new RestTemplateBuilder();
|
||||
|
||||
@Test
|
||||
void connectTimeoutCanBeConfiguredOnOkHttpRequestFactory() {
|
||||
ClientHttpRequestFactory requestFactory = this.builder.requestFactory(OkHttp3ClientHttpRequestFactory.class)
|
||||
.setConnectTimeout(Duration.ofMillis(1234)).build().getRequestFactory();
|
||||
assertThat(requestFactory).extracting("client", InstanceOfAssertFactories.type(OkHttpClient.class))
|
||||
.extracting(OkHttpClient::connectTimeoutMillis).isEqualTo(1234);
|
||||
}
|
||||
|
||||
@Test
|
||||
void readTimeoutCanBeConfiguredOnOkHttpRequestFactory() {
|
||||
ClientHttpRequestFactory requestFactory = this.builder.requestFactory(OkHttp3ClientHttpRequestFactory.class)
|
||||
.setReadTimeout(Duration.ofMillis(1234)).build().getRequestFactory();
|
||||
assertThat(requestFactory).extracting("client", InstanceOfAssertFactories.type(OkHttpClient.class))
|
||||
.extracting(OkHttpClient::readTimeoutMillis).isEqualTo(1234);
|
||||
}
|
||||
|
||||
@Test
|
||||
void bufferRequestBodyCanNotBeConfiguredOnOkHttpRequestFactory() {
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(() -> this.builder.requestFactory(OkHttp3ClientHttpRequestFactory.class)
|
||||
.setBufferRequestBody(false).build().getRequestFactory())
|
||||
.withMessageContaining(OkHttp3ClientHttpRequestFactory.class.getName());
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue