Provide client factory with supplier in RestTemplateBuilder

This commit removes
`RestTemplateBuilder.requestFactory(ClientHttpRequestFactory factory)`
because it can be misleading. This builder class is meant to be
immutable, but calling that method and then timeout related ones will
affect the `ClientHttpRequestFactory` instance.

Instead, this method is replaced with a
`Supplier<ClientHttpRequestFactory>` that is called every time a
`RestTemplate` is being built.

That approach may reduce the reusability of request factories, but it is
much more consistent.

Closes gh-11255
pull/11527/head
Brian Clozel 7 years ago
parent 04ae0cd62c
commit 11d4426b4d

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2017 the original author or authors. * Copyright 2012-2018 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.
@ -27,6 +27,7 @@ import java.util.LinkedHashMap;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.function.Supplier;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
import org.springframework.http.client.AbstractClientHttpRequestFactoryWrapper; import org.springframework.http.client.AbstractClientHttpRequestFactoryWrapper;
@ -58,6 +59,7 @@ import org.springframework.web.util.UriTemplateHandler;
* @author Stephane Nicoll * @author Stephane Nicoll
* @author Phillip Webb * @author Phillip Webb
* @author Andy Wilkinson * @author Andy Wilkinson
* @author Brian Clozel
* @since 1.4.0 * @since 1.4.0
*/ */
public class RestTemplateBuilder { public class RestTemplateBuilder {
@ -81,7 +83,7 @@ public class RestTemplateBuilder {
private final Set<HttpMessageConverter<?>> messageConverters; private final Set<HttpMessageConverter<?>> messageConverters;
private final ClientHttpRequestFactory requestFactory; private final Supplier<ClientHttpRequestFactory> requestFactorySupplier;
private final UriTemplateHandler uriTemplateHandler; private final UriTemplateHandler uriTemplateHandler;
@ -105,7 +107,7 @@ public class RestTemplateBuilder {
this.detectRequestFactory = true; this.detectRequestFactory = true;
this.rootUri = null; this.rootUri = null;
this.messageConverters = null; this.messageConverters = null;
this.requestFactory = null; this.requestFactorySupplier = null;
this.uriTemplateHandler = null; this.uriTemplateHandler = null;
this.errorHandler = null; this.errorHandler = null;
this.basicAuthorization = null; this.basicAuthorization = null;
@ -117,7 +119,7 @@ public class RestTemplateBuilder {
private RestTemplateBuilder(boolean detectRequestFactory, String rootUri, private RestTemplateBuilder(boolean detectRequestFactory, String rootUri,
Set<HttpMessageConverter<?>> messageConverters, Set<HttpMessageConverter<?>> messageConverters,
ClientHttpRequestFactory requestFactory, Supplier<ClientHttpRequestFactory> requestFactorySupplier,
UriTemplateHandler uriTemplateHandler, ResponseErrorHandler errorHandler, UriTemplateHandler uriTemplateHandler, ResponseErrorHandler errorHandler,
BasicAuthorizationInterceptor basicAuthorization, BasicAuthorizationInterceptor basicAuthorization,
Set<RestTemplateCustomizer> restTemplateCustomizers, Set<RestTemplateCustomizer> restTemplateCustomizers,
@ -126,7 +128,7 @@ public class RestTemplateBuilder {
this.detectRequestFactory = detectRequestFactory; this.detectRequestFactory = detectRequestFactory;
this.rootUri = rootUri; this.rootUri = rootUri;
this.messageConverters = messageConverters; this.messageConverters = messageConverters;
this.requestFactory = requestFactory; this.requestFactorySupplier = requestFactorySupplier;
this.uriTemplateHandler = uriTemplateHandler; this.uriTemplateHandler = uriTemplateHandler;
this.errorHandler = errorHandler; this.errorHandler = errorHandler;
this.basicAuthorization = basicAuthorization; this.basicAuthorization = basicAuthorization;
@ -144,7 +146,7 @@ public class RestTemplateBuilder {
*/ */
public RestTemplateBuilder detectRequestFactory(boolean detectRequestFactory) { public RestTemplateBuilder detectRequestFactory(boolean detectRequestFactory) {
return new RestTemplateBuilder(detectRequestFactory, this.rootUri, return new RestTemplateBuilder(detectRequestFactory, this.rootUri,
this.messageConverters, this.requestFactory, this.uriTemplateHandler, this.messageConverters, this.requestFactorySupplier, this.uriTemplateHandler,
this.errorHandler, this.basicAuthorization, this.restTemplateCustomizers, this.errorHandler, this.basicAuthorization, this.restTemplateCustomizers,
this.requestFactoryCustomizers, this.interceptors); this.requestFactoryCustomizers, this.interceptors);
} }
@ -157,7 +159,7 @@ public class RestTemplateBuilder {
*/ */
public RestTemplateBuilder rootUri(String rootUri) { public RestTemplateBuilder rootUri(String rootUri) {
return new RestTemplateBuilder(this.detectRequestFactory, rootUri, return new RestTemplateBuilder(this.detectRequestFactory, rootUri,
this.messageConverters, this.requestFactory, this.uriTemplateHandler, this.messageConverters, this.requestFactorySupplier, this.uriTemplateHandler,
this.errorHandler, this.basicAuthorization, this.restTemplateCustomizers, this.errorHandler, this.basicAuthorization, this.restTemplateCustomizers,
this.requestFactoryCustomizers, this.interceptors); this.requestFactoryCustomizers, this.interceptors);
} }
@ -190,7 +192,7 @@ public class RestTemplateBuilder {
return new RestTemplateBuilder(this.detectRequestFactory, this.rootUri, return new RestTemplateBuilder(this.detectRequestFactory, this.rootUri,
Collections.unmodifiableSet( Collections.unmodifiableSet(
new LinkedHashSet<HttpMessageConverter<?>>(messageConverters)), new LinkedHashSet<HttpMessageConverter<?>>(messageConverters)),
this.requestFactory, this.uriTemplateHandler, this.errorHandler, this.requestFactorySupplier, this.uriTemplateHandler, this.errorHandler,
this.basicAuthorization, this.restTemplateCustomizers, this.basicAuthorization, this.restTemplateCustomizers,
this.requestFactoryCustomizers, this.interceptors); this.requestFactoryCustomizers, this.interceptors);
} }
@ -219,7 +221,7 @@ public class RestTemplateBuilder {
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.detectRequestFactory, this.rootUri, return new RestTemplateBuilder(this.detectRequestFactory, this.rootUri,
append(this.messageConverters, messageConverters), this.requestFactory, append(this.messageConverters, messageConverters), this.requestFactorySupplier,
this.uriTemplateHandler, this.errorHandler, this.basicAuthorization, this.uriTemplateHandler, this.errorHandler, this.basicAuthorization,
this.restTemplateCustomizers, this.requestFactoryCustomizers, this.restTemplateCustomizers, this.requestFactoryCustomizers,
this.interceptors); this.interceptors);
@ -236,7 +238,7 @@ public class RestTemplateBuilder {
return new RestTemplateBuilder(this.detectRequestFactory, this.rootUri, return new RestTemplateBuilder(this.detectRequestFactory, this.rootUri,
Collections.unmodifiableSet( Collections.unmodifiableSet(
new LinkedHashSet<>(new RestTemplate().getMessageConverters())), new LinkedHashSet<>(new RestTemplate().getMessageConverters())),
this.requestFactory, this.uriTemplateHandler, this.errorHandler, this.requestFactorySupplier, this.uriTemplateHandler, this.errorHandler,
this.basicAuthorization, this.restTemplateCustomizers, this.basicAuthorization, this.restTemplateCustomizers,
this.requestFactoryCustomizers, this.interceptors); this.requestFactoryCustomizers, this.interceptors);
} }
@ -269,7 +271,7 @@ public class RestTemplateBuilder {
Collection<ClientHttpRequestInterceptor> interceptors) { Collection<ClientHttpRequestInterceptor> interceptors) {
Assert.notNull(interceptors, "interceptors must not be null"); Assert.notNull(interceptors, "interceptors must not be null");
return new RestTemplateBuilder(this.detectRequestFactory, this.rootUri, return new RestTemplateBuilder(this.detectRequestFactory, this.rootUri,
this.messageConverters, this.requestFactory, this.uriTemplateHandler, this.messageConverters, this.requestFactorySupplier, this.uriTemplateHandler,
this.errorHandler, this.basicAuthorization, this.restTemplateCustomizers, this.errorHandler, this.basicAuthorization, this.restTemplateCustomizers,
this.requestFactoryCustomizers, this.requestFactoryCustomizers,
Collections.unmodifiableSet(new LinkedHashSet<>(interceptors))); Collections.unmodifiableSet(new LinkedHashSet<>(interceptors)));
@ -301,7 +303,7 @@ public class RestTemplateBuilder {
Collection<? extends ClientHttpRequestInterceptor> interceptors) { Collection<? extends ClientHttpRequestInterceptor> interceptors) {
Assert.notNull(interceptors, "interceptors must not be null"); Assert.notNull(interceptors, "interceptors must not be null");
return new RestTemplateBuilder(this.detectRequestFactory, this.rootUri, return new RestTemplateBuilder(this.detectRequestFactory, this.rootUri,
this.messageConverters, this.requestFactory, this.uriTemplateHandler, this.messageConverters, this.requestFactorySupplier, this.uriTemplateHandler,
this.errorHandler, this.basicAuthorization, this.restTemplateCustomizers, this.errorHandler, this.basicAuthorization, this.restTemplateCustomizers,
this.requestFactoryCustomizers, append(this.interceptors, interceptors)); this.requestFactoryCustomizers, append(this.interceptors, interceptors));
} }
@ -315,7 +317,7 @@ public class RestTemplateBuilder {
public RestTemplateBuilder requestFactory( public RestTemplateBuilder requestFactory(
Class<? extends ClientHttpRequestFactory> requestFactory) { Class<? extends ClientHttpRequestFactory> requestFactory) {
Assert.notNull(requestFactory, "RequestFactory must not be null"); Assert.notNull(requestFactory, "RequestFactory must not be null");
return requestFactory(createRequestFactory(requestFactory)); return requestFactory(() -> createRequestFactory(requestFactory));
} }
private ClientHttpRequestFactory createRequestFactory( private ClientHttpRequestFactory createRequestFactory(
@ -331,15 +333,17 @@ public class RestTemplateBuilder {
} }
/** /**
* Set the {@link ClientHttpRequestFactory} that should be used with the * Set the {@code Supplier} of {@link ClientHttpRequestFactory}
* {@link RestTemplate}. * that should be called each time we {@link #build()} a new
* @param requestFactory the request factory to use * {@link RestTemplate} instance.
* @param requestFactorySupplier the supplier for the request factory
* @return a new builder instance * @return a new builder instance
* @since 2.0.0
*/ */
public RestTemplateBuilder requestFactory(ClientHttpRequestFactory requestFactory) { public RestTemplateBuilder requestFactory(Supplier<ClientHttpRequestFactory> requestFactorySupplier) {
Assert.notNull(requestFactory, "RequestFactory must not be null"); Assert.notNull(requestFactorySupplier, "RequestFactory Supplier must not be null");
return new RestTemplateBuilder(this.detectRequestFactory, this.rootUri, return new RestTemplateBuilder(this.detectRequestFactory, this.rootUri,
this.messageConverters, requestFactory, this.uriTemplateHandler, this.messageConverters, requestFactorySupplier, this.uriTemplateHandler,
this.errorHandler, this.basicAuthorization, this.restTemplateCustomizers, this.errorHandler, this.basicAuthorization, this.restTemplateCustomizers,
this.requestFactoryCustomizers, this.interceptors); this.requestFactoryCustomizers, this.interceptors);
} }
@ -353,7 +357,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.detectRequestFactory, this.rootUri, return new RestTemplateBuilder(this.detectRequestFactory, this.rootUri,
this.messageConverters, this.requestFactory, uriTemplateHandler, this.messageConverters, this.requestFactorySupplier, uriTemplateHandler,
this.errorHandler, this.basicAuthorization, this.restTemplateCustomizers, this.errorHandler, this.basicAuthorization, this.restTemplateCustomizers,
this.requestFactoryCustomizers, this.interceptors); this.requestFactoryCustomizers, this.interceptors);
} }
@ -367,7 +371,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.detectRequestFactory, this.rootUri, return new RestTemplateBuilder(this.detectRequestFactory, this.rootUri,
this.messageConverters, this.requestFactory, this.uriTemplateHandler, this.messageConverters, this.requestFactorySupplier, this.uriTemplateHandler,
errorHandler, this.basicAuthorization, this.restTemplateCustomizers, errorHandler, this.basicAuthorization, this.restTemplateCustomizers,
this.requestFactoryCustomizers, this.interceptors); this.requestFactoryCustomizers, this.interceptors);
} }
@ -381,7 +385,7 @@ public class RestTemplateBuilder {
*/ */
public RestTemplateBuilder basicAuthorization(String username, String password) { public RestTemplateBuilder basicAuthorization(String username, String password) {
return new RestTemplateBuilder(this.detectRequestFactory, this.rootUri, return new RestTemplateBuilder(this.detectRequestFactory, this.rootUri,
this.messageConverters, this.requestFactory, this.uriTemplateHandler, this.messageConverters, this.requestFactorySupplier, this.uriTemplateHandler,
this.errorHandler, new BasicAuthorizationInterceptor(username, password), this.errorHandler, new BasicAuthorizationInterceptor(username, password),
this.restTemplateCustomizers, this.requestFactoryCustomizers, this.restTemplateCustomizers, this.requestFactoryCustomizers,
this.interceptors); this.interceptors);
@ -417,7 +421,7 @@ public class RestTemplateBuilder {
Assert.notNull(restTemplateCustomizers, Assert.notNull(restTemplateCustomizers,
"RestTemplateCustomizers must not be null"); "RestTemplateCustomizers must not be null");
return new RestTemplateBuilder(this.detectRequestFactory, this.rootUri, return new RestTemplateBuilder(this.detectRequestFactory, this.rootUri,
this.messageConverters, this.requestFactory, this.uriTemplateHandler, this.messageConverters, this.requestFactorySupplier, this.uriTemplateHandler,
this.errorHandler, this.basicAuthorization, this.errorHandler, this.basicAuthorization,
Collections.unmodifiableSet(new LinkedHashSet<RestTemplateCustomizer>( Collections.unmodifiableSet(new LinkedHashSet<RestTemplateCustomizer>(
restTemplateCustomizers)), restTemplateCustomizers)),
@ -451,7 +455,7 @@ public class RestTemplateBuilder {
Collection<? extends RestTemplateCustomizer> customizers) { Collection<? extends RestTemplateCustomizer> customizers) {
Assert.notNull(customizers, "RestTemplateCustomizers must not be null"); Assert.notNull(customizers, "RestTemplateCustomizers must not be null");
return new RestTemplateBuilder(this.detectRequestFactory, this.rootUri, return new RestTemplateBuilder(this.detectRequestFactory, this.rootUri,
this.messageConverters, this.requestFactory, this.uriTemplateHandler, this.messageConverters, this.requestFactorySupplier, this.uriTemplateHandler,
this.errorHandler, this.basicAuthorization, this.errorHandler, this.basicAuthorization,
append(this.restTemplateCustomizers, customizers), append(this.restTemplateCustomizers, customizers),
this.requestFactoryCustomizers, this.interceptors); this.requestFactoryCustomizers, this.interceptors);
@ -465,7 +469,7 @@ public class RestTemplateBuilder {
*/ */
public RestTemplateBuilder setConnectTimeout(int connectTimeout) { public RestTemplateBuilder setConnectTimeout(int connectTimeout) {
return new RestTemplateBuilder(this.detectRequestFactory, this.rootUri, return new RestTemplateBuilder(this.detectRequestFactory, this.rootUri,
this.messageConverters, this.requestFactory, this.uriTemplateHandler, this.messageConverters, this.requestFactorySupplier, this.uriTemplateHandler,
this.errorHandler, this.basicAuthorization, this.restTemplateCustomizers, this.errorHandler, this.basicAuthorization, this.restTemplateCustomizers,
append(this.requestFactoryCustomizers, append(this.requestFactoryCustomizers,
new ConnectTimeoutRequestFactoryCustomizer(connectTimeout)), new ConnectTimeoutRequestFactoryCustomizer(connectTimeout)),
@ -480,7 +484,7 @@ public class RestTemplateBuilder {
*/ */
public RestTemplateBuilder setReadTimeout(int readTimeout) { public RestTemplateBuilder setReadTimeout(int readTimeout) {
return new RestTemplateBuilder(this.detectRequestFactory, this.rootUri, return new RestTemplateBuilder(this.detectRequestFactory, this.rootUri,
this.messageConverters, this.requestFactory, this.uriTemplateHandler, this.messageConverters, this.requestFactorySupplier, this.uriTemplateHandler,
this.errorHandler, this.basicAuthorization, this.restTemplateCustomizers, this.errorHandler, this.basicAuthorization, this.restTemplateCustomizers,
append(this.requestFactoryCustomizers, append(this.requestFactoryCustomizers,
new ReadTimeoutRequestFactoryCustomizer(readTimeout)), new ReadTimeoutRequestFactoryCustomizer(readTimeout)),
@ -547,8 +551,8 @@ public class RestTemplateBuilder {
private void configureRequestFactory(RestTemplate restTemplate) { private void configureRequestFactory(RestTemplate restTemplate) {
ClientHttpRequestFactory requestFactory = null; ClientHttpRequestFactory requestFactory = null;
if (this.requestFactory != null) { if (this.requestFactorySupplier != null) {
requestFactory = this.requestFactory; requestFactory = this.requestFactorySupplier.get();
} }
else if (this.detectRequestFactory) { else if (this.detectRequestFactory) {
requestFactory = detectRequestFactory(); requestFactory = detectRequestFactory();

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2017 the original author or authors. * Copyright 2012-2018 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.
@ -18,6 +18,7 @@ package org.springframework.boot.web.client;
import java.util.Collections; import java.util.Collections;
import java.util.Set; import java.util.Set;
import java.util.function.Supplier;
import org.apache.http.client.config.RequestConfig; import org.apache.http.client.config.RequestConfig;
import org.junit.Before; import org.junit.Before;
@ -273,16 +274,16 @@ public class RestTemplateBuilderTests {
} }
@Test @Test
public void requestFactoryWhenFactoryIsNullShouldThrowException() { public void requestFactoryWhenSupplierIsNullShouldThrowException() {
this.thrown.expect(IllegalArgumentException.class); this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("RequestFactory must not be null"); this.thrown.expectMessage("RequestFactory Supplier must not be null");
this.builder.requestFactory((ClientHttpRequestFactory) null); this.builder.requestFactory((Supplier<ClientHttpRequestFactory>) null);
} }
@Test @Test
public void requestFactoryShouldApply() { public void requestFactoryShouldApply() {
ClientHttpRequestFactory requestFactory = mock(ClientHttpRequestFactory.class); ClientHttpRequestFactory requestFactory = mock(ClientHttpRequestFactory.class);
RestTemplate template = this.builder.requestFactory(requestFactory).build(); RestTemplate template = this.builder.requestFactory(() -> requestFactory).build();
assertThat(template.getRequestFactory()).isSameAs(requestFactory); assertThat(template.getRequestFactory()).isSameAs(requestFactory);
} }
@ -466,7 +467,7 @@ public class RestTemplateBuilderTests {
@Test @Test
public void connectTimeoutCanBeConfiguredOnAWrappedRequestFactory() { public void connectTimeoutCanBeConfiguredOnAWrappedRequestFactory() {
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory(); SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
this.builder.requestFactory(new BufferingClientHttpRequestFactory(requestFactory)) this.builder.requestFactory(() -> new BufferingClientHttpRequestFactory(requestFactory))
.setConnectTimeout(1234).build(); .setConnectTimeout(1234).build();
assertThat(ReflectionTestUtils.getField(requestFactory, "connectTimeout")) assertThat(ReflectionTestUtils.getField(requestFactory, "connectTimeout"))
.isEqualTo(1234); .isEqualTo(1234);
@ -475,7 +476,7 @@ public class RestTemplateBuilderTests {
@Test @Test
public void readTimeoutCanBeConfiguredOnAWrappedRequestFactory() { public void readTimeoutCanBeConfiguredOnAWrappedRequestFactory() {
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory(); SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
this.builder.requestFactory(new BufferingClientHttpRequestFactory(requestFactory)) this.builder.requestFactory(() -> new BufferingClientHttpRequestFactory(requestFactory))
.setReadTimeout(1234).build(); .setReadTimeout(1234).build();
assertThat(ReflectionTestUtils.getField(requestFactory, "readTimeout")) assertThat(ReflectionTestUtils.getField(requestFactory, "readTimeout"))
.isEqualTo(1234); .isEqualTo(1234);
@ -485,7 +486,7 @@ public class RestTemplateBuilderTests {
public void unwrappingDoesNotAffectRequestFactoryThatIsSetOnTheBuiltTemplate() { public void unwrappingDoesNotAffectRequestFactoryThatIsSetOnTheBuiltTemplate() {
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory(); SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
RestTemplate template = this.builder RestTemplate template = this.builder
.requestFactory(new BufferingClientHttpRequestFactory(requestFactory)) .requestFactory(() -> new BufferingClientHttpRequestFactory(requestFactory))
.build(); .build();
assertThat(template.getRequestFactory()) assertThat(template.getRequestFactory())
.isInstanceOf(BufferingClientHttpRequestFactory.class); .isInstanceOf(BufferingClientHttpRequestFactory.class);

Loading…
Cancel
Save