All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.springframework.boot.web.client.RestTemplateBuilder Maven / Gradle / Ivy

There is a newer version: 3.2.5
Show newest version
/*
 * Copyright 2012-2020 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.nio.charset.Charset;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Supplier;

import reactor.netty.http.client.HttpClientRequest;

import org.springframework.beans.BeanUtils;
import org.springframework.http.client.AbstractClientHttpRequestFactoryWrapper;
import org.springframework.http.client.ClientHttpRequest;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.client.ResponseErrorHandler;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriTemplateHandler;

/**
 * Builder that can be used to configure and create a {@link RestTemplate}. Provides
 * convenience methods to register {@link #messageConverters(HttpMessageConverter...)
 * converters}, {@link #errorHandler(ResponseErrorHandler) error handlers} and
 * {@link #uriTemplateHandler(UriTemplateHandler) UriTemplateHandlers}.
 * 

* By default the built {@link RestTemplate} will attempt to use the most suitable * {@link ClientHttpRequestFactory}, call {@link #detectRequestFactory(boolean) * detectRequestFactory(false)} if you prefer to keep the default. In a typical * auto-configured Spring Boot application this builder is available as a bean and can be * injected whenever a {@link RestTemplate} is needed. * * @author Stephane Nicoll * @author Phillip Webb * @author Andy Wilkinson * @author Brian Clozel * @author Dmytro Nosan * @author Kevin Strijbos * @author Ilya Lukyanovich * @since 1.4.0 */ public class RestTemplateBuilder { private final RequestFactoryCustomizer requestFactoryCustomizer; private final boolean detectRequestFactory; private final String rootUri; private final Set> messageConverters; private final Set interceptors; private final Supplier requestFactory; private final UriTemplateHandler uriTemplateHandler; private final ResponseErrorHandler errorHandler; private final BasicAuthentication basicAuthentication; private final Map> defaultHeaders; private final Set customizers; private final Set> requestCustomizers; /** * Create a new {@link RestTemplateBuilder} instance. * @param customizers any {@link RestTemplateCustomizer RestTemplateCustomizers} that * should be applied when the {@link RestTemplate} is built */ public RestTemplateBuilder(RestTemplateCustomizer... customizers) { Assert.notNull(customizers, "Customizers must not be null"); this.requestFactoryCustomizer = new RequestFactoryCustomizer(); this.detectRequestFactory = true; this.rootUri = null; this.messageConverters = null; this.interceptors = Collections.emptySet(); this.requestFactory = null; this.uriTemplateHandler = null; this.errorHandler = null; this.basicAuthentication = null; this.defaultHeaders = Collections.emptyMap(); this.customizers = copiedSetOf(customizers); this.requestCustomizers = Collections.emptySet(); } private RestTemplateBuilder(RequestFactoryCustomizer requestFactoryCustomizer, boolean detectRequestFactory, String rootUri, Set> messageConverters, Set interceptors, Supplier requestFactorySupplier, UriTemplateHandler uriTemplateHandler, ResponseErrorHandler errorHandler, BasicAuthentication basicAuthentication, Map> defaultHeaders, Set customizers, Set> requestCustomizers) { this.requestFactoryCustomizer = requestFactoryCustomizer; this.detectRequestFactory = detectRequestFactory; this.rootUri = rootUri; this.messageConverters = messageConverters; this.interceptors = interceptors; this.requestFactory = requestFactorySupplier; this.uriTemplateHandler = uriTemplateHandler; this.errorHandler = errorHandler; this.basicAuthentication = basicAuthentication; this.defaultHeaders = defaultHeaders; this.customizers = customizers; this.requestCustomizers = requestCustomizers; } /** * Set if the {@link ClientHttpRequestFactory} should be detected based on the * classpath. Default if {@code true}. * @param detectRequestFactory if the {@link ClientHttpRequestFactory} should be * detected * @return a new builder instance */ public RestTemplateBuilder detectRequestFactory(boolean detectRequestFactory) { return new RestTemplateBuilder(this.requestFactoryCustomizer, detectRequestFactory, this.rootUri, this.messageConverters, this.interceptors, this.requestFactory, this.uriTemplateHandler, this.errorHandler, this.basicAuthentication, this.defaultHeaders, this.customizers, this.requestCustomizers); } /** * Set a root URL that should be applied to each request that starts with {@code '/'}. * Since this works by adding a {@link UriTemplateHandler} to the * {@link RestTemplate}, the root URL will only apply when {@code String} variants of * the {@link RestTemplate} methods are used for specifying the request URL. See * {@link RootUriTemplateHandler} for details. * @param rootUri the root URI or {@code null} * @return a new builder instance */ public RestTemplateBuilder rootUri(String rootUri) { return new RestTemplateBuilder(this.requestFactoryCustomizer, this.detectRequestFactory, rootUri, this.messageConverters, this.interceptors, this.requestFactory, this.uriTemplateHandler, this.errorHandler, this.basicAuthentication, this.defaultHeaders, this.customizers, this.requestCustomizers); } /** * Set the {@link HttpMessageConverter HttpMessageConverters} that should be used with * the {@link RestTemplate}. Setting this value will replace any previously configured * converters and any converters configured on the builder will replace RestTemplate's * default converters. * @param messageConverters the converters to set * @return a new builder instance * @see #additionalMessageConverters(HttpMessageConverter...) */ public RestTemplateBuilder messageConverters(HttpMessageConverter... messageConverters) { Assert.notNull(messageConverters, "MessageConverters must not be null"); return messageConverters(Arrays.asList(messageConverters)); } /** * Set the {@link HttpMessageConverter HttpMessageConverters} that should be used with * the {@link RestTemplate}. Setting this value will replace any previously configured * converters and any converters configured on the builder will replace RestTemplate's * default converters. * @param messageConverters the converters to set * @return a new builder instance * @see #additionalMessageConverters(HttpMessageConverter...) */ public RestTemplateBuilder messageConverters(Collection> messageConverters) { Assert.notNull(messageConverters, "MessageConverters must not be null"); return new RestTemplateBuilder(this.requestFactoryCustomizer, this.detectRequestFactory, this.rootUri, copiedSetOf(messageConverters), this.interceptors, this.requestFactory, this.uriTemplateHandler, this.errorHandler, this.basicAuthentication, this.defaultHeaders, this.customizers, this.requestCustomizers); } /** * Add additional {@link HttpMessageConverter HttpMessageConverters} that should be * used with the {@link RestTemplate}. Any converters configured on the builder will * replace RestTemplate's default converters. * @param messageConverters the converters to add * @return a new builder instance * @see #messageConverters(HttpMessageConverter...) */ public RestTemplateBuilder additionalMessageConverters(HttpMessageConverter... messageConverters) { Assert.notNull(messageConverters, "MessageConverters must not be null"); return additionalMessageConverters(Arrays.asList(messageConverters)); } /** * Add additional {@link HttpMessageConverter HttpMessageConverters} that should be * used with the {@link RestTemplate}. Any converters configured on the builder will * replace RestTemplate's default converters. * @param messageConverters the converters to add * @return a new builder instance * @see #messageConverters(HttpMessageConverter...) */ public RestTemplateBuilder additionalMessageConverters( Collection> messageConverters) { Assert.notNull(messageConverters, "MessageConverters must not be null"); return new RestTemplateBuilder(this.requestFactoryCustomizer, this.detectRequestFactory, this.rootUri, append(this.messageConverters, messageConverters), this.interceptors, this.requestFactory, this.uriTemplateHandler, this.errorHandler, this.basicAuthentication, this.defaultHeaders, this.customizers, this.requestCustomizers); } /** * Set the {@link HttpMessageConverter HttpMessageConverters} that should be used with * the {@link RestTemplate} to the default set. Calling this method will replace any * previously defined converters. * @return a new builder instance * @see #messageConverters(HttpMessageConverter...) */ public RestTemplateBuilder defaultMessageConverters() { return new RestTemplateBuilder(this.requestFactoryCustomizer, this.detectRequestFactory, this.rootUri, copiedSetOf(new RestTemplate().getMessageConverters()), this.interceptors, this.requestFactory, this.uriTemplateHandler, this.errorHandler, this.basicAuthentication, this.defaultHeaders, this.customizers, this.requestCustomizers); } /** * Set the {@link ClientHttpRequestInterceptor ClientHttpRequestInterceptors} that * should be used with the {@link RestTemplate}. Setting this value will replace any * previously defined interceptors. * @param interceptors the interceptors to set * @return a new builder instance * @since 1.4.1 * @see #additionalInterceptors(ClientHttpRequestInterceptor...) */ public RestTemplateBuilder interceptors(ClientHttpRequestInterceptor... interceptors) { Assert.notNull(interceptors, "interceptors must not be null"); return interceptors(Arrays.asList(interceptors)); } /** * Set the {@link ClientHttpRequestInterceptor ClientHttpRequestInterceptors} that * should be used with the {@link RestTemplate}. Setting this value will replace any * previously defined interceptors. * @param interceptors the interceptors to set * @return a new builder instance * @since 1.4.1 * @see #additionalInterceptors(ClientHttpRequestInterceptor...) */ public RestTemplateBuilder interceptors(Collection interceptors) { Assert.notNull(interceptors, "interceptors must not be null"); return new RestTemplateBuilder(this.requestFactoryCustomizer, this.detectRequestFactory, this.rootUri, this.messageConverters, copiedSetOf(interceptors), this.requestFactory, this.uriTemplateHandler, this.errorHandler, this.basicAuthentication, this.defaultHeaders, this.customizers, this.requestCustomizers); } /** * Add additional {@link ClientHttpRequestInterceptor ClientHttpRequestInterceptors} * that should be used with the {@link RestTemplate}. * @param interceptors the interceptors to add * @return a new builder instance * @since 1.4.1 * @see #interceptors(ClientHttpRequestInterceptor...) */ public RestTemplateBuilder additionalInterceptors(ClientHttpRequestInterceptor... interceptors) { Assert.notNull(interceptors, "interceptors must not be null"); return additionalInterceptors(Arrays.asList(interceptors)); } /** * Add additional {@link ClientHttpRequestInterceptor ClientHttpRequestInterceptors} * that should be used with the {@link RestTemplate}. * @param interceptors the interceptors to add * @return a new builder instance * @since 1.4.1 * @see #interceptors(ClientHttpRequestInterceptor...) */ public RestTemplateBuilder additionalInterceptors(Collection interceptors) { Assert.notNull(interceptors, "interceptors must not be null"); return new RestTemplateBuilder(this.requestFactoryCustomizer, this.detectRequestFactory, this.rootUri, this.messageConverters, append(this.interceptors, interceptors), this.requestFactory, this.uriTemplateHandler, this.errorHandler, this.basicAuthentication, this.defaultHeaders, this.customizers, this.requestCustomizers); } /** * Set the {@link ClientHttpRequestFactory} class that should be used with the * {@link RestTemplate}. * @param requestFactory the request factory to use * @return a new builder instance */ public RestTemplateBuilder requestFactory(Class requestFactory) { Assert.notNull(requestFactory, "RequestFactory must not be null"); return requestFactory(() -> createRequestFactory(requestFactory)); } private ClientHttpRequestFactory createRequestFactory(Class 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 * each time we {@link #build()} a new {@link RestTemplate} instance. * @param requestFactory the supplier for the request factory * @return a new builder instance * @since 2.0.0 */ public RestTemplateBuilder requestFactory(Supplier requestFactory) { Assert.notNull(requestFactory, "RequestFactory Supplier must not be null"); return new RestTemplateBuilder(this.requestFactoryCustomizer, this.detectRequestFactory, this.rootUri, this.messageConverters, this.interceptors, requestFactory, this.uriTemplateHandler, this.errorHandler, this.basicAuthentication, this.defaultHeaders, this.customizers, this.requestCustomizers); } /** * Set the {@link UriTemplateHandler} that should be used with the * {@link RestTemplate}. * @param uriTemplateHandler the URI template handler to use * @return a new builder instance */ public RestTemplateBuilder uriTemplateHandler(UriTemplateHandler uriTemplateHandler) { Assert.notNull(uriTemplateHandler, "UriTemplateHandler must not be null"); return new RestTemplateBuilder(this.requestFactoryCustomizer, this.detectRequestFactory, this.rootUri, this.messageConverters, this.interceptors, this.requestFactory, uriTemplateHandler, this.errorHandler, this.basicAuthentication, this.defaultHeaders, this.customizers, this.requestCustomizers); } /** * Set the {@link ResponseErrorHandler} that should be used with the * {@link RestTemplate}. * @param errorHandler the error handler to use * @return a new builder instance */ public RestTemplateBuilder errorHandler(ResponseErrorHandler errorHandler) { Assert.notNull(errorHandler, "ErrorHandler must not be null"); return new RestTemplateBuilder(this.requestFactoryCustomizer, this.detectRequestFactory, this.rootUri, this.messageConverters, this.interceptors, this.requestFactory, this.uriTemplateHandler, errorHandler, this.basicAuthentication, this.defaultHeaders, this.customizers, this.requestCustomizers); } /** * Add HTTP Basic Authentication to requests with the given username/password pair, * unless a custom Authorization header has been set before. * @param username the user name * @param password the password * @return a new builder instance * @since 2.1.0 * @see #basicAuthentication(String, String, Charset) */ public RestTemplateBuilder basicAuthentication(String username, String password) { return basicAuthentication(username, password, null); } /** * Add HTTP Basic Authentication to requests with the given username/password pair, * unless a custom Authorization header has been set before. * @param username the user name * @param password the password * @param charset the charset to use * @return a new builder instance * @since 2.2.0 */ public RestTemplateBuilder basicAuthentication(String username, String password, Charset charset) { return new RestTemplateBuilder(this.requestFactoryCustomizer, this.detectRequestFactory, this.rootUri, this.messageConverters, this.interceptors, this.requestFactory, this.uriTemplateHandler, this.errorHandler, new BasicAuthentication(username, password, charset), this.defaultHeaders, this.customizers, this.requestCustomizers); } /** * Add a default header that will be set if not already present on the outgoing * {@link HttpClientRequest}. * @param name the name of the header * @param values the header values * @return a new builder instance * @since 2.2.0 */ public RestTemplateBuilder defaultHeader(String name, String... values) { Assert.notNull(name, "Name must not be null"); Assert.notNull(values, "Values must not be null"); return new RestTemplateBuilder(this.requestFactoryCustomizer, this.detectRequestFactory, this.rootUri, this.messageConverters, this.interceptors, this.requestFactory, this.uriTemplateHandler, this.errorHandler, this.basicAuthentication, append(this.defaultHeaders, name, values), this.customizers, this.requestCustomizers); } /** * Sets the connection timeout on the underlying {@link ClientHttpRequestFactory}. * @param connectTimeout the connection timeout * @return a new builder instance. * @since 2.1.0 */ public RestTemplateBuilder setConnectTimeout(Duration connectTimeout) { return new RestTemplateBuilder(this.requestFactoryCustomizer.connectTimeout(connectTimeout), this.detectRequestFactory, this.rootUri, this.messageConverters, this.interceptors, this.requestFactory, this.uriTemplateHandler, this.errorHandler, this.basicAuthentication, this.defaultHeaders, this.customizers, this.requestCustomizers); } /** * Sets the read timeout on the underlying {@link ClientHttpRequestFactory}. * @param readTimeout the read timeout * @return a new builder instance. * @since 2.1.0 */ public RestTemplateBuilder setReadTimeout(Duration readTimeout) { return new RestTemplateBuilder(this.requestFactoryCustomizer.readTimeout(readTimeout), this.detectRequestFactory, this.rootUri, this.messageConverters, this.interceptors, this.requestFactory, this.uriTemplateHandler, this.errorHandler, this.basicAuthentication, this.defaultHeaders, this.customizers, this.requestCustomizers); } /** * Sets if the underlying {@link ClientHttpRequestFactory} should buffer the * {@linkplain ClientHttpRequest#getBody() request body} internally. * @param bufferRequestBody value of the bufferRequestBody parameter * @return a new builder instance. * @since 2.2.0 * @see SimpleClientHttpRequestFactory#setBufferRequestBody(boolean) * @see HttpComponentsClientHttpRequestFactory#setBufferRequestBody(boolean) */ public RestTemplateBuilder setBufferRequestBody(boolean bufferRequestBody) { return new RestTemplateBuilder(this.requestFactoryCustomizer.bufferRequestBody(bufferRequestBody), this.detectRequestFactory, this.rootUri, this.messageConverters, this.interceptors, this.requestFactory, this.uriTemplateHandler, this.errorHandler, this.basicAuthentication, this.defaultHeaders, this.customizers, this.requestCustomizers); } /** * Set the {@link RestTemplateCustomizer RestTemplateCustomizers} that should be * applied to the {@link RestTemplate}. Customizers are applied in the order that they * were added after builder configuration has been applied. Setting this value will * replace any previously configured customizers. * @param customizers the customizers to set * @return a new builder instance * @see #additionalCustomizers(RestTemplateCustomizer...) */ public RestTemplateBuilder customizers(RestTemplateCustomizer... customizers) { Assert.notNull(customizers, "Customizers must not be null"); return customizers(Arrays.asList(customizers)); } /** * Set the {@link RestTemplateCustomizer RestTemplateCustomizers} that should be * applied to the {@link RestTemplate}. Customizers are applied in the order that they * were added after builder configuration has been applied. Setting this value will * replace any previously configured customizers. * @param customizers the customizers to set * @return a new builder instance * @see #additionalCustomizers(RestTemplateCustomizer...) */ public RestTemplateBuilder customizers(Collection customizers) { Assert.notNull(customizers, "Customizers must not be null"); return new RestTemplateBuilder(this.requestFactoryCustomizer, this.detectRequestFactory, this.rootUri, this.messageConverters, this.interceptors, this.requestFactory, this.uriTemplateHandler, this.errorHandler, this.basicAuthentication, this.defaultHeaders, copiedSetOf(customizers), this.requestCustomizers); } /** * Add {@link RestTemplateCustomizer RestTemplateCustomizers} that should be applied * to the {@link RestTemplate}. Customizers are applied in the order that they were * added after builder configuration has been applied. * @param customizers the customizers to add * @return a new builder instance * @see #customizers(RestTemplateCustomizer...) */ public RestTemplateBuilder additionalCustomizers(RestTemplateCustomizer... customizers) { Assert.notNull(customizers, "Customizers must not be null"); return additionalCustomizers(Arrays.asList(customizers)); } /** * Add {@link RestTemplateCustomizer RestTemplateCustomizers} that should be applied * to the {@link RestTemplate}. Customizers are applied in the order that they were * added after builder configuration has been applied. * @param customizers the customizers to add * @return a new builder instance * @see #customizers(RestTemplateCustomizer...) */ public RestTemplateBuilder additionalCustomizers(Collection customizers) { Assert.notNull(customizers, "RestTemplateCustomizers must not be null"); return new RestTemplateBuilder(this.requestFactoryCustomizer, this.detectRequestFactory, this.rootUri, this.messageConverters, this.interceptors, this.requestFactory, this.uriTemplateHandler, this.errorHandler, this.basicAuthentication, this.defaultHeaders, append(this.customizers, customizers), this.requestCustomizers); } /** * Set the {@link RestTemplateRequestCustomizer RestTemplateRequestCustomizers} that * should be applied to the {@link ClientHttpRequest}. Customizers are applied in the * order that they were added. Setting this value will replace any previously * configured request customizers. * @param requestCustomizers the request customizers to set * @return a new builder instance * @since 2.2.0 * @see #additionalRequestCustomizers(RestTemplateRequestCustomizer...) */ public RestTemplateBuilder requestCustomizers(RestTemplateRequestCustomizer... requestCustomizers) { Assert.notNull(requestCustomizers, "RequestCustomizers must not be null"); return requestCustomizers(Arrays.asList(requestCustomizers)); } /** * Set the {@link RestTemplateRequestCustomizer RestTemplateRequestCustomizers} that * should be applied to the {@link ClientHttpRequest}. Customizers are applied in the * order that they were added. Setting this value will replace any previously * configured request customizers. * @param requestCustomizers the request customizers to set * @return a new builder instance * @since 2.2.0 * @see #additionalRequestCustomizers(RestTemplateRequestCustomizer...) */ public RestTemplateBuilder requestCustomizers( Collection> requestCustomizers) { Assert.notNull(requestCustomizers, "RequestCustomizers must not be null"); return new RestTemplateBuilder(this.requestFactoryCustomizer, this.detectRequestFactory, this.rootUri, this.messageConverters, this.interceptors, this.requestFactory, this.uriTemplateHandler, this.errorHandler, this.basicAuthentication, this.defaultHeaders, this.customizers, copiedSetOf(requestCustomizers)); } /** * Add the {@link RestTemplateRequestCustomizer RestTemplateRequestCustomizers} that * should be applied to the {@link ClientHttpRequest}. Customizers are applied in the * order that they were added. * @param requestCustomizers the request customizers to add * @return a new builder instance * @since 2.2.0 * @see #requestCustomizers(RestTemplateRequestCustomizer...) */ public RestTemplateBuilder additionalRequestCustomizers(RestTemplateRequestCustomizer... requestCustomizers) { Assert.notNull(requestCustomizers, "RequestCustomizers must not be null"); return additionalRequestCustomizers(Arrays.asList(requestCustomizers)); } /** * Add the {@link RestTemplateRequestCustomizer RestTemplateRequestCustomizers} that * should be applied to the {@link ClientHttpRequest}. Customizers are applied in the * order that they were added. * @param requestCustomizers the request customizers to add * @return a new builder instance * @since 2.2.0 * @see #requestCustomizers(Collection) */ public RestTemplateBuilder additionalRequestCustomizers( Collection> requestCustomizers) { Assert.notNull(requestCustomizers, "RequestCustomizers must not be null"); return new RestTemplateBuilder(this.requestFactoryCustomizer, this.detectRequestFactory, this.rootUri, this.messageConverters, this.interceptors, this.requestFactory, this.uriTemplateHandler, this.errorHandler, this.basicAuthentication, this.defaultHeaders, this.customizers, append(this.requestCustomizers, requestCustomizers)); } /** * Build a new {@link RestTemplate} instance and configure it using this builder. * @return a configured {@link RestTemplate} instance. * @see #build(Class) * @see #configure(RestTemplate) */ public RestTemplate build() { return build(RestTemplate.class); } /** * Build a new {@link RestTemplate} instance of the specified type and configure it * using this builder. * @param the type of rest template * @param restTemplateClass the template type to create * @return a configured {@link RestTemplate} instance. * @see RestTemplateBuilder#build() * @see #configure(RestTemplate) */ public T build(Class restTemplateClass) { return configure(BeanUtils.instantiateClass(restTemplateClass)); } /** * Configure the provided {@link RestTemplate} instance using this builder. * @param the type of rest template * @param restTemplate the {@link RestTemplate} to configure * @return the rest template instance * @see RestTemplateBuilder#build() * @see RestTemplateBuilder#build(Class) */ public T configure(T restTemplate) { ClientHttpRequestFactory requestFactory = buildRequestFactory(); if (requestFactory != null) { restTemplate.setRequestFactory(requestFactory); } addClientHttpRequestInitializer(restTemplate); if (!CollectionUtils.isEmpty(this.messageConverters)) { restTemplate.setMessageConverters(new ArrayList<>(this.messageConverters)); } if (this.uriTemplateHandler != null) { restTemplate.setUriTemplateHandler(this.uriTemplateHandler); } if (this.errorHandler != null) { restTemplate.setErrorHandler(this.errorHandler); } if (this.rootUri != null) { RootUriTemplateHandler.addTo(restTemplate, this.rootUri); } restTemplate.getInterceptors().addAll(this.interceptors); if (!CollectionUtils.isEmpty(this.customizers)) { for (RestTemplateCustomizer customizer : this.customizers) { customizer.customize(restTemplate); } } return restTemplate; } /** * Build a new {@link ClientHttpRequestFactory} instance using the settings of this * builder. * @return a {@link ClientHttpRequestFactory} or {@code null} * @since 2.2.0 */ public ClientHttpRequestFactory buildRequestFactory() { ClientHttpRequestFactory requestFactory = null; if (this.requestFactory != null) { requestFactory = this.requestFactory.get(); } else if (this.detectRequestFactory) { requestFactory = new ClientHttpRequestFactorySupplier().get(); } if (requestFactory != null) { if (this.requestFactoryCustomizer != null) { this.requestFactoryCustomizer.accept(requestFactory); } } return requestFactory; } private void addClientHttpRequestInitializer(RestTemplate restTemplate) { if (this.basicAuthentication == null && this.defaultHeaders.isEmpty() && this.requestCustomizers.isEmpty()) { return; } restTemplate.getClientHttpRequestInitializers().add(new RestTemplateBuilderClientHttpRequestInitializer( this.basicAuthentication, this.defaultHeaders, this.requestCustomizers)); } @SuppressWarnings("unchecked") private Set copiedSetOf(T... items) { return copiedSetOf(Arrays.asList(items)); } private Set copiedSetOf(Collection collection) { return Collections.unmodifiableSet(new LinkedHashSet<>(collection)); } private static List copiedListOf(T[] items) { return Collections.unmodifiableList(Arrays.asList(Arrays.copyOf(items, items.length))); } private static Set append(Collection collection, Collection additions) { Set result = new LinkedHashSet<>((collection != null) ? collection : Collections.emptySet()); if (additions != null) { result.addAll(additions); } return Collections.unmodifiableSet(result); } private static Map> append(Map> map, K key, V[] values) { Map> result = new LinkedHashMap<>((map != null) ? map : Collections.emptyMap()); if (values != null) { result.put(key, copiedListOf(values)); } return Collections.unmodifiableMap(result); } /** * Internal customizer used to apply {@link ClientHttpRequestFactory} settings. */ private static class RequestFactoryCustomizer implements Consumer { 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) { return method; } throw new IllegalStateException("Request factory " + requestFactory.getClass() + " does not have a suitable " + methodName + " method"); } private void invoke(ClientHttpRequestFactory requestFactory, Method method, Object... parameters) { ReflectionUtils.invokeMethod(method, requestFactory, parameters); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy