Skip to content

Commit 11d4426

Browse files
committed
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
1 parent 04ae0cd commit 11d4426

File tree

2 files changed

+41
-36
lines changed

2 files changed

+41
-36
lines changed

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/client/RestTemplateBuilder.java

Lines changed: 32 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2017 the original author or authors.
2+
* Copyright 2012-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -27,6 +27,7 @@
2727
import java.util.LinkedHashSet;
2828
import java.util.Map;
2929
import java.util.Set;
30+
import java.util.function.Supplier;
3031

3132
import org.springframework.beans.BeanUtils;
3233
import org.springframework.http.client.AbstractClientHttpRequestFactoryWrapper;
@@ -58,6 +59,7 @@
5859
* @author Stephane Nicoll
5960
* @author Phillip Webb
6061
* @author Andy Wilkinson
62+
* @author Brian Clozel
6163
* @since 1.4.0
6264
*/
6365
public class RestTemplateBuilder {
@@ -81,7 +83,7 @@ public class RestTemplateBuilder {
8183

8284
private final Set<HttpMessageConverter<?>> messageConverters;
8385

84-
private final ClientHttpRequestFactory requestFactory;
86+
private final Supplier<ClientHttpRequestFactory> requestFactorySupplier;
8587

8688
private final UriTemplateHandler uriTemplateHandler;
8789

@@ -105,7 +107,7 @@ public RestTemplateBuilder(RestTemplateCustomizer... customizers) {
105107
this.detectRequestFactory = true;
106108
this.rootUri = null;
107109
this.messageConverters = null;
108-
this.requestFactory = null;
110+
this.requestFactorySupplier = null;
109111
this.uriTemplateHandler = null;
110112
this.errorHandler = null;
111113
this.basicAuthorization = null;
@@ -117,7 +119,7 @@ public RestTemplateBuilder(RestTemplateCustomizer... customizers) {
117119

118120
private RestTemplateBuilder(boolean detectRequestFactory, String rootUri,
119121
Set<HttpMessageConverter<?>> messageConverters,
120-
ClientHttpRequestFactory requestFactory,
122+
Supplier<ClientHttpRequestFactory> requestFactorySupplier,
121123
UriTemplateHandler uriTemplateHandler, ResponseErrorHandler errorHandler,
122124
BasicAuthorizationInterceptor basicAuthorization,
123125
Set<RestTemplateCustomizer> restTemplateCustomizers,
@@ -126,7 +128,7 @@ private RestTemplateBuilder(boolean detectRequestFactory, String rootUri,
126128
this.detectRequestFactory = detectRequestFactory;
127129
this.rootUri = rootUri;
128130
this.messageConverters = messageConverters;
129-
this.requestFactory = requestFactory;
131+
this.requestFactorySupplier = requestFactorySupplier;
130132
this.uriTemplateHandler = uriTemplateHandler;
131133
this.errorHandler = errorHandler;
132134
this.basicAuthorization = basicAuthorization;
@@ -144,7 +146,7 @@ private RestTemplateBuilder(boolean detectRequestFactory, String rootUri,
144146
*/
145147
public RestTemplateBuilder detectRequestFactory(boolean detectRequestFactory) {
146148
return new RestTemplateBuilder(detectRequestFactory, this.rootUri,
147-
this.messageConverters, this.requestFactory, this.uriTemplateHandler,
149+
this.messageConverters, this.requestFactorySupplier, this.uriTemplateHandler,
148150
this.errorHandler, this.basicAuthorization, this.restTemplateCustomizers,
149151
this.requestFactoryCustomizers, this.interceptors);
150152
}
@@ -157,7 +159,7 @@ public RestTemplateBuilder detectRequestFactory(boolean detectRequestFactory) {
157159
*/
158160
public RestTemplateBuilder rootUri(String rootUri) {
159161
return new RestTemplateBuilder(this.detectRequestFactory, rootUri,
160-
this.messageConverters, this.requestFactory, this.uriTemplateHandler,
162+
this.messageConverters, this.requestFactorySupplier, this.uriTemplateHandler,
161163
this.errorHandler, this.basicAuthorization, this.restTemplateCustomizers,
162164
this.requestFactoryCustomizers, this.interceptors);
163165
}
@@ -190,7 +192,7 @@ public RestTemplateBuilder messageConverters(
190192
return new RestTemplateBuilder(this.detectRequestFactory, this.rootUri,
191193
Collections.unmodifiableSet(
192194
new LinkedHashSet<HttpMessageConverter<?>>(messageConverters)),
193-
this.requestFactory, this.uriTemplateHandler, this.errorHandler,
195+
this.requestFactorySupplier, this.uriTemplateHandler, this.errorHandler,
194196
this.basicAuthorization, this.restTemplateCustomizers,
195197
this.requestFactoryCustomizers, this.interceptors);
196198
}
@@ -219,7 +221,7 @@ public RestTemplateBuilder additionalMessageConverters(
219221
Collection<? extends HttpMessageConverter<?>> messageConverters) {
220222
Assert.notNull(messageConverters, "MessageConverters must not be null");
221223
return new RestTemplateBuilder(this.detectRequestFactory, this.rootUri,
222-
append(this.messageConverters, messageConverters), this.requestFactory,
224+
append(this.messageConverters, messageConverters), this.requestFactorySupplier,
223225
this.uriTemplateHandler, this.errorHandler, this.basicAuthorization,
224226
this.restTemplateCustomizers, this.requestFactoryCustomizers,
225227
this.interceptors);
@@ -236,7 +238,7 @@ public RestTemplateBuilder defaultMessageConverters() {
236238
return new RestTemplateBuilder(this.detectRequestFactory, this.rootUri,
237239
Collections.unmodifiableSet(
238240
new LinkedHashSet<>(new RestTemplate().getMessageConverters())),
239-
this.requestFactory, this.uriTemplateHandler, this.errorHandler,
241+
this.requestFactorySupplier, this.uriTemplateHandler, this.errorHandler,
240242
this.basicAuthorization, this.restTemplateCustomizers,
241243
this.requestFactoryCustomizers, this.interceptors);
242244
}
@@ -269,7 +271,7 @@ public RestTemplateBuilder interceptors(
269271
Collection<ClientHttpRequestInterceptor> interceptors) {
270272
Assert.notNull(interceptors, "interceptors must not be null");
271273
return new RestTemplateBuilder(this.detectRequestFactory, this.rootUri,
272-
this.messageConverters, this.requestFactory, this.uriTemplateHandler,
274+
this.messageConverters, this.requestFactorySupplier, this.uriTemplateHandler,
273275
this.errorHandler, this.basicAuthorization, this.restTemplateCustomizers,
274276
this.requestFactoryCustomizers,
275277
Collections.unmodifiableSet(new LinkedHashSet<>(interceptors)));
@@ -301,7 +303,7 @@ public RestTemplateBuilder additionalInterceptors(
301303
Collection<? extends ClientHttpRequestInterceptor> interceptors) {
302304
Assert.notNull(interceptors, "interceptors must not be null");
303305
return new RestTemplateBuilder(this.detectRequestFactory, this.rootUri,
304-
this.messageConverters, this.requestFactory, this.uriTemplateHandler,
306+
this.messageConverters, this.requestFactorySupplier, this.uriTemplateHandler,
305307
this.errorHandler, this.basicAuthorization, this.restTemplateCustomizers,
306308
this.requestFactoryCustomizers, append(this.interceptors, interceptors));
307309
}
@@ -315,7 +317,7 @@ public RestTemplateBuilder additionalInterceptors(
315317
public RestTemplateBuilder requestFactory(
316318
Class<? extends ClientHttpRequestFactory> requestFactory) {
317319
Assert.notNull(requestFactory, "RequestFactory must not be null");
318-
return requestFactory(createRequestFactory(requestFactory));
320+
return requestFactory(() -> createRequestFactory(requestFactory));
319321
}
320322

321323
private ClientHttpRequestFactory createRequestFactory(
@@ -331,15 +333,17 @@ private ClientHttpRequestFactory createRequestFactory(
331333
}
332334

333335
/**
334-
* Set the {@link ClientHttpRequestFactory} that should be used with the
335-
* {@link RestTemplate}.
336-
* @param requestFactory the request factory to use
336+
* Set the {@code Supplier} of {@link ClientHttpRequestFactory}
337+
* that should be called each time we {@link #build()} a new
338+
* {@link RestTemplate} instance.
339+
* @param requestFactorySupplier the supplier for the request factory
337340
* @return a new builder instance
341+
* @since 2.0.0
338342
*/
339-
public RestTemplateBuilder requestFactory(ClientHttpRequestFactory requestFactory) {
340-
Assert.notNull(requestFactory, "RequestFactory must not be null");
343+
public RestTemplateBuilder requestFactory(Supplier<ClientHttpRequestFactory> requestFactorySupplier) {
344+
Assert.notNull(requestFactorySupplier, "RequestFactory Supplier must not be null");
341345
return new RestTemplateBuilder(this.detectRequestFactory, this.rootUri,
342-
this.messageConverters, requestFactory, this.uriTemplateHandler,
346+
this.messageConverters, requestFactorySupplier, this.uriTemplateHandler,
343347
this.errorHandler, this.basicAuthorization, this.restTemplateCustomizers,
344348
this.requestFactoryCustomizers, this.interceptors);
345349
}
@@ -353,7 +357,7 @@ public RestTemplateBuilder requestFactory(ClientHttpRequestFactory requestFactor
353357
public RestTemplateBuilder uriTemplateHandler(UriTemplateHandler uriTemplateHandler) {
354358
Assert.notNull(uriTemplateHandler, "UriTemplateHandler must not be null");
355359
return new RestTemplateBuilder(this.detectRequestFactory, this.rootUri,
356-
this.messageConverters, this.requestFactory, uriTemplateHandler,
360+
this.messageConverters, this.requestFactorySupplier, uriTemplateHandler,
357361
this.errorHandler, this.basicAuthorization, this.restTemplateCustomizers,
358362
this.requestFactoryCustomizers, this.interceptors);
359363
}
@@ -367,7 +371,7 @@ public RestTemplateBuilder uriTemplateHandler(UriTemplateHandler uriTemplateHand
367371
public RestTemplateBuilder errorHandler(ResponseErrorHandler errorHandler) {
368372
Assert.notNull(errorHandler, "ErrorHandler must not be null");
369373
return new RestTemplateBuilder(this.detectRequestFactory, this.rootUri,
370-
this.messageConverters, this.requestFactory, this.uriTemplateHandler,
374+
this.messageConverters, this.requestFactorySupplier, this.uriTemplateHandler,
371375
errorHandler, this.basicAuthorization, this.restTemplateCustomizers,
372376
this.requestFactoryCustomizers, this.interceptors);
373377
}
@@ -381,7 +385,7 @@ public RestTemplateBuilder errorHandler(ResponseErrorHandler errorHandler) {
381385
*/
382386
public RestTemplateBuilder basicAuthorization(String username, String password) {
383387
return new RestTemplateBuilder(this.detectRequestFactory, this.rootUri,
384-
this.messageConverters, this.requestFactory, this.uriTemplateHandler,
388+
this.messageConverters, this.requestFactorySupplier, this.uriTemplateHandler,
385389
this.errorHandler, new BasicAuthorizationInterceptor(username, password),
386390
this.restTemplateCustomizers, this.requestFactoryCustomizers,
387391
this.interceptors);
@@ -417,7 +421,7 @@ public RestTemplateBuilder customizers(
417421
Assert.notNull(restTemplateCustomizers,
418422
"RestTemplateCustomizers must not be null");
419423
return new RestTemplateBuilder(this.detectRequestFactory, this.rootUri,
420-
this.messageConverters, this.requestFactory, this.uriTemplateHandler,
424+
this.messageConverters, this.requestFactorySupplier, this.uriTemplateHandler,
421425
this.errorHandler, this.basicAuthorization,
422426
Collections.unmodifiableSet(new LinkedHashSet<RestTemplateCustomizer>(
423427
restTemplateCustomizers)),
@@ -451,7 +455,7 @@ public RestTemplateBuilder additionalCustomizers(
451455
Collection<? extends RestTemplateCustomizer> customizers) {
452456
Assert.notNull(customizers, "RestTemplateCustomizers must not be null");
453457
return new RestTemplateBuilder(this.detectRequestFactory, this.rootUri,
454-
this.messageConverters, this.requestFactory, this.uriTemplateHandler,
458+
this.messageConverters, this.requestFactorySupplier, this.uriTemplateHandler,
455459
this.errorHandler, this.basicAuthorization,
456460
append(this.restTemplateCustomizers, customizers),
457461
this.requestFactoryCustomizers, this.interceptors);
@@ -465,7 +469,7 @@ public RestTemplateBuilder additionalCustomizers(
465469
*/
466470
public RestTemplateBuilder setConnectTimeout(int connectTimeout) {
467471
return new RestTemplateBuilder(this.detectRequestFactory, this.rootUri,
468-
this.messageConverters, this.requestFactory, this.uriTemplateHandler,
472+
this.messageConverters, this.requestFactorySupplier, this.uriTemplateHandler,
469473
this.errorHandler, this.basicAuthorization, this.restTemplateCustomizers,
470474
append(this.requestFactoryCustomizers,
471475
new ConnectTimeoutRequestFactoryCustomizer(connectTimeout)),
@@ -480,7 +484,7 @@ public RestTemplateBuilder setConnectTimeout(int connectTimeout) {
480484
*/
481485
public RestTemplateBuilder setReadTimeout(int readTimeout) {
482486
return new RestTemplateBuilder(this.detectRequestFactory, this.rootUri,
483-
this.messageConverters, this.requestFactory, this.uriTemplateHandler,
487+
this.messageConverters, this.requestFactorySupplier, this.uriTemplateHandler,
484488
this.errorHandler, this.basicAuthorization, this.restTemplateCustomizers,
485489
append(this.requestFactoryCustomizers,
486490
new ReadTimeoutRequestFactoryCustomizer(readTimeout)),
@@ -547,8 +551,8 @@ public <T extends RestTemplate> T configure(T restTemplate) {
547551

548552
private void configureRequestFactory(RestTemplate restTemplate) {
549553
ClientHttpRequestFactory requestFactory = null;
550-
if (this.requestFactory != null) {
551-
requestFactory = this.requestFactory;
554+
if (this.requestFactorySupplier != null) {
555+
requestFactory = this.requestFactorySupplier.get();
552556
}
553557
else if (this.detectRequestFactory) {
554558
requestFactory = detectRequestFactory();

spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/client/RestTemplateBuilderTests.java

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2017 the original author or authors.
2+
* Copyright 2012-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -18,6 +18,7 @@
1818

1919
import java.util.Collections;
2020
import java.util.Set;
21+
import java.util.function.Supplier;
2122

2223
import org.apache.http.client.config.RequestConfig;
2324
import org.junit.Before;
@@ -273,16 +274,16 @@ public void requestFactoryPackagePrivateClassShouldApply() {
273274
}
274275

275276
@Test
276-
public void requestFactoryWhenFactoryIsNullShouldThrowException() {
277+
public void requestFactoryWhenSupplierIsNullShouldThrowException() {
277278
this.thrown.expect(IllegalArgumentException.class);
278-
this.thrown.expectMessage("RequestFactory must not be null");
279-
this.builder.requestFactory((ClientHttpRequestFactory) null);
279+
this.thrown.expectMessage("RequestFactory Supplier must not be null");
280+
this.builder.requestFactory((Supplier<ClientHttpRequestFactory>) null);
280281
}
281282

282283
@Test
283284
public void requestFactoryShouldApply() {
284285
ClientHttpRequestFactory requestFactory = mock(ClientHttpRequestFactory.class);
285-
RestTemplate template = this.builder.requestFactory(requestFactory).build();
286+
RestTemplate template = this.builder.requestFactory(() -> requestFactory).build();
286287
assertThat(template.getRequestFactory()).isSameAs(requestFactory);
287288
}
288289

@@ -466,7 +467,7 @@ public void readTimeoutCanBeConfiguredOnOkHttp3RequestFactory() {
466467
@Test
467468
public void connectTimeoutCanBeConfiguredOnAWrappedRequestFactory() {
468469
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
469-
this.builder.requestFactory(new BufferingClientHttpRequestFactory(requestFactory))
470+
this.builder.requestFactory(() -> new BufferingClientHttpRequestFactory(requestFactory))
470471
.setConnectTimeout(1234).build();
471472
assertThat(ReflectionTestUtils.getField(requestFactory, "connectTimeout"))
472473
.isEqualTo(1234);
@@ -475,7 +476,7 @@ public void connectTimeoutCanBeConfiguredOnAWrappedRequestFactory() {
475476
@Test
476477
public void readTimeoutCanBeConfiguredOnAWrappedRequestFactory() {
477478
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
478-
this.builder.requestFactory(new BufferingClientHttpRequestFactory(requestFactory))
479+
this.builder.requestFactory(() -> new BufferingClientHttpRequestFactory(requestFactory))
479480
.setReadTimeout(1234).build();
480481
assertThat(ReflectionTestUtils.getField(requestFactory, "readTimeout"))
481482
.isEqualTo(1234);
@@ -485,7 +486,7 @@ public void readTimeoutCanBeConfiguredOnAWrappedRequestFactory() {
485486
public void unwrappingDoesNotAffectRequestFactoryThatIsSetOnTheBuiltTemplate() {
486487
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
487488
RestTemplate template = this.builder
488-
.requestFactory(new BufferingClientHttpRequestFactory(requestFactory))
489+
.requestFactory(() -> new BufferingClientHttpRequestFactory(requestFactory))
489490
.build();
490491
assertThat(template.getRequestFactory())
491492
.isInstanceOf(BufferingClientHttpRequestFactory.class);

0 commit comments

Comments
 (0)