mirror of
https://github.com/spring-projects/spring-boot.git
synced 2024-07-15 01:07:30 +08:00
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>
This commit is contained in:
parent
c22e76632c
commit
e6c37d698f
@ -18,16 +18,22 @@ package org.springframework.boot.test.web.client;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
import java.security.KeyManagementException;
|
||||||
|
import java.security.KeyStoreException;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.time.Duration;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import javax.net.ssl.SSLContext;
|
import javax.net.ssl.SSLContext;
|
||||||
|
|
||||||
import org.apache.hc.client5.http.classic.HttpClient;
|
import org.apache.hc.client5.http.classic.HttpClient;
|
||||||
import org.apache.hc.client5.http.config.RequestConfig;
|
import org.apache.hc.client5.http.config.RequestConfig;
|
||||||
import org.apache.hc.client5.http.cookie.StandardCookieSpec;
|
import org.apache.hc.client5.http.cookie.StandardCookieSpec;
|
||||||
|
import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
|
||||||
import org.apache.hc.client5.http.impl.classic.HttpClients;
|
import org.apache.hc.client5.http.impl.classic.HttpClients;
|
||||||
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
|
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
|
||||||
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;
|
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;
|
||||||
@ -35,10 +41,12 @@ import org.apache.hc.client5.http.protocol.HttpClientContext;
|
|||||||
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory;
|
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory;
|
||||||
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactoryBuilder;
|
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactoryBuilder;
|
||||||
import org.apache.hc.client5.http.ssl.TrustSelfSignedStrategy;
|
import org.apache.hc.client5.http.ssl.TrustSelfSignedStrategy;
|
||||||
|
import org.apache.hc.core5.http.io.SocketConfig;
|
||||||
import org.apache.hc.core5.http.protocol.HttpContext;
|
import org.apache.hc.core5.http.protocol.HttpContext;
|
||||||
import org.apache.hc.core5.http.ssl.TLS;
|
import org.apache.hc.core5.http.ssl.TLS;
|
||||||
import org.apache.hc.core5.ssl.SSLContextBuilder;
|
import org.apache.hc.core5.ssl.SSLContextBuilder;
|
||||||
|
|
||||||
|
import org.springframework.boot.web.client.ClientHttpRequestFactorySettings;
|
||||||
import org.springframework.boot.web.client.RestTemplateBuilder;
|
import org.springframework.boot.web.client.RestTemplateBuilder;
|
||||||
import org.springframework.boot.web.client.RootUriTemplateHandler;
|
import org.springframework.boot.web.client.RootUriTemplateHandler;
|
||||||
import org.springframework.core.ParameterizedTypeReference;
|
import org.springframework.core.ParameterizedTypeReference;
|
||||||
@ -138,8 +146,8 @@ public class TestRestTemplate {
|
|||||||
if (httpClientOptions != null) {
|
if (httpClientOptions != null) {
|
||||||
ClientHttpRequestFactory requestFactory = builder.buildRequestFactory();
|
ClientHttpRequestFactory requestFactory = builder.buildRequestFactory();
|
||||||
if (requestFactory instanceof HttpComponentsClientHttpRequestFactory) {
|
if (requestFactory instanceof HttpComponentsClientHttpRequestFactory) {
|
||||||
builder = builder
|
builder = builder.requestFactory(
|
||||||
.requestFactory(() -> new CustomHttpComponentsClientHttpRequestFactory(httpClientOptions));
|
(settings) -> new CustomHttpComponentsClientHttpRequestFactory(httpClientOptions, settings));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (username != null || password != null) {
|
if (username != null || password != null) {
|
||||||
@ -1000,43 +1008,71 @@ public class TestRestTemplate {
|
|||||||
|
|
||||||
private final boolean enableRedirects;
|
private final boolean enableRedirects;
|
||||||
|
|
||||||
public CustomHttpComponentsClientHttpRequestFactory(HttpClientOption[] httpClientOptions) {
|
public CustomHttpComponentsClientHttpRequestFactory(HttpClientOption[] httpClientOptions,
|
||||||
|
ClientHttpRequestFactorySettings settings) {
|
||||||
Set<HttpClientOption> options = new HashSet<>(Arrays.asList(httpClientOptions));
|
Set<HttpClientOption> options = new HashSet<>(Arrays.asList(httpClientOptions));
|
||||||
this.cookieSpec = (options.contains(HttpClientOption.ENABLE_COOKIES) ? StandardCookieSpec.STRICT
|
this.cookieSpec = (options.contains(HttpClientOption.ENABLE_COOKIES) ? StandardCookieSpec.STRICT
|
||||||
: StandardCookieSpec.IGNORE);
|
: StandardCookieSpec.IGNORE);
|
||||||
this.enableRedirects = options.contains(HttpClientOption.ENABLE_REDIRECTS);
|
this.enableRedirects = options.contains(HttpClientOption.ENABLE_REDIRECTS);
|
||||||
if (options.contains(HttpClientOption.SSL)) {
|
boolean ssl = options.contains(HttpClientOption.SSL);
|
||||||
setHttpClient(createSslHttpClient());
|
if (settings.readTimeout() != null || ssl) {
|
||||||
|
setHttpClient(createHttpClient(settings.readTimeout(), ssl));
|
||||||
|
}
|
||||||
|
if (settings.connectTimeout() != null) {
|
||||||
|
setConnectTimeout((int) settings.connectTimeout().toMillis());
|
||||||
|
}
|
||||||
|
if (settings.bufferRequestBody() != null) {
|
||||||
|
setBufferRequestBody(settings.bufferRequestBody());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private HttpClient createSslHttpClient() {
|
private HttpClient createHttpClient(Duration readTimeout, boolean ssl) {
|
||||||
try {
|
try {
|
||||||
SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustSelfSignedStrategy())
|
HttpClientBuilder builder = HttpClients.custom();
|
||||||
.build();
|
builder.setConnectionManager(createConnectionManager(readTimeout, ssl));
|
||||||
SSLConnectionSocketFactory socketFactory = SSLConnectionSocketFactoryBuilder.create()
|
builder.setDefaultRequestConfig(createRequestConfig());
|
||||||
.setSslContext(sslContext).setTlsVersions(TLS.V_1_3, TLS.V_1_2).build();
|
return builder.build();
|
||||||
PoolingHttpClientConnectionManager connectionManager = PoolingHttpClientConnectionManagerBuilder
|
|
||||||
.create().setSSLSocketFactory(socketFactory).build();
|
|
||||||
|
|
||||||
return HttpClients.custom().setConnectionManager(connectionManager)
|
|
||||||
.setDefaultRequestConfig(getRequestConfig()).build();
|
|
||||||
}
|
}
|
||||||
catch (Exception ex) {
|
catch (Exception ex) {
|
||||||
throw new IllegalStateException("Unable to create SSL HttpClient", ex);
|
throw new IllegalStateException("Unable to create customized HttpClient", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private PoolingHttpClientConnectionManager createConnectionManager(Duration readTimeout, boolean ssl)
|
||||||
|
throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException {
|
||||||
|
PoolingHttpClientConnectionManagerBuilder builder = PoolingHttpClientConnectionManagerBuilder.create();
|
||||||
|
if (ssl) {
|
||||||
|
builder.setSSLSocketFactory(createSocketFactory());
|
||||||
|
}
|
||||||
|
if (readTimeout != null) {
|
||||||
|
SocketConfig socketConfig = SocketConfig.custom()
|
||||||
|
.setSoTimeout((int) readTimeout.toMillis(), TimeUnit.MILLISECONDS).build();
|
||||||
|
builder.setDefaultSocketConfig(socketConfig);
|
||||||
|
}
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private SSLConnectionSocketFactory createSocketFactory()
|
||||||
|
throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException {
|
||||||
|
SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustSelfSignedStrategy())
|
||||||
|
.build();
|
||||||
|
return SSLConnectionSocketFactoryBuilder.create().setSslContext(sslContext)
|
||||||
|
.setTlsVersions(TLS.V_1_3, TLS.V_1_2).build();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected HttpContext createHttpContext(HttpMethod httpMethod, URI uri) {
|
protected HttpContext createHttpContext(HttpMethod httpMethod, URI uri) {
|
||||||
HttpClientContext context = HttpClientContext.create();
|
HttpClientContext context = HttpClientContext.create();
|
||||||
context.setRequestConfig(getRequestConfig());
|
context.setRequestConfig(createRequestConfig());
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected RequestConfig getRequestConfig() {
|
protected RequestConfig createRequestConfig() {
|
||||||
return RequestConfig.custom().setCookieSpec(this.cookieSpec).setAuthenticationEnabled(false)
|
RequestConfig.Builder builder = RequestConfig.custom();
|
||||||
.setRedirectsEnabled(this.enableRedirects).build();
|
builder.setCookieSpec(this.cookieSpec);
|
||||||
|
builder.setAuthenticationEnabled(false);
|
||||||
|
builder.setRedirectsEnabled(this.enableRedirects);
|
||||||
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -134,7 +134,7 @@ class TestRestTemplateTests {
|
|||||||
TestRestTemplate template = new TestRestTemplate(HttpClientOption.ENABLE_REDIRECTS);
|
TestRestTemplate template = new TestRestTemplate(HttpClientOption.ENABLE_REDIRECTS);
|
||||||
CustomHttpComponentsClientHttpRequestFactory factory = (CustomHttpComponentsClientHttpRequestFactory) template
|
CustomHttpComponentsClientHttpRequestFactory factory = (CustomHttpComponentsClientHttpRequestFactory) template
|
||||||
.getRestTemplate().getRequestFactory();
|
.getRestTemplate().getRequestFactory();
|
||||||
RequestConfig config = factory.getRequestConfig();
|
RequestConfig config = factory.createRequestConfig();
|
||||||
assertThat(config.isRedirectsEnabled()).isTrue();
|
assertThat(config.isRedirectsEnabled()).isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -16,17 +16,9 @@
|
|||||||
|
|
||||||
package org.springframework.boot.web.client;
|
package org.springframework.boot.web.client;
|
||||||
|
|
||||||
import java.util.function.Consumer;
|
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import org.springframework.aot.hint.RuntimeHints;
|
|
||||||
import org.springframework.aot.hint.TypeHint.Builder;
|
|
||||||
import org.springframework.aot.hint.TypeReference;
|
|
||||||
import org.springframework.http.client.ClientHttpRequestFactory;
|
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.ClassUtils;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A supplier for {@link ClientHttpRequestFactory} that detects the preferred candidate
|
* A supplier for {@link ClientHttpRequestFactory} that detects the preferred candidate
|
||||||
@ -35,43 +27,15 @@ import org.springframework.util.ClassUtils;
|
|||||||
* @author Stephane Nicoll
|
* @author Stephane Nicoll
|
||||||
* @author Moritz Halbritter
|
* @author Moritz Halbritter
|
||||||
* @since 2.1.0
|
* @since 2.1.0
|
||||||
|
* @deprecated since 3.0.0 for removal in 3.2.0 in favor of
|
||||||
|
* {@link ClientHttpRequestFactories}
|
||||||
*/
|
*/
|
||||||
|
@Deprecated(since = "3.0.0", forRemoval = true)
|
||||||
public class ClientHttpRequestFactorySupplier implements Supplier<ClientHttpRequestFactory> {
|
public class ClientHttpRequestFactorySupplier implements Supplier<ClientHttpRequestFactory> {
|
||||||
|
|
||||||
private 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);
|
|
||||||
|
|
||||||
private static final String OKHTTP_CLIENT_CLASS = "okhttp3.OkHttpClient";
|
|
||||||
|
|
||||||
private static final boolean OKHTTP_CLIENT_PRESENT = ClassUtils.isPresent(OKHTTP_CLIENT_CLASS, null);
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ClientHttpRequestFactory get() {
|
public ClientHttpRequestFactory get() {
|
||||||
if (APACHE_HTTP_CLIENT_PRESENT) {
|
return ClientHttpRequestFactories.get(ClientHttpRequestFactorySettings.DEFAULTS);
|
||||||
return new HttpComponentsClientHttpRequestFactory();
|
|
||||||
}
|
|
||||||
if (OKHTTP_CLIENT_PRESENT) {
|
|
||||||
return new OkHttp3ClientHttpRequestFactory();
|
|
||||||
}
|
|
||||||
return new SimpleClientHttpRequestFactory();
|
|
||||||
}
|
|
||||||
|
|
||||||
static class ClientHttpRequestFactorySupplierRuntimeHints {
|
|
||||||
|
|
||||||
static void registerHints(RuntimeHints hints, ClassLoader classLoader, Consumer<Builder> callback) {
|
|
||||||
if (ClassUtils.isPresent(APACHE_HTTP_CLIENT_CLASS, classLoader)) {
|
|
||||||
hints.reflection().registerType(HttpComponentsClientHttpRequestFactory.class, (typeHint) -> callback
|
|
||||||
.accept(typeHint.onReachableType(TypeReference.of(APACHE_HTTP_CLIENT_CLASS))));
|
|
||||||
}
|
|
||||||
if (ClassUtils.isPresent(OKHTTP_CLIENT_CLASS, classLoader)) {
|
|
||||||
hints.reflection().registerType(OkHttp3ClientHttpRequestFactory.class,
|
|
||||||
(typeHint) -> callback.accept(typeHint.onReachableType(TypeReference.of(OKHTTP_CLIENT_CLASS))));
|
|
||||||
}
|
|
||||||
hints.reflection().registerType(SimpleClientHttpRequestFactory.class, (typeHint) -> callback
|
|
||||||
.accept(typeHint.onReachableType(TypeReference.of(SimpleClientHttpRequestFactory.class))));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -16,9 +16,6 @@
|
|||||||
|
|
||||||
package org.springframework.boot.web.client;
|
package org.springframework.boot.web.client;
|
||||||
|
|
||||||
import java.lang.reflect.Constructor;
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -29,20 +26,13 @@ import java.util.LinkedHashMap;
|
|||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Function;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import reactor.netty.http.client.HttpClientRequest;
|
import reactor.netty.http.client.HttpClientRequest;
|
||||||
|
|
||||||
import org.springframework.aot.hint.ExecutableMode;
|
|
||||||
import org.springframework.aot.hint.RuntimeHints;
|
|
||||||
import org.springframework.aot.hint.RuntimeHintsRegistrar;
|
|
||||||
import org.springframework.aot.hint.TypeReference;
|
|
||||||
import org.springframework.beans.BeanUtils;
|
import org.springframework.beans.BeanUtils;
|
||||||
import org.springframework.context.annotation.ImportRuntimeHints;
|
|
||||||
import org.springframework.http.client.AbstractClientHttpRequestFactoryWrapper;
|
|
||||||
import org.springframework.http.client.ClientHttpRequest;
|
import org.springframework.http.client.ClientHttpRequest;
|
||||||
import org.springframework.http.client.ClientHttpRequestFactory;
|
import org.springframework.http.client.ClientHttpRequestFactory;
|
||||||
import org.springframework.http.client.ClientHttpRequestInterceptor;
|
import org.springframework.http.client.ClientHttpRequestInterceptor;
|
||||||
@ -51,7 +41,6 @@ import org.springframework.http.client.SimpleClientHttpRequestFactory;
|
|||||||
import org.springframework.http.converter.HttpMessageConverter;
|
import org.springframework.http.converter.HttpMessageConverter;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
import org.springframework.util.ReflectionUtils;
|
|
||||||
import org.springframework.web.client.ResponseErrorHandler;
|
import org.springframework.web.client.ResponseErrorHandler;
|
||||||
import org.springframework.web.client.RestTemplate;
|
import org.springframework.web.client.RestTemplate;
|
||||||
import org.springframework.web.util.UriTemplateHandler;
|
import org.springframework.web.util.UriTemplateHandler;
|
||||||
@ -77,10 +66,9 @@ import org.springframework.web.util.UriTemplateHandler;
|
|||||||
* @author Ilya Lukyanovich
|
* @author Ilya Lukyanovich
|
||||||
* @since 1.4.0
|
* @since 1.4.0
|
||||||
*/
|
*/
|
||||||
@ImportRuntimeHints(RestTemplateBuilder.RestTemplateBuilderRuntimeHints.class)
|
|
||||||
public class RestTemplateBuilder {
|
public class RestTemplateBuilder {
|
||||||
|
|
||||||
private final RequestFactoryCustomizer requestFactoryCustomizer;
|
private final ClientHttpRequestFactorySettings requestFactorySettings;
|
||||||
|
|
||||||
private final boolean detectRequestFactory;
|
private final boolean detectRequestFactory;
|
||||||
|
|
||||||
@ -90,7 +78,7 @@ public class RestTemplateBuilder {
|
|||||||
|
|
||||||
private final Set<ClientHttpRequestInterceptor> interceptors;
|
private final Set<ClientHttpRequestInterceptor> interceptors;
|
||||||
|
|
||||||
private final Supplier<ClientHttpRequestFactory> requestFactory;
|
private final Function<ClientHttpRequestFactorySettings, ClientHttpRequestFactory> requestFactory;
|
||||||
|
|
||||||
private final UriTemplateHandler uriTemplateHandler;
|
private final UriTemplateHandler uriTemplateHandler;
|
||||||
|
|
||||||
@ -111,7 +99,7 @@ public class RestTemplateBuilder {
|
|||||||
*/
|
*/
|
||||||
public RestTemplateBuilder(RestTemplateCustomizer... customizers) {
|
public RestTemplateBuilder(RestTemplateCustomizer... customizers) {
|
||||||
Assert.notNull(customizers, "Customizers must not be null");
|
Assert.notNull(customizers, "Customizers must not be null");
|
||||||
this.requestFactoryCustomizer = new RequestFactoryCustomizer();
|
this.requestFactorySettings = ClientHttpRequestFactorySettings.DEFAULTS;
|
||||||
this.detectRequestFactory = true;
|
this.detectRequestFactory = true;
|
||||||
this.rootUri = null;
|
this.rootUri = null;
|
||||||
this.messageConverters = null;
|
this.messageConverters = null;
|
||||||
@ -125,18 +113,19 @@ public class RestTemplateBuilder {
|
|||||||
this.requestCustomizers = Collections.emptySet();
|
this.requestCustomizers = Collections.emptySet();
|
||||||
}
|
}
|
||||||
|
|
||||||
private RestTemplateBuilder(RequestFactoryCustomizer requestFactoryCustomizer, boolean detectRequestFactory,
|
private RestTemplateBuilder(ClientHttpRequestFactorySettings requestFactorySettings, boolean detectRequestFactory,
|
||||||
String rootUri, Set<HttpMessageConverter<?>> messageConverters,
|
String rootUri, Set<HttpMessageConverter<?>> messageConverters,
|
||||||
Set<ClientHttpRequestInterceptor> interceptors, Supplier<ClientHttpRequestFactory> requestFactorySupplier,
|
Set<ClientHttpRequestInterceptor> interceptors,
|
||||||
|
Function<ClientHttpRequestFactorySettings, ClientHttpRequestFactory> requestFactory,
|
||||||
UriTemplateHandler uriTemplateHandler, ResponseErrorHandler errorHandler,
|
UriTemplateHandler uriTemplateHandler, ResponseErrorHandler errorHandler,
|
||||||
BasicAuthentication basicAuthentication, Map<String, List<String>> defaultHeaders,
|
BasicAuthentication basicAuthentication, Map<String, List<String>> defaultHeaders,
|
||||||
Set<RestTemplateCustomizer> customizers, Set<RestTemplateRequestCustomizer<?>> requestCustomizers) {
|
Set<RestTemplateCustomizer> customizers, Set<RestTemplateRequestCustomizer<?>> requestCustomizers) {
|
||||||
this.requestFactoryCustomizer = requestFactoryCustomizer;
|
this.requestFactorySettings = requestFactorySettings;
|
||||||
this.detectRequestFactory = detectRequestFactory;
|
this.detectRequestFactory = detectRequestFactory;
|
||||||
this.rootUri = rootUri;
|
this.rootUri = rootUri;
|
||||||
this.messageConverters = messageConverters;
|
this.messageConverters = messageConverters;
|
||||||
this.interceptors = interceptors;
|
this.interceptors = interceptors;
|
||||||
this.requestFactory = requestFactorySupplier;
|
this.requestFactory = requestFactory;
|
||||||
this.uriTemplateHandler = uriTemplateHandler;
|
this.uriTemplateHandler = uriTemplateHandler;
|
||||||
this.errorHandler = errorHandler;
|
this.errorHandler = errorHandler;
|
||||||
this.basicAuthentication = basicAuthentication;
|
this.basicAuthentication = basicAuthentication;
|
||||||
@ -153,7 +142,7 @@ public class RestTemplateBuilder {
|
|||||||
* @return a new builder instance
|
* @return a new builder instance
|
||||||
*/
|
*/
|
||||||
public RestTemplateBuilder detectRequestFactory(boolean detectRequestFactory) {
|
public RestTemplateBuilder detectRequestFactory(boolean detectRequestFactory) {
|
||||||
return new RestTemplateBuilder(this.requestFactoryCustomizer, detectRequestFactory, this.rootUri,
|
return new RestTemplateBuilder(this.requestFactorySettings, detectRequestFactory, this.rootUri,
|
||||||
this.messageConverters, this.interceptors, this.requestFactory, this.uriTemplateHandler,
|
this.messageConverters, this.interceptors, this.requestFactory, this.uriTemplateHandler,
|
||||||
this.errorHandler, this.basicAuthentication, this.defaultHeaders, this.customizers,
|
this.errorHandler, this.basicAuthentication, this.defaultHeaders, this.customizers,
|
||||||
this.requestCustomizers);
|
this.requestCustomizers);
|
||||||
@ -169,7 +158,7 @@ public class RestTemplateBuilder {
|
|||||||
* @return a new builder instance
|
* @return a new builder instance
|
||||||
*/
|
*/
|
||||||
public RestTemplateBuilder rootUri(String rootUri) {
|
public RestTemplateBuilder rootUri(String rootUri) {
|
||||||
return new RestTemplateBuilder(this.requestFactoryCustomizer, this.detectRequestFactory, rootUri,
|
return new RestTemplateBuilder(this.requestFactorySettings, this.detectRequestFactory, rootUri,
|
||||||
this.messageConverters, this.interceptors, this.requestFactory, this.uriTemplateHandler,
|
this.messageConverters, this.interceptors, this.requestFactory, this.uriTemplateHandler,
|
||||||
this.errorHandler, this.basicAuthentication, this.defaultHeaders, this.customizers,
|
this.errorHandler, this.basicAuthentication, this.defaultHeaders, this.customizers,
|
||||||
this.requestCustomizers);
|
this.requestCustomizers);
|
||||||
@ -200,7 +189,7 @@ public class RestTemplateBuilder {
|
|||||||
*/
|
*/
|
||||||
public RestTemplateBuilder messageConverters(Collection<? extends HttpMessageConverter<?>> messageConverters) {
|
public RestTemplateBuilder messageConverters(Collection<? extends HttpMessageConverter<?>> messageConverters) {
|
||||||
Assert.notNull(messageConverters, "MessageConverters must not be null");
|
Assert.notNull(messageConverters, "MessageConverters must not be null");
|
||||||
return new RestTemplateBuilder(this.requestFactoryCustomizer, this.detectRequestFactory, this.rootUri,
|
return new RestTemplateBuilder(this.requestFactorySettings, this.detectRequestFactory, this.rootUri,
|
||||||
copiedSetOf(messageConverters), this.interceptors, this.requestFactory, this.uriTemplateHandler,
|
copiedSetOf(messageConverters), this.interceptors, this.requestFactory, this.uriTemplateHandler,
|
||||||
this.errorHandler, this.basicAuthentication, this.defaultHeaders, this.customizers,
|
this.errorHandler, this.basicAuthentication, this.defaultHeaders, this.customizers,
|
||||||
this.requestCustomizers);
|
this.requestCustomizers);
|
||||||
@ -230,7 +219,7 @@ public class RestTemplateBuilder {
|
|||||||
public RestTemplateBuilder additionalMessageConverters(
|
public RestTemplateBuilder additionalMessageConverters(
|
||||||
Collection<? extends HttpMessageConverter<?>> messageConverters) {
|
Collection<? extends HttpMessageConverter<?>> messageConverters) {
|
||||||
Assert.notNull(messageConverters, "MessageConverters must not be null");
|
Assert.notNull(messageConverters, "MessageConverters must not be null");
|
||||||
return new RestTemplateBuilder(this.requestFactoryCustomizer, this.detectRequestFactory, this.rootUri,
|
return new RestTemplateBuilder(this.requestFactorySettings, this.detectRequestFactory, this.rootUri,
|
||||||
append(this.messageConverters, messageConverters), this.interceptors, this.requestFactory,
|
append(this.messageConverters, messageConverters), this.interceptors, this.requestFactory,
|
||||||
this.uriTemplateHandler, this.errorHandler, this.basicAuthentication, this.defaultHeaders,
|
this.uriTemplateHandler, this.errorHandler, this.basicAuthentication, this.defaultHeaders,
|
||||||
this.customizers, this.requestCustomizers);
|
this.customizers, this.requestCustomizers);
|
||||||
@ -244,7 +233,7 @@ public class RestTemplateBuilder {
|
|||||||
* @see #messageConverters(HttpMessageConverter...)
|
* @see #messageConverters(HttpMessageConverter...)
|
||||||
*/
|
*/
|
||||||
public RestTemplateBuilder defaultMessageConverters() {
|
public RestTemplateBuilder defaultMessageConverters() {
|
||||||
return new RestTemplateBuilder(this.requestFactoryCustomizer, this.detectRequestFactory, this.rootUri,
|
return new RestTemplateBuilder(this.requestFactorySettings, this.detectRequestFactory, this.rootUri,
|
||||||
copiedSetOf(new RestTemplate().getMessageConverters()), this.interceptors, this.requestFactory,
|
copiedSetOf(new RestTemplate().getMessageConverters()), this.interceptors, this.requestFactory,
|
||||||
this.uriTemplateHandler, this.errorHandler, this.basicAuthentication, this.defaultHeaders,
|
this.uriTemplateHandler, this.errorHandler, this.basicAuthentication, this.defaultHeaders,
|
||||||
this.customizers, this.requestCustomizers);
|
this.customizers, this.requestCustomizers);
|
||||||
@ -275,7 +264,7 @@ public class RestTemplateBuilder {
|
|||||||
*/
|
*/
|
||||||
public RestTemplateBuilder interceptors(Collection<ClientHttpRequestInterceptor> interceptors) {
|
public RestTemplateBuilder interceptors(Collection<ClientHttpRequestInterceptor> interceptors) {
|
||||||
Assert.notNull(interceptors, "interceptors must not be null");
|
Assert.notNull(interceptors, "interceptors must not be null");
|
||||||
return new RestTemplateBuilder(this.requestFactoryCustomizer, this.detectRequestFactory, this.rootUri,
|
return new RestTemplateBuilder(this.requestFactorySettings, this.detectRequestFactory, this.rootUri,
|
||||||
this.messageConverters, copiedSetOf(interceptors), this.requestFactory, this.uriTemplateHandler,
|
this.messageConverters, copiedSetOf(interceptors), this.requestFactory, this.uriTemplateHandler,
|
||||||
this.errorHandler, this.basicAuthentication, this.defaultHeaders, this.customizers,
|
this.errorHandler, this.basicAuthentication, this.defaultHeaders, this.customizers,
|
||||||
this.requestCustomizers);
|
this.requestCustomizers);
|
||||||
@ -304,7 +293,7 @@ public class RestTemplateBuilder {
|
|||||||
*/
|
*/
|
||||||
public RestTemplateBuilder additionalInterceptors(Collection<? extends ClientHttpRequestInterceptor> interceptors) {
|
public RestTemplateBuilder additionalInterceptors(Collection<? extends ClientHttpRequestInterceptor> interceptors) {
|
||||||
Assert.notNull(interceptors, "interceptors must not be null");
|
Assert.notNull(interceptors, "interceptors must not be null");
|
||||||
return new RestTemplateBuilder(this.requestFactoryCustomizer, this.detectRequestFactory, this.rootUri,
|
return new RestTemplateBuilder(this.requestFactorySettings, this.detectRequestFactory, this.rootUri,
|
||||||
this.messageConverters, append(this.interceptors, interceptors), this.requestFactory,
|
this.messageConverters, append(this.interceptors, interceptors), this.requestFactory,
|
||||||
this.uriTemplateHandler, this.errorHandler, this.basicAuthentication, this.defaultHeaders,
|
this.uriTemplateHandler, this.errorHandler, this.basicAuthentication, this.defaultHeaders,
|
||||||
this.customizers, this.requestCustomizers);
|
this.customizers, this.requestCustomizers);
|
||||||
@ -313,37 +302,41 @@ public class RestTemplateBuilder {
|
|||||||
/**
|
/**
|
||||||
* Set the {@link ClientHttpRequestFactory} class that should be used with the
|
* Set the {@link ClientHttpRequestFactory} class that should be used with the
|
||||||
* {@link RestTemplate}.
|
* {@link RestTemplate}.
|
||||||
* @param requestFactory the request factory to use
|
* @param requestFactoryType the request factory type to use
|
||||||
* @return a new builder instance
|
* @return a new builder instance
|
||||||
*/
|
*/
|
||||||
public RestTemplateBuilder requestFactory(Class<? extends ClientHttpRequestFactory> requestFactory) {
|
public RestTemplateBuilder requestFactory(Class<? extends ClientHttpRequestFactory> requestFactoryType) {
|
||||||
Assert.notNull(requestFactory, "RequestFactory must not be null");
|
Assert.notNull(requestFactoryType, "RequestFactoryType must not be null");
|
||||||
return requestFactory(() -> createRequestFactory(requestFactory));
|
return requestFactory((settings) -> ClientHttpRequestFactories.get(requestFactoryType, settings));
|
||||||
}
|
|
||||||
|
|
||||||
private ClientHttpRequestFactory createRequestFactory(Class<? extends ClientHttpRequestFactory> requestFactory) {
|
|
||||||
try {
|
|
||||||
Constructor<?> constructor = requestFactory.getDeclaredConstructor();
|
|
||||||
constructor.setAccessible(true);
|
|
||||||
return (ClientHttpRequestFactory) constructor.newInstance();
|
|
||||||
}
|
|
||||||
catch (Exception ex) {
|
|
||||||
throw new IllegalStateException(ex);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the {@code Supplier} of {@link ClientHttpRequestFactory} that should be called
|
* Set the {@code Supplier} of {@link ClientHttpRequestFactory} that should be called
|
||||||
* each time we {@link #build()} a new {@link RestTemplate} instance.
|
* each time we {@link #build()} a new {@link RestTemplate} instance.
|
||||||
* @param requestFactory the supplier for the request factory
|
* @param requestFactorySupplier the supplier for the request factory
|
||||||
* @return a new builder instance
|
* @return a new builder instance
|
||||||
* @since 2.0.0
|
* @since 2.0.0
|
||||||
*/
|
*/
|
||||||
public RestTemplateBuilder requestFactory(Supplier<ClientHttpRequestFactory> requestFactory) {
|
public RestTemplateBuilder requestFactory(Supplier<ClientHttpRequestFactory> requestFactorySupplier) {
|
||||||
Assert.notNull(requestFactory, "RequestFactory Supplier must not be null");
|
Assert.notNull(requestFactorySupplier, "RequestFactorySupplier must not be null");
|
||||||
return new RestTemplateBuilder(this.requestFactoryCustomizer, this.detectRequestFactory, this.rootUri,
|
return requestFactory((settings) -> ClientHttpRequestFactories.get(requestFactorySupplier, settings));
|
||||||
this.messageConverters, this.interceptors, requestFactory, this.uriTemplateHandler, this.errorHandler,
|
}
|
||||||
this.basicAuthentication, this.defaultHeaders, this.customizers, this.requestCustomizers);
|
|
||||||
|
/**
|
||||||
|
* Set the {@link ClientHttpRequestFactorySupplier} that should be called each time we
|
||||||
|
* {@link #build()} a new {@link RestTemplate} instance.
|
||||||
|
* @param requestFactoryFunction the settings to request factory function
|
||||||
|
* @return a new builder instance
|
||||||
|
* @since 3.0.0
|
||||||
|
* @see ClientHttpRequestFactories
|
||||||
|
*/
|
||||||
|
public RestTemplateBuilder requestFactory(
|
||||||
|
Function<ClientHttpRequestFactorySettings, ClientHttpRequestFactory> requestFactoryFunction) {
|
||||||
|
Assert.notNull(requestFactoryFunction, "RequestFactoryFunction must not be null");
|
||||||
|
return new RestTemplateBuilder(this.requestFactorySettings, this.detectRequestFactory, this.rootUri,
|
||||||
|
this.messageConverters, this.interceptors, requestFactoryFunction, this.uriTemplateHandler,
|
||||||
|
this.errorHandler, this.basicAuthentication, this.defaultHeaders, this.customizers,
|
||||||
|
this.requestCustomizers);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -354,7 +347,7 @@ public class RestTemplateBuilder {
|
|||||||
*/
|
*/
|
||||||
public RestTemplateBuilder uriTemplateHandler(UriTemplateHandler uriTemplateHandler) {
|
public RestTemplateBuilder uriTemplateHandler(UriTemplateHandler uriTemplateHandler) {
|
||||||
Assert.notNull(uriTemplateHandler, "UriTemplateHandler must not be null");
|
Assert.notNull(uriTemplateHandler, "UriTemplateHandler must not be null");
|
||||||
return new RestTemplateBuilder(this.requestFactoryCustomizer, this.detectRequestFactory, this.rootUri,
|
return new RestTemplateBuilder(this.requestFactorySettings, this.detectRequestFactory, this.rootUri,
|
||||||
this.messageConverters, this.interceptors, this.requestFactory, uriTemplateHandler, this.errorHandler,
|
this.messageConverters, this.interceptors, this.requestFactory, uriTemplateHandler, this.errorHandler,
|
||||||
this.basicAuthentication, this.defaultHeaders, this.customizers, this.requestCustomizers);
|
this.basicAuthentication, this.defaultHeaders, this.customizers, this.requestCustomizers);
|
||||||
}
|
}
|
||||||
@ -367,7 +360,7 @@ public class RestTemplateBuilder {
|
|||||||
*/
|
*/
|
||||||
public RestTemplateBuilder errorHandler(ResponseErrorHandler errorHandler) {
|
public RestTemplateBuilder errorHandler(ResponseErrorHandler errorHandler) {
|
||||||
Assert.notNull(errorHandler, "ErrorHandler must not be null");
|
Assert.notNull(errorHandler, "ErrorHandler must not be null");
|
||||||
return new RestTemplateBuilder(this.requestFactoryCustomizer, this.detectRequestFactory, this.rootUri,
|
return new RestTemplateBuilder(this.requestFactorySettings, this.detectRequestFactory, this.rootUri,
|
||||||
this.messageConverters, this.interceptors, this.requestFactory, this.uriTemplateHandler, errorHandler,
|
this.messageConverters, this.interceptors, this.requestFactory, this.uriTemplateHandler, errorHandler,
|
||||||
this.basicAuthentication, this.defaultHeaders, this.customizers, this.requestCustomizers);
|
this.basicAuthentication, this.defaultHeaders, this.customizers, this.requestCustomizers);
|
||||||
}
|
}
|
||||||
@ -395,7 +388,7 @@ public class RestTemplateBuilder {
|
|||||||
* @since 2.2.0
|
* @since 2.2.0
|
||||||
*/
|
*/
|
||||||
public RestTemplateBuilder basicAuthentication(String username, String password, Charset charset) {
|
public RestTemplateBuilder basicAuthentication(String username, String password, Charset charset) {
|
||||||
return new RestTemplateBuilder(this.requestFactoryCustomizer, this.detectRequestFactory, this.rootUri,
|
return new RestTemplateBuilder(this.requestFactorySettings, this.detectRequestFactory, this.rootUri,
|
||||||
this.messageConverters, this.interceptors, this.requestFactory, this.uriTemplateHandler,
|
this.messageConverters, this.interceptors, this.requestFactory, this.uriTemplateHandler,
|
||||||
this.errorHandler, new BasicAuthentication(username, password, charset), this.defaultHeaders,
|
this.errorHandler, new BasicAuthentication(username, password, charset), this.defaultHeaders,
|
||||||
this.customizers, this.requestCustomizers);
|
this.customizers, this.requestCustomizers);
|
||||||
@ -412,7 +405,7 @@ public class RestTemplateBuilder {
|
|||||||
public RestTemplateBuilder defaultHeader(String name, String... values) {
|
public RestTemplateBuilder defaultHeader(String name, String... values) {
|
||||||
Assert.notNull(name, "Name must not be null");
|
Assert.notNull(name, "Name must not be null");
|
||||||
Assert.notNull(values, "Values must not be null");
|
Assert.notNull(values, "Values must not be null");
|
||||||
return new RestTemplateBuilder(this.requestFactoryCustomizer, this.detectRequestFactory, this.rootUri,
|
return new RestTemplateBuilder(this.requestFactorySettings, this.detectRequestFactory, this.rootUri,
|
||||||
this.messageConverters, this.interceptors, this.requestFactory, this.uriTemplateHandler,
|
this.messageConverters, this.interceptors, this.requestFactory, this.uriTemplateHandler,
|
||||||
this.errorHandler, this.basicAuthentication, append(this.defaultHeaders, name, values),
|
this.errorHandler, this.basicAuthentication, append(this.defaultHeaders, name, values),
|
||||||
this.customizers, this.requestCustomizers);
|
this.customizers, this.requestCustomizers);
|
||||||
@ -425,7 +418,7 @@ public class RestTemplateBuilder {
|
|||||||
* @since 2.1.0
|
* @since 2.1.0
|
||||||
*/
|
*/
|
||||||
public RestTemplateBuilder setConnectTimeout(Duration connectTimeout) {
|
public RestTemplateBuilder setConnectTimeout(Duration connectTimeout) {
|
||||||
return new RestTemplateBuilder(this.requestFactoryCustomizer.connectTimeout(connectTimeout),
|
return new RestTemplateBuilder(this.requestFactorySettings.withConnectTimeout(connectTimeout),
|
||||||
this.detectRequestFactory, this.rootUri, this.messageConverters, this.interceptors, this.requestFactory,
|
this.detectRequestFactory, this.rootUri, this.messageConverters, this.interceptors, this.requestFactory,
|
||||||
this.uriTemplateHandler, this.errorHandler, this.basicAuthentication, this.defaultHeaders,
|
this.uriTemplateHandler, this.errorHandler, this.basicAuthentication, this.defaultHeaders,
|
||||||
this.customizers, this.requestCustomizers);
|
this.customizers, this.requestCustomizers);
|
||||||
@ -438,7 +431,7 @@ public class RestTemplateBuilder {
|
|||||||
* @since 2.1.0
|
* @since 2.1.0
|
||||||
*/
|
*/
|
||||||
public RestTemplateBuilder setReadTimeout(Duration readTimeout) {
|
public RestTemplateBuilder setReadTimeout(Duration readTimeout) {
|
||||||
return new RestTemplateBuilder(this.requestFactoryCustomizer.readTimeout(readTimeout),
|
return new RestTemplateBuilder(this.requestFactorySettings.withReadTimeout(readTimeout),
|
||||||
this.detectRequestFactory, this.rootUri, this.messageConverters, this.interceptors, this.requestFactory,
|
this.detectRequestFactory, this.rootUri, this.messageConverters, this.interceptors, this.requestFactory,
|
||||||
this.uriTemplateHandler, this.errorHandler, this.basicAuthentication, this.defaultHeaders,
|
this.uriTemplateHandler, this.errorHandler, this.basicAuthentication, this.defaultHeaders,
|
||||||
this.customizers, this.requestCustomizers);
|
this.customizers, this.requestCustomizers);
|
||||||
@ -454,7 +447,7 @@ public class RestTemplateBuilder {
|
|||||||
* @see HttpComponentsClientHttpRequestFactory#setBufferRequestBody(boolean)
|
* @see HttpComponentsClientHttpRequestFactory#setBufferRequestBody(boolean)
|
||||||
*/
|
*/
|
||||||
public RestTemplateBuilder setBufferRequestBody(boolean bufferRequestBody) {
|
public RestTemplateBuilder setBufferRequestBody(boolean bufferRequestBody) {
|
||||||
return new RestTemplateBuilder(this.requestFactoryCustomizer.bufferRequestBody(bufferRequestBody),
|
return new RestTemplateBuilder(this.requestFactorySettings.withBufferRequestBody(bufferRequestBody),
|
||||||
this.detectRequestFactory, this.rootUri, this.messageConverters, this.interceptors, this.requestFactory,
|
this.detectRequestFactory, this.rootUri, this.messageConverters, this.interceptors, this.requestFactory,
|
||||||
this.uriTemplateHandler, this.errorHandler, this.basicAuthentication, this.defaultHeaders,
|
this.uriTemplateHandler, this.errorHandler, this.basicAuthentication, this.defaultHeaders,
|
||||||
this.customizers, this.requestCustomizers);
|
this.customizers, this.requestCustomizers);
|
||||||
@ -485,7 +478,7 @@ public class RestTemplateBuilder {
|
|||||||
*/
|
*/
|
||||||
public RestTemplateBuilder customizers(Collection<? extends RestTemplateCustomizer> customizers) {
|
public RestTemplateBuilder customizers(Collection<? extends RestTemplateCustomizer> customizers) {
|
||||||
Assert.notNull(customizers, "Customizers must not be null");
|
Assert.notNull(customizers, "Customizers must not be null");
|
||||||
return new RestTemplateBuilder(this.requestFactoryCustomizer, this.detectRequestFactory, this.rootUri,
|
return new RestTemplateBuilder(this.requestFactorySettings, this.detectRequestFactory, this.rootUri,
|
||||||
this.messageConverters, this.interceptors, this.requestFactory, this.uriTemplateHandler,
|
this.messageConverters, this.interceptors, this.requestFactory, this.uriTemplateHandler,
|
||||||
this.errorHandler, this.basicAuthentication, this.defaultHeaders, copiedSetOf(customizers),
|
this.errorHandler, this.basicAuthentication, this.defaultHeaders, copiedSetOf(customizers),
|
||||||
this.requestCustomizers);
|
this.requestCustomizers);
|
||||||
@ -514,7 +507,7 @@ public class RestTemplateBuilder {
|
|||||||
*/
|
*/
|
||||||
public RestTemplateBuilder additionalCustomizers(Collection<? extends RestTemplateCustomizer> customizers) {
|
public RestTemplateBuilder additionalCustomizers(Collection<? extends RestTemplateCustomizer> customizers) {
|
||||||
Assert.notNull(customizers, "RestTemplateCustomizers must not be null");
|
Assert.notNull(customizers, "RestTemplateCustomizers must not be null");
|
||||||
return new RestTemplateBuilder(this.requestFactoryCustomizer, this.detectRequestFactory, this.rootUri,
|
return new RestTemplateBuilder(this.requestFactorySettings, this.detectRequestFactory, this.rootUri,
|
||||||
this.messageConverters, this.interceptors, this.requestFactory, this.uriTemplateHandler,
|
this.messageConverters, this.interceptors, this.requestFactory, this.uriTemplateHandler,
|
||||||
this.errorHandler, this.basicAuthentication, this.defaultHeaders, append(this.customizers, customizers),
|
this.errorHandler, this.basicAuthentication, this.defaultHeaders, append(this.customizers, customizers),
|
||||||
this.requestCustomizers);
|
this.requestCustomizers);
|
||||||
@ -548,7 +541,7 @@ public class RestTemplateBuilder {
|
|||||||
public RestTemplateBuilder requestCustomizers(
|
public RestTemplateBuilder requestCustomizers(
|
||||||
Collection<? extends RestTemplateRequestCustomizer<?>> requestCustomizers) {
|
Collection<? extends RestTemplateRequestCustomizer<?>> requestCustomizers) {
|
||||||
Assert.notNull(requestCustomizers, "RequestCustomizers must not be null");
|
Assert.notNull(requestCustomizers, "RequestCustomizers must not be null");
|
||||||
return new RestTemplateBuilder(this.requestFactoryCustomizer, this.detectRequestFactory, this.rootUri,
|
return new RestTemplateBuilder(this.requestFactorySettings, this.detectRequestFactory, this.rootUri,
|
||||||
this.messageConverters, this.interceptors, this.requestFactory, this.uriTemplateHandler,
|
this.messageConverters, this.interceptors, this.requestFactory, this.uriTemplateHandler,
|
||||||
this.errorHandler, this.basicAuthentication, this.defaultHeaders, this.customizers,
|
this.errorHandler, this.basicAuthentication, this.defaultHeaders, this.customizers,
|
||||||
copiedSetOf(requestCustomizers));
|
copiedSetOf(requestCustomizers));
|
||||||
@ -580,7 +573,7 @@ public class RestTemplateBuilder {
|
|||||||
public RestTemplateBuilder additionalRequestCustomizers(
|
public RestTemplateBuilder additionalRequestCustomizers(
|
||||||
Collection<? extends RestTemplateRequestCustomizer<?>> requestCustomizers) {
|
Collection<? extends RestTemplateRequestCustomizer<?>> requestCustomizers) {
|
||||||
Assert.notNull(requestCustomizers, "RequestCustomizers must not be null");
|
Assert.notNull(requestCustomizers, "RequestCustomizers must not be null");
|
||||||
return new RestTemplateBuilder(this.requestFactoryCustomizer, this.detectRequestFactory, this.rootUri,
|
return new RestTemplateBuilder(this.requestFactorySettings, this.detectRequestFactory, this.rootUri,
|
||||||
this.messageConverters, this.interceptors, this.requestFactory, this.uriTemplateHandler,
|
this.messageConverters, this.interceptors, this.requestFactory, this.uriTemplateHandler,
|
||||||
this.errorHandler, this.basicAuthentication, this.defaultHeaders, this.customizers,
|
this.errorHandler, this.basicAuthentication, this.defaultHeaders, this.customizers,
|
||||||
append(this.requestCustomizers, requestCustomizers));
|
append(this.requestCustomizers, requestCustomizers));
|
||||||
@ -651,19 +644,13 @@ public class RestTemplateBuilder {
|
|||||||
* @since 2.2.0
|
* @since 2.2.0
|
||||||
*/
|
*/
|
||||||
public ClientHttpRequestFactory buildRequestFactory() {
|
public ClientHttpRequestFactory buildRequestFactory() {
|
||||||
ClientHttpRequestFactory requestFactory = null;
|
|
||||||
if (this.requestFactory != null) {
|
if (this.requestFactory != null) {
|
||||||
requestFactory = this.requestFactory.get();
|
return this.requestFactory.apply(this.requestFactorySettings);
|
||||||
}
|
}
|
||||||
else if (this.detectRequestFactory) {
|
if (this.detectRequestFactory) {
|
||||||
requestFactory = new ClientHttpRequestFactorySupplier().get();
|
return ClientHttpRequestFactories.get(this.requestFactorySettings);
|
||||||
}
|
}
|
||||||
if (requestFactory != null) {
|
return null;
|
||||||
if (this.requestFactoryCustomizer != null) {
|
|
||||||
this.requestFactoryCustomizer.accept(requestFactory);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return requestFactory;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addClientHttpRequestInitializer(RestTemplate restTemplate) {
|
private void addClientHttpRequestInitializer(RestTemplate restTemplate) {
|
||||||
@ -703,118 +690,4 @@ public class RestTemplateBuilder {
|
|||||||
return Collections.unmodifiableMap(result);
|
return Collections.unmodifiableMap(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Internal customizer used to apply {@link ClientHttpRequestFactory} settings.
|
|
||||||
*/
|
|
||||||
private static class RequestFactoryCustomizer implements Consumer<ClientHttpRequestFactory> {
|
|
||||||
|
|
||||||
private final Duration connectTimeout;
|
|
||||||
|
|
||||||
private final Duration readTimeout;
|
|
||||||
|
|
||||||
private final Boolean bufferRequestBody;
|
|
||||||
|
|
||||||
RequestFactoryCustomizer() {
|
|
||||||
this(null, null, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private RequestFactoryCustomizer(Duration connectTimeout, Duration readTimeout, Boolean bufferRequestBody) {
|
|
||||||
this.connectTimeout = connectTimeout;
|
|
||||||
this.readTimeout = readTimeout;
|
|
||||||
this.bufferRequestBody = bufferRequestBody;
|
|
||||||
}
|
|
||||||
|
|
||||||
RequestFactoryCustomizer connectTimeout(Duration connectTimeout) {
|
|
||||||
return new RequestFactoryCustomizer(connectTimeout, this.readTimeout, this.bufferRequestBody);
|
|
||||||
}
|
|
||||||
|
|
||||||
RequestFactoryCustomizer readTimeout(Duration readTimeout) {
|
|
||||||
return new RequestFactoryCustomizer(this.connectTimeout, readTimeout, this.bufferRequestBody);
|
|
||||||
}
|
|
||||||
|
|
||||||
RequestFactoryCustomizer bufferRequestBody(boolean bufferRequestBody) {
|
|
||||||
return new RequestFactoryCustomizer(this.connectTimeout, this.readTimeout, bufferRequestBody);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void accept(ClientHttpRequestFactory requestFactory) {
|
|
||||||
ClientHttpRequestFactory unwrappedRequestFactory = unwrapRequestFactoryIfNecessary(requestFactory);
|
|
||||||
if (this.connectTimeout != null) {
|
|
||||||
setConnectTimeout(unwrappedRequestFactory);
|
|
||||||
}
|
|
||||||
if (this.readTimeout != null) {
|
|
||||||
setReadTimeout(unwrappedRequestFactory);
|
|
||||||
}
|
|
||||||
if (this.bufferRequestBody != null) {
|
|
||||||
setBufferRequestBody(unwrappedRequestFactory);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private 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 void setConnectTimeout(ClientHttpRequestFactory factory) {
|
|
||||||
Method method = findMethod(factory, "setConnectTimeout", int.class);
|
|
||||||
int timeout = Math.toIntExact(this.connectTimeout.toMillis());
|
|
||||||
invoke(factory, method, timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setReadTimeout(ClientHttpRequestFactory factory) {
|
|
||||||
Method method = findMethod(factory, "setReadTimeout", int.class);
|
|
||||||
int timeout = Math.toIntExact(this.readTimeout.toMillis());
|
|
||||||
invoke(factory, method, timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setBufferRequestBody(ClientHttpRequestFactory factory) {
|
|
||||||
Method method = findMethod(factory, "setBufferRequestBody", boolean.class);
|
|
||||||
invoke(factory, method, this.bufferRequestBody);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Method findMethod(ClientHttpRequestFactory requestFactory, String methodName, Class<?>... parameters) {
|
|
||||||
Method method = ReflectionUtils.findMethod(requestFactory.getClass(), methodName, parameters);
|
|
||||||
if (method == null) {
|
|
||||||
throw new IllegalStateException("Request factory " + requestFactory.getClass()
|
|
||||||
+ " does not have a suitable " + methodName + " method");
|
|
||||||
}
|
|
||||||
else if (method.isAnnotationPresent(Deprecated.class)) {
|
|
||||||
throw new IllegalStateException("Request factory " + requestFactory.getClass() + " has the "
|
|
||||||
+ methodName + " method marked as deprecated");
|
|
||||||
}
|
|
||||||
return method;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void invoke(ClientHttpRequestFactory requestFactory, Method method, Object... parameters) {
|
|
||||||
ReflectionUtils.invokeMethod(method, requestFactory, parameters);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static class RestTemplateBuilderRuntimeHints implements RuntimeHintsRegistrar {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
|
|
||||||
hints.reflection().registerField(Objects.requireNonNull(
|
|
||||||
ReflectionUtils.findField(AbstractClientHttpRequestFactoryWrapper.class, "requestFactory")));
|
|
||||||
ClientHttpRequestFactorySupplier.ClientHttpRequestFactorySupplierRuntimeHints.registerHints(hints,
|
|
||||||
classLoader, (hint) -> {
|
|
||||||
hint.withMethod("setConnectTimeout", TypeReference.listOf(int.class), ExecutableMode.INVOKE);
|
|
||||||
hint.withMethod("setReadTimeout", TypeReference.listOf(int.class), ExecutableMode.INVOKE);
|
|
||||||
hint.withMethod("setBufferRequestBody", TypeReference.listOf(boolean.class),
|
|
||||||
ExecutableMode.INVOKE);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2012-2019 the original author or authors.
|
* Copyright 2012-2022 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -16,14 +16,14 @@
|
|||||||
|
|
||||||
package org.springframework.boot.webservices.client;
|
package org.springframework.boot.webservices.client;
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
|
import java.util.function.Function;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import org.springframework.boot.web.client.ClientHttpRequestFactorySupplier;
|
import org.springframework.boot.web.client.ClientHttpRequestFactories;
|
||||||
|
import org.springframework.boot.web.client.ClientHttpRequestFactorySettings;
|
||||||
import org.springframework.http.client.ClientHttpRequestFactory;
|
import org.springframework.http.client.ClientHttpRequestFactory;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.ReflectionUtils;
|
|
||||||
import org.springframework.ws.transport.WebServiceMessageSender;
|
import org.springframework.ws.transport.WebServiceMessageSender;
|
||||||
import org.springframework.ws.transport.http.ClientHttpRequestMessageSender;
|
import org.springframework.ws.transport.http.ClientHttpRequestMessageSender;
|
||||||
|
|
||||||
@ -40,7 +40,7 @@ public class HttpWebServiceMessageSenderBuilder {
|
|||||||
|
|
||||||
private Duration readTimeout;
|
private Duration readTimeout;
|
||||||
|
|
||||||
private Supplier<ClientHttpRequestFactory> requestFactorySupplier;
|
private Function<ClientHttpRequestFactorySettings, ClientHttpRequestFactory> requestFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the connection timeout.
|
* Set the connection timeout.
|
||||||
@ -70,50 +70,39 @@ public class HttpWebServiceMessageSenderBuilder {
|
|||||||
*/
|
*/
|
||||||
public HttpWebServiceMessageSenderBuilder requestFactory(
|
public HttpWebServiceMessageSenderBuilder requestFactory(
|
||||||
Supplier<ClientHttpRequestFactory> requestFactorySupplier) {
|
Supplier<ClientHttpRequestFactory> requestFactorySupplier) {
|
||||||
Assert.notNull(requestFactorySupplier, "RequestFactory Supplier must not be null");
|
Assert.notNull(requestFactorySupplier, "RequestFactorySupplier must not be null");
|
||||||
this.requestFactorySupplier = requestFactorySupplier;
|
this.requestFactory = (settings) -> ClientHttpRequestFactories.get(requestFactorySupplier, settings);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public WebServiceMessageSender build() {
|
/**
|
||||||
ClientHttpRequestFactory requestFactory = (this.requestFactorySupplier != null)
|
* Set the {@code Function} of {@link ClientHttpRequestFactorySettings} to
|
||||||
? this.requestFactorySupplier.get() : new ClientHttpRequestFactorySupplier().get();
|
* {@link ClientHttpRequestFactory} that should be called to create the HTTP-based
|
||||||
if (this.connectTimeout != null) {
|
* {@link WebServiceMessageSender}.
|
||||||
new TimeoutRequestFactoryCustomizer(this.connectTimeout, "setConnectTimeout").customize(requestFactory);
|
* @param requestFactoryFunction the function for the request factory
|
||||||
}
|
* @return a new builder instance
|
||||||
if (this.readTimeout != null) {
|
* @since 3.0.0
|
||||||
new TimeoutRequestFactoryCustomizer(this.readTimeout, "setReadTimeout").customize(requestFactory);
|
*/
|
||||||
}
|
public HttpWebServiceMessageSenderBuilder requestFactory(
|
||||||
return new ClientHttpRequestMessageSender(requestFactory);
|
Function<ClientHttpRequestFactorySettings, ClientHttpRequestFactory> requestFactoryFunction) {
|
||||||
|
Assert.notNull(requestFactoryFunction, "RequestFactoryFunction must not be null");
|
||||||
|
this.requestFactory = requestFactoryFunction;
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link ClientHttpRequestFactory} customizer to call a "set timeout" method.
|
* Build the {@link WebServiceMessageSender} instance.
|
||||||
|
* @return the {@link WebServiceMessageSender} instance
|
||||||
*/
|
*/
|
||||||
private static class TimeoutRequestFactoryCustomizer {
|
public WebServiceMessageSender build() {
|
||||||
|
return new ClientHttpRequestMessageSender(getRequestFactory());
|
||||||
private final Duration timeout;
|
}
|
||||||
|
|
||||||
private final String methodName;
|
|
||||||
|
|
||||||
TimeoutRequestFactoryCustomizer(Duration timeout, String methodName) {
|
|
||||||
this.timeout = timeout;
|
|
||||||
this.methodName = methodName;
|
|
||||||
}
|
|
||||||
|
|
||||||
void customize(ClientHttpRequestFactory factory) {
|
|
||||||
ReflectionUtils.invokeMethod(findMethod(factory), factory, Math.toIntExact(this.timeout.toMillis()));
|
|
||||||
}
|
|
||||||
|
|
||||||
private Method findMethod(ClientHttpRequestFactory factory) {
|
|
||||||
Method method = ReflectionUtils.findMethod(factory.getClass(), this.methodName, int.class);
|
|
||||||
if (method != null) {
|
|
||||||
return method;
|
|
||||||
}
|
|
||||||
throw new IllegalStateException(
|
|
||||||
"Request factory " + factory.getClass() + " does not have a " + this.methodName + "(int) method");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
private ClientHttpRequestFactory getRequestFactory() {
|
||||||
|
ClientHttpRequestFactorySettings settings = new ClientHttpRequestFactorySettings(this.connectTimeout,
|
||||||
|
this.readTimeout, null);
|
||||||
|
return (this.requestFactory != null) ? this.requestFactory.apply(settings)
|
||||||
|
: ClientHttpRequestFactories.get(settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ org.springframework.boot.env.PropertySourceRuntimeHints,\
|
|||||||
org.springframework.boot.json.JacksonRuntimeHints,\
|
org.springframework.boot.json.JacksonRuntimeHints,\
|
||||||
org.springframework.boot.logging.java.JavaLoggingSystemRuntimeHints,\
|
org.springframework.boot.logging.java.JavaLoggingSystemRuntimeHints,\
|
||||||
org.springframework.boot.logging.logback.LogbackRuntimeHints,\
|
org.springframework.boot.logging.logback.LogbackRuntimeHints,\
|
||||||
|
org.springframework.boot.web.client.ClientHttpRequestFactoriesRuntimeHints,\
|
||||||
org.springframework.boot.web.embedded.undertow.UndertowWebServer.UndertowWebServerRuntimeHints,\
|
org.springframework.boot.web.embedded.undertow.UndertowWebServer.UndertowWebServerRuntimeHints,\
|
||||||
org.springframework.boot.web.server.MimeMappings.MimeMappingsRuntimeHints
|
org.springframework.boot.web.server.MimeMappings.MimeMappingsRuntimeHints
|
||||||
|
|
||||||
|
@ -40,6 +40,7 @@ import org.springframework.beans.factory.aot.BeanFactoryInitializationCode;
|
|||||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||||
|
import org.springframework.boot.context.properties.bind.BindableRuntimeHintsRegistrar;
|
||||||
import org.springframework.boot.context.properties.bind.ConstructorBinding;
|
import org.springframework.boot.context.properties.bind.ConstructorBinding;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.context.ApplicationContextAware;
|
import org.springframework.context.ApplicationContextAware;
|
||||||
@ -50,7 +51,8 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for {@link ConfigurationPropertiesBeanFactoryInitializationAotProcessor}.
|
* Tests for {@link ConfigurationPropertiesBeanFactoryInitializationAotProcessor} and
|
||||||
|
* {@link BindableRuntimeHintsRegistrar}.
|
||||||
*
|
*
|
||||||
* @author Stephane Nicoll
|
* @author Stephane Nicoll
|
||||||
* @author Moritz Halbritter
|
* @author Moritz Halbritter
|
||||||
|
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -18,28 +18,21 @@ package org.springframework.boot.web.client;
|
|||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.time.Duration;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.function.Function;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import okhttp3.OkHttpClient;
|
|
||||||
import org.assertj.core.api.InstanceOfAssertFactories;
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
import org.mockito.InOrder;
|
import org.mockito.InOrder;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.junit.jupiter.MockitoExtension;
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
|
|
||||||
import org.springframework.aot.hint.RuntimeHints;
|
|
||||||
import org.springframework.aot.hint.predicate.ReflectionHintsPredicates;
|
|
||||||
import org.springframework.aot.hint.predicate.RuntimeHintsPredicates;
|
|
||||||
import org.springframework.boot.web.client.RestTemplateBuilder.RestTemplateBuilderRuntimeHints;
|
|
||||||
import org.springframework.http.HttpHeaders;
|
import org.springframework.http.HttpHeaders;
|
||||||
import org.springframework.http.HttpMethod;
|
import org.springframework.http.HttpMethod;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.client.AbstractClientHttpRequestFactoryWrapper;
|
|
||||||
import org.springframework.http.client.BufferingClientHttpRequestFactory;
|
import org.springframework.http.client.BufferingClientHttpRequestFactory;
|
||||||
import org.springframework.http.client.ClientHttpRequest;
|
import org.springframework.http.client.ClientHttpRequest;
|
||||||
import org.springframework.http.client.ClientHttpRequestFactory;
|
import org.springframework.http.client.ClientHttpRequestFactory;
|
||||||
@ -47,22 +40,18 @@ import org.springframework.http.client.ClientHttpRequestInitializer;
|
|||||||
import org.springframework.http.client.ClientHttpRequestInterceptor;
|
import org.springframework.http.client.ClientHttpRequestInterceptor;
|
||||||
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
|
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
|
||||||
import org.springframework.http.client.InterceptingClientHttpRequestFactory;
|
import org.springframework.http.client.InterceptingClientHttpRequestFactory;
|
||||||
import org.springframework.http.client.OkHttp3ClientHttpRequestFactory;
|
|
||||||
import org.springframework.http.client.SimpleClientHttpRequestFactory;
|
import org.springframework.http.client.SimpleClientHttpRequestFactory;
|
||||||
import org.springframework.http.converter.HttpMessageConverter;
|
import org.springframework.http.converter.HttpMessageConverter;
|
||||||
import org.springframework.http.converter.ResourceHttpMessageConverter;
|
import org.springframework.http.converter.ResourceHttpMessageConverter;
|
||||||
import org.springframework.http.converter.StringHttpMessageConverter;
|
import org.springframework.http.converter.StringHttpMessageConverter;
|
||||||
import org.springframework.test.util.ReflectionTestUtils;
|
import org.springframework.test.util.ReflectionTestUtils;
|
||||||
import org.springframework.test.web.client.MockRestServiceServer;
|
import org.springframework.test.web.client.MockRestServiceServer;
|
||||||
import org.springframework.util.ReflectionUtils;
|
|
||||||
import org.springframework.web.client.ResponseErrorHandler;
|
import org.springframework.web.client.ResponseErrorHandler;
|
||||||
import org.springframework.web.client.RestTemplate;
|
import org.springframework.web.client.RestTemplate;
|
||||||
import org.springframework.web.util.UriTemplateHandler;
|
import org.springframework.web.util.UriTemplateHandler;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
|
||||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
|
||||||
import static org.assertj.core.api.Assertions.entry;
|
import static org.assertj.core.api.Assertions.entry;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.BDDMockito.then;
|
import static org.mockito.BDDMockito.then;
|
||||||
@ -255,7 +244,7 @@ class RestTemplateBuilderTests {
|
|||||||
void requestFactoryClassWhenFactoryIsNullShouldThrowException() {
|
void requestFactoryClassWhenFactoryIsNullShouldThrowException() {
|
||||||
assertThatIllegalArgumentException()
|
assertThatIllegalArgumentException()
|
||||||
.isThrownBy(() -> this.builder.requestFactory((Class<ClientHttpRequestFactory>) null))
|
.isThrownBy(() -> this.builder.requestFactory((Class<ClientHttpRequestFactory>) null))
|
||||||
.withMessageContaining("RequestFactory must not be null");
|
.withMessageContaining("RequestFactoryType must not be null");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -274,7 +263,15 @@ class RestTemplateBuilderTests {
|
|||||||
void requestFactoryWhenSupplierIsNullShouldThrowException() {
|
void requestFactoryWhenSupplierIsNullShouldThrowException() {
|
||||||
assertThatIllegalArgumentException()
|
assertThatIllegalArgumentException()
|
||||||
.isThrownBy(() -> this.builder.requestFactory((Supplier<ClientHttpRequestFactory>) null))
|
.isThrownBy(() -> this.builder.requestFactory((Supplier<ClientHttpRequestFactory>) null))
|
||||||
.withMessageContaining("RequestFactory Supplier must not be null");
|
.withMessageContaining("RequestFactorySupplier must not be null");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void requestFactoryWhenFunctionIsNullShouldThrowException() {
|
||||||
|
assertThatIllegalArgumentException()
|
||||||
|
.isThrownBy(() -> this.builder
|
||||||
|
.requestFactory((Function<ClientHttpRequestFactorySettings, ClientHttpRequestFactory>) null))
|
||||||
|
.withMessageContaining("RequestFactoryFunction must not be null");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -459,128 +456,6 @@ class RestTemplateBuilderTests {
|
|||||||
assertThat(template.getRequestFactory()).isInstanceOf(HttpComponentsClientHttpRequestFactory.class);
|
assertThat(template.getRequestFactory()).isInstanceOf(HttpComponentsClientHttpRequestFactory.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
void connectTimeoutCanBeNullToUseDefault() {
|
|
||||||
ClientHttpRequestFactory requestFactory = this.builder.requestFactory(SimpleClientHttpRequestFactory.class)
|
|
||||||
.setConnectTimeout(null).build().getRequestFactory();
|
|
||||||
assertThat(requestFactory).hasFieldOrPropertyWithValue("connectTimeout", -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void readTimeoutCanBeNullToUseDefault() {
|
|
||||||
ClientHttpRequestFactory requestFactory = this.builder.requestFactory(SimpleClientHttpRequestFactory.class)
|
|
||||||
.setReadTimeout(null).build().getRequestFactory();
|
|
||||||
assertThat(requestFactory).hasFieldOrPropertyWithValue("readTimeout", -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void connectTimeoutCanBeConfiguredOnHttpComponentsRequestFactory() {
|
|
||||||
ClientHttpRequestFactory requestFactory = this.builder
|
|
||||||
.requestFactory(HttpComponentsClientHttpRequestFactory.class).setConnectTimeout(Duration.ofMillis(1234))
|
|
||||||
.build().getRequestFactory();
|
|
||||||
assertThat(((int) ReflectionTestUtils.getField(requestFactory, "connectTimeout"))).isEqualTo(1234);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void readTimeoutConfigurationFailsOnHttpComponentsRequestFactory() {
|
|
||||||
assertThatThrownBy(() -> this.builder.requestFactory(HttpComponentsClientHttpRequestFactory.class)
|
|
||||||
.setReadTimeout(Duration.ofMillis(1234)).build()).isInstanceOf(IllegalStateException.class)
|
|
||||||
.hasMessageContaining("setReadTimeout method marked as deprecated");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void bufferRequestBodyCanBeConfiguredOnHttpComponentsRequestFactory() {
|
|
||||||
ClientHttpRequestFactory requestFactory = this.builder
|
|
||||||
.requestFactory(HttpComponentsClientHttpRequestFactory.class).setBufferRequestBody(false).build()
|
|
||||||
.getRequestFactory();
|
|
||||||
assertThat(requestFactory).hasFieldOrPropertyWithValue("bufferRequestBody", false);
|
|
||||||
requestFactory = this.builder.requestFactory(HttpComponentsClientHttpRequestFactory.class)
|
|
||||||
.setBufferRequestBody(true).build().getRequestFactory();
|
|
||||||
assertThat(requestFactory).hasFieldOrPropertyWithValue("bufferRequestBody", true);
|
|
||||||
requestFactory = this.builder.requestFactory(HttpComponentsClientHttpRequestFactory.class).build()
|
|
||||||
.getRequestFactory();
|
|
||||||
assertThat(requestFactory).hasFieldOrPropertyWithValue("bufferRequestBody", true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void connectTimeoutCanBeConfiguredOnSimpleRequestFactory() {
|
|
||||||
ClientHttpRequestFactory requestFactory = this.builder.requestFactory(SimpleClientHttpRequestFactory.class)
|
|
||||||
.setConnectTimeout(Duration.ofMillis(1234)).build().getRequestFactory();
|
|
||||||
assertThat(requestFactory).hasFieldOrPropertyWithValue("connectTimeout", 1234);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void readTimeoutCanBeConfiguredOnSimpleRequestFactory() {
|
|
||||||
ClientHttpRequestFactory requestFactory = this.builder.requestFactory(SimpleClientHttpRequestFactory.class)
|
|
||||||
.setReadTimeout(Duration.ofMillis(1234)).build().getRequestFactory();
|
|
||||||
assertThat(requestFactory).hasFieldOrPropertyWithValue("readTimeout", 1234);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void bufferRequestBodyCanBeConfiguredOnSimpleRequestFactory() {
|
|
||||||
ClientHttpRequestFactory requestFactory = this.builder.requestFactory(SimpleClientHttpRequestFactory.class)
|
|
||||||
.setBufferRequestBody(false).build().getRequestFactory();
|
|
||||||
assertThat(requestFactory).hasFieldOrPropertyWithValue("bufferRequestBody", false);
|
|
||||||
requestFactory = this.builder.requestFactory(SimpleClientHttpRequestFactory.class).setBufferRequestBody(true)
|
|
||||||
.build().getRequestFactory();
|
|
||||||
assertThat(requestFactory).hasFieldOrPropertyWithValue("bufferRequestBody", true);
|
|
||||||
requestFactory = this.builder.requestFactory(SimpleClientHttpRequestFactory.class).build().getRequestFactory();
|
|
||||||
assertThat(requestFactory).hasFieldOrPropertyWithValue("bufferRequestBody", true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@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 readTimeoutCanBeConfiguredOnOkHttp3RequestFactory() {
|
|
||||||
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 bufferRequestBodyCanNotBeConfiguredOnOkHttp3RequestFactory() {
|
|
||||||
assertThatIllegalStateException()
|
|
||||||
.isThrownBy(() -> this.builder.requestFactory(OkHttp3ClientHttpRequestFactory.class)
|
|
||||||
.setBufferRequestBody(false).build().getRequestFactory())
|
|
||||||
.withMessageContaining(OkHttp3ClientHttpRequestFactory.class.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void connectTimeoutCanBeConfiguredOnAWrappedRequestFactory() {
|
|
||||||
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
|
|
||||||
this.builder.requestFactory(() -> new BufferingClientHttpRequestFactory(requestFactory))
|
|
||||||
.setConnectTimeout(Duration.ofMillis(1234)).build();
|
|
||||||
assertThat(requestFactory).hasFieldOrPropertyWithValue("connectTimeout", 1234);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void readTimeoutCanBeConfiguredOnAWrappedRequestFactory() {
|
|
||||||
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
|
|
||||||
this.builder.requestFactory(() -> new BufferingClientHttpRequestFactory(requestFactory))
|
|
||||||
.setReadTimeout(Duration.ofMillis(1234)).build();
|
|
||||||
assertThat(requestFactory).hasFieldOrPropertyWithValue("readTimeout", 1234);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void bufferRequestBodyCanBeConfiguredOnAWrappedRequestFactory() {
|
|
||||||
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
|
|
||||||
this.builder.requestFactory(() -> new BufferingClientHttpRequestFactory(requestFactory))
|
|
||||||
.setBufferRequestBody(false).build();
|
|
||||||
assertThat(requestFactory).hasFieldOrPropertyWithValue("bufferRequestBody", false);
|
|
||||||
this.builder.requestFactory(() -> new BufferingClientHttpRequestFactory(requestFactory))
|
|
||||||
.setBufferRequestBody(true).build();
|
|
||||||
assertThat(requestFactory).hasFieldOrPropertyWithValue("bufferRequestBody", true);
|
|
||||||
this.builder.requestFactory(() -> new BufferingClientHttpRequestFactory(requestFactory)).build();
|
|
||||||
assertThat(requestFactory).hasFieldOrPropertyWithValue("bufferRequestBody", true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void unwrappingDoesNotAffectRequestFactoryThatIsSetOnTheBuiltTemplate() {
|
void unwrappingDoesNotAffectRequestFactoryThatIsSetOnTheBuiltTemplate() {
|
||||||
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
|
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
|
||||||
@ -589,58 +464,6 @@ class RestTemplateBuilderTests {
|
|||||||
assertThat(template.getRequestFactory()).isInstanceOf(BufferingClientHttpRequestFactory.class);
|
assertThat(template.getRequestFactory()).isInstanceOf(BufferingClientHttpRequestFactory.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
void shouldRegisterHints() {
|
|
||||||
RuntimeHints hints = new RuntimeHints();
|
|
||||||
new RestTemplateBuilderRuntimeHints().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 RestTemplateBuilderRuntimeHints().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 RestTemplateBuilderRuntimeHints().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 RestTemplateBuilderRuntimeHints().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);
|
|
||||||
}
|
|
||||||
|
|
||||||
private ClientHttpRequest createRequest(RestTemplate template) {
|
private ClientHttpRequest createRequest(RestTemplate template) {
|
||||||
return ReflectionTestUtils.invokeMethod(template, "createRequest", URI.create("http://localhost"),
|
return ReflectionTestUtils.invokeMethod(template, "createRequest", URI.create("http://localhost"),
|
||||||
HttpMethod.GET);
|
HttpMethod.GET);
|
||||||
@ -654,4 +477,8 @@ class RestTemplateBuilderTests {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static class TestHttpComponentsClientHttpRequestFactory extends HttpComponentsClientHttpRequestFactory {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2012-2019 the original author or authors.
|
* Copyright 2012-2022 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -57,8 +57,8 @@ class HttpWebServiceMessageSenderBuilderTests {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
void buildUsesHttpComponentsByDefault() {
|
void buildUsesHttpComponentsByDefault() {
|
||||||
ClientHttpRequestMessageSender messageSender = build(
|
ClientHttpRequestMessageSender messageSender = build(new HttpWebServiceMessageSenderBuilder()
|
||||||
new HttpWebServiceMessageSenderBuilder().setConnectTimeout(Duration.ofSeconds(5)));
|
.setConnectTimeout(Duration.ofSeconds(5)).setReadTimeout(Duration.ofSeconds(5)));
|
||||||
ClientHttpRequestFactory requestFactory = messageSender.getRequestFactory();
|
ClientHttpRequestFactory requestFactory = messageSender.getRequestFactory();
|
||||||
assertThat(requestFactory).isInstanceOf(HttpComponentsClientHttpRequestFactory.class);
|
assertThat(requestFactory).isInstanceOf(HttpComponentsClientHttpRequestFactory.class);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2012-2021 the original author or authors.
|
* Copyright 2012-2022 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
Loading…
Reference in New Issue
Block a user