001/* 002 * Copyright 2012-2018 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.boot.web.client; 018 019import java.lang.reflect.Constructor; 020import java.lang.reflect.Field; 021import java.lang.reflect.Method; 022import java.time.Duration; 023import java.util.ArrayList; 024import java.util.Arrays; 025import java.util.Collection; 026import java.util.Collections; 027import java.util.LinkedHashSet; 028import java.util.Set; 029import java.util.function.Consumer; 030import java.util.function.Supplier; 031 032import org.springframework.beans.BeanUtils; 033import org.springframework.http.client.AbstractClientHttpRequestFactoryWrapper; 034import org.springframework.http.client.ClientHttpRequestFactory; 035import org.springframework.http.client.ClientHttpRequestInterceptor; 036import org.springframework.http.client.support.BasicAuthenticationInterceptor; 037import org.springframework.http.converter.HttpMessageConverter; 038import org.springframework.util.Assert; 039import org.springframework.util.CollectionUtils; 040import org.springframework.util.ReflectionUtils; 041import org.springframework.web.client.ResponseErrorHandler; 042import org.springframework.web.client.RestTemplate; 043import org.springframework.web.util.UriTemplateHandler; 044 045/** 046 * Builder that can be used to configure and create a {@link RestTemplate}. Provides 047 * convenience methods to register {@link #messageConverters(HttpMessageConverter...) 048 * converters}, {@link #errorHandler(ResponseErrorHandler) error handlers} and 049 * {@link #uriTemplateHandler(UriTemplateHandler) UriTemplateHandlers}. 050 * <p> 051 * By default the built {@link RestTemplate} will attempt to use the most suitable 052 * {@link ClientHttpRequestFactory}, call {@link #detectRequestFactory(boolean) 053 * detectRequestFactory(false)} if you prefer to keep the default. In a typical 054 * auto-configured Spring Boot application this builder is available as a bean and can be 055 * injected whenever a {@link RestTemplate} is needed. 056 * 057 * @author Stephane Nicoll 058 * @author Phillip Webb 059 * @author Andy Wilkinson 060 * @author Brian Clozel 061 * @since 1.4.0 062 */ 063public class RestTemplateBuilder { 064 065 private final boolean detectRequestFactory; 066 067 private final String rootUri; 068 069 private final Set<HttpMessageConverter<?>> messageConverters; 070 071 private final Supplier<ClientHttpRequestFactory> requestFactorySupplier; 072 073 private final UriTemplateHandler uriTemplateHandler; 074 075 private final ResponseErrorHandler errorHandler; 076 077 private final BasicAuthenticationInterceptor basicAuthentication; 078 079 private final Set<RestTemplateCustomizer> restTemplateCustomizers; 080 081 private final RequestFactoryCustomizer requestFactoryCustomizer; 082 083 private final Set<ClientHttpRequestInterceptor> interceptors; 084 085 /** 086 * Create a new {@link RestTemplateBuilder} instance. 087 * @param customizers any {@link RestTemplateCustomizer RestTemplateCustomizers} that 088 * should be applied when the {@link RestTemplate} is built 089 */ 090 public RestTemplateBuilder(RestTemplateCustomizer... customizers) { 091 Assert.notNull(customizers, "Customizers must not be null"); 092 this.detectRequestFactory = true; 093 this.rootUri = null; 094 this.messageConverters = null; 095 this.requestFactorySupplier = null; 096 this.uriTemplateHandler = null; 097 this.errorHandler = null; 098 this.basicAuthentication = null; 099 this.restTemplateCustomizers = Collections 100 .unmodifiableSet(new LinkedHashSet<>(Arrays.asList(customizers))); 101 this.requestFactoryCustomizer = new RequestFactoryCustomizer(); 102 this.interceptors = Collections.emptySet(); 103 } 104 105 private RestTemplateBuilder(boolean detectRequestFactory, String rootUri, 106 Set<HttpMessageConverter<?>> messageConverters, 107 Supplier<ClientHttpRequestFactory> requestFactorySupplier, 108 UriTemplateHandler uriTemplateHandler, ResponseErrorHandler errorHandler, 109 BasicAuthenticationInterceptor basicAuthentication, 110 Set<RestTemplateCustomizer> restTemplateCustomizers, 111 RequestFactoryCustomizer requestFactoryCustomizer, 112 Set<ClientHttpRequestInterceptor> interceptors) { 113 this.detectRequestFactory = detectRequestFactory; 114 this.rootUri = rootUri; 115 this.messageConverters = messageConverters; 116 this.requestFactorySupplier = requestFactorySupplier; 117 this.uriTemplateHandler = uriTemplateHandler; 118 this.errorHandler = errorHandler; 119 this.basicAuthentication = basicAuthentication; 120 this.restTemplateCustomizers = restTemplateCustomizers; 121 this.requestFactoryCustomizer = requestFactoryCustomizer; 122 this.interceptors = interceptors; 123 } 124 125 /** 126 * Set if the {@link ClientHttpRequestFactory} should be detected based on the 127 * classpath. Default if {@code true}. 128 * @param detectRequestFactory if the {@link ClientHttpRequestFactory} should be 129 * detected 130 * @return a new builder instance 131 */ 132 public RestTemplateBuilder detectRequestFactory(boolean detectRequestFactory) { 133 return new RestTemplateBuilder(detectRequestFactory, this.rootUri, 134 this.messageConverters, this.requestFactorySupplier, 135 this.uriTemplateHandler, this.errorHandler, this.basicAuthentication, 136 this.restTemplateCustomizers, this.requestFactoryCustomizer, 137 this.interceptors); 138 } 139 140 /** 141 * Set a root URL that should be applied to each request that starts with {@code '/'}. 142 * See {@link RootUriTemplateHandler} for details. 143 * @param rootUri the root URI or {@code null} 144 * @return a new builder instance 145 */ 146 public RestTemplateBuilder rootUri(String rootUri) { 147 return new RestTemplateBuilder(this.detectRequestFactory, rootUri, 148 this.messageConverters, this.requestFactorySupplier, 149 this.uriTemplateHandler, this.errorHandler, this.basicAuthentication, 150 this.restTemplateCustomizers, this.requestFactoryCustomizer, 151 this.interceptors); 152 } 153 154 /** 155 * Set the {@link HttpMessageConverter HttpMessageConverters} that should be used with 156 * the {@link RestTemplate}. Setting this value will replace any previously configured 157 * converters and any converters configured on the builder will replace RestTemplate's 158 * default converters. 159 * @param messageConverters the converters to set 160 * @return a new builder instance 161 * @see #additionalMessageConverters(HttpMessageConverter...) 162 */ 163 public RestTemplateBuilder messageConverters( 164 HttpMessageConverter<?>... messageConverters) { 165 Assert.notNull(messageConverters, "MessageConverters must not be null"); 166 return messageConverters(Arrays.asList(messageConverters)); 167 } 168 169 /** 170 * Set the {@link HttpMessageConverter HttpMessageConverters} that should be used with 171 * the {@link RestTemplate}. Setting this value will replace any previously configured 172 * converters and any converters configured on the builder will replace RestTemplate's 173 * default converters. 174 * @param messageConverters the converters to set 175 * @return a new builder instance 176 * @see #additionalMessageConverters(HttpMessageConverter...) 177 */ 178 public RestTemplateBuilder messageConverters( 179 Collection<? extends HttpMessageConverter<?>> messageConverters) { 180 Assert.notNull(messageConverters, "MessageConverters must not be null"); 181 return new RestTemplateBuilder(this.detectRequestFactory, this.rootUri, 182 Collections.unmodifiableSet( 183 new LinkedHashSet<HttpMessageConverter<?>>(messageConverters)), 184 this.requestFactorySupplier, this.uriTemplateHandler, this.errorHandler, 185 this.basicAuthentication, this.restTemplateCustomizers, 186 this.requestFactoryCustomizer, this.interceptors); 187 } 188 189 /** 190 * Add additional {@link HttpMessageConverter HttpMessageConverters} that should be 191 * used with the {@link RestTemplate}. Any converters configured on the builder will 192 * replace RestTemplate's default converters. 193 * @param messageConverters the converters to add 194 * @return a new builder instance 195 * @see #messageConverters(HttpMessageConverter...) 196 */ 197 public RestTemplateBuilder additionalMessageConverters( 198 HttpMessageConverter<?>... messageConverters) { 199 Assert.notNull(messageConverters, "MessageConverters must not be null"); 200 return additionalMessageConverters(Arrays.asList(messageConverters)); 201 } 202 203 /** 204 * Add additional {@link HttpMessageConverter HttpMessageConverters} that should be 205 * used with the {@link RestTemplate}. Any converters configured on the builder will 206 * replace RestTemplate's default converters. 207 * @param messageConverters the converters to add 208 * @return a new builder instance 209 * @see #messageConverters(HttpMessageConverter...) 210 */ 211 public RestTemplateBuilder additionalMessageConverters( 212 Collection<? extends HttpMessageConverter<?>> messageConverters) { 213 Assert.notNull(messageConverters, "MessageConverters must not be null"); 214 return new RestTemplateBuilder(this.detectRequestFactory, this.rootUri, 215 append(this.messageConverters, messageConverters), 216 this.requestFactorySupplier, this.uriTemplateHandler, this.errorHandler, 217 this.basicAuthentication, this.restTemplateCustomizers, 218 this.requestFactoryCustomizer, this.interceptors); 219 } 220 221 /** 222 * Set the {@link HttpMessageConverter HttpMessageConverters} that should be used with 223 * the {@link RestTemplate} to the default set. Calling this method will replace any 224 * previously defined converters. 225 * @return a new builder instance 226 * @see #messageConverters(HttpMessageConverter...) 227 */ 228 public RestTemplateBuilder defaultMessageConverters() { 229 return new RestTemplateBuilder(this.detectRequestFactory, this.rootUri, 230 Collections.unmodifiableSet( 231 new LinkedHashSet<>(new RestTemplate().getMessageConverters())), 232 this.requestFactorySupplier, this.uriTemplateHandler, this.errorHandler, 233 this.basicAuthentication, this.restTemplateCustomizers, 234 this.requestFactoryCustomizer, this.interceptors); 235 } 236 237 /** 238 * Set the {@link ClientHttpRequestInterceptor ClientHttpRequestInterceptors} that 239 * should be used with the {@link RestTemplate}. Setting this value will replace any 240 * previously defined interceptors. 241 * @param interceptors the interceptors to set 242 * @return a new builder instance 243 * @since 1.4.1 244 * @see #additionalInterceptors(ClientHttpRequestInterceptor...) 245 */ 246 public RestTemplateBuilder interceptors( 247 ClientHttpRequestInterceptor... interceptors) { 248 Assert.notNull(interceptors, "interceptors must not be null"); 249 return interceptors(Arrays.asList(interceptors)); 250 } 251 252 /** 253 * Set the {@link ClientHttpRequestInterceptor ClientHttpRequestInterceptors} that 254 * should be used with the {@link RestTemplate}. Setting this value will replace any 255 * previously defined interceptors. 256 * @param interceptors the interceptors to set 257 * @return a new builder instance 258 * @since 1.4.1 259 * @see #additionalInterceptors(ClientHttpRequestInterceptor...) 260 */ 261 public RestTemplateBuilder interceptors( 262 Collection<ClientHttpRequestInterceptor> interceptors) { 263 Assert.notNull(interceptors, "interceptors must not be null"); 264 return new RestTemplateBuilder(this.detectRequestFactory, this.rootUri, 265 this.messageConverters, this.requestFactorySupplier, 266 this.uriTemplateHandler, this.errorHandler, this.basicAuthentication, 267 this.restTemplateCustomizers, this.requestFactoryCustomizer, 268 Collections.unmodifiableSet(new LinkedHashSet<>(interceptors))); 269 } 270 271 /** 272 * Add additional {@link ClientHttpRequestInterceptor ClientHttpRequestInterceptors} 273 * that should be used with the {@link RestTemplate}. 274 * @param interceptors the interceptors to add 275 * @return a new builder instance 276 * @since 1.4.1 277 * @see #interceptors(ClientHttpRequestInterceptor...) 278 */ 279 public RestTemplateBuilder additionalInterceptors( 280 ClientHttpRequestInterceptor... interceptors) { 281 Assert.notNull(interceptors, "interceptors must not be null"); 282 return additionalInterceptors(Arrays.asList(interceptors)); 283 } 284 285 /** 286 * Add additional {@link ClientHttpRequestInterceptor ClientHttpRequestInterceptors} 287 * that should be used with the {@link RestTemplate}. 288 * @param interceptors the interceptors to add 289 * @return a new builder instance 290 * @since 1.4.1 291 * @see #interceptors(ClientHttpRequestInterceptor...) 292 */ 293 public RestTemplateBuilder additionalInterceptors( 294 Collection<? extends ClientHttpRequestInterceptor> interceptors) { 295 Assert.notNull(interceptors, "interceptors must not be null"); 296 return new RestTemplateBuilder(this.detectRequestFactory, this.rootUri, 297 this.messageConverters, this.requestFactorySupplier, 298 this.uriTemplateHandler, this.errorHandler, this.basicAuthentication, 299 this.restTemplateCustomizers, this.requestFactoryCustomizer, 300 append(this.interceptors, interceptors)); 301 } 302 303 /** 304 * Set the {@link ClientHttpRequestFactory} class that should be used with the 305 * {@link RestTemplate}. 306 * @param requestFactory the request factory to use 307 * @return a new builder instance 308 */ 309 public RestTemplateBuilder requestFactory( 310 Class<? extends ClientHttpRequestFactory> requestFactory) { 311 Assert.notNull(requestFactory, "RequestFactory must not be null"); 312 return requestFactory(() -> createRequestFactory(requestFactory)); 313 } 314 315 private ClientHttpRequestFactory createRequestFactory( 316 Class<? extends ClientHttpRequestFactory> requestFactory) { 317 try { 318 Constructor<?> constructor = requestFactory.getDeclaredConstructor(); 319 constructor.setAccessible(true); 320 return (ClientHttpRequestFactory) constructor.newInstance(); 321 } 322 catch (Exception ex) { 323 throw new IllegalStateException(ex); 324 } 325 } 326 327 /** 328 * Set the {@code Supplier} of {@link ClientHttpRequestFactory} that should be called 329 * each time we {@link #build()} a new {@link RestTemplate} instance. 330 * @param requestFactorySupplier the supplier for the request factory 331 * @return a new builder instance 332 * @since 2.0.0 333 */ 334 public RestTemplateBuilder requestFactory( 335 Supplier<ClientHttpRequestFactory> requestFactorySupplier) { 336 Assert.notNull(requestFactorySupplier, 337 "RequestFactory Supplier must not be null"); 338 return new RestTemplateBuilder(this.detectRequestFactory, this.rootUri, 339 this.messageConverters, requestFactorySupplier, this.uriTemplateHandler, 340 this.errorHandler, this.basicAuthentication, this.restTemplateCustomizers, 341 this.requestFactoryCustomizer, this.interceptors); 342 } 343 344 /** 345 * Set the {@link UriTemplateHandler} that should be used with the 346 * {@link RestTemplate}. 347 * @param uriTemplateHandler the URI template handler to use 348 * @return a new builder instance 349 */ 350 public RestTemplateBuilder uriTemplateHandler(UriTemplateHandler uriTemplateHandler) { 351 Assert.notNull(uriTemplateHandler, "UriTemplateHandler must not be null"); 352 return new RestTemplateBuilder(this.detectRequestFactory, this.rootUri, 353 this.messageConverters, this.requestFactorySupplier, uriTemplateHandler, 354 this.errorHandler, this.basicAuthentication, this.restTemplateCustomizers, 355 this.requestFactoryCustomizer, this.interceptors); 356 } 357 358 /** 359 * Set the {@link ResponseErrorHandler} that should be used with the 360 * {@link RestTemplate}. 361 * @param errorHandler the error handler to use 362 * @return a new builder instance 363 */ 364 public RestTemplateBuilder errorHandler(ResponseErrorHandler errorHandler) { 365 Assert.notNull(errorHandler, "ErrorHandler must not be null"); 366 return new RestTemplateBuilder(this.detectRequestFactory, this.rootUri, 367 this.messageConverters, this.requestFactorySupplier, 368 this.uriTemplateHandler, errorHandler, this.basicAuthentication, 369 this.restTemplateCustomizers, this.requestFactoryCustomizer, 370 this.interceptors); 371 } 372 373 /** 374 * Add HTTP basic authentication to requests. See 375 * {@link BasicAuthenticationInterceptor} for details. 376 * @param username the user name 377 * @param password the password 378 * @return a new builder instance 379 * @deprecated since 2.1.0 in favor of 380 * {@link #basicAuthentication(String username, String password)} 381 */ 382 @Deprecated 383 public RestTemplateBuilder basicAuthorization(String username, String password) { 384 return basicAuthentication(username, password); 385 } 386 387 /** 388 * Add HTTP basic authentication to requests. See 389 * {@link BasicAuthenticationInterceptor} for details. 390 * @param username the user name 391 * @param password the password 392 * @return a new builder instance 393 * @since 2.1.0 394 */ 395 public RestTemplateBuilder basicAuthentication(String username, String password) { 396 return new RestTemplateBuilder(this.detectRequestFactory, this.rootUri, 397 this.messageConverters, this.requestFactorySupplier, 398 this.uriTemplateHandler, this.errorHandler, 399 new BasicAuthenticationInterceptor(username, password), 400 this.restTemplateCustomizers, this.requestFactoryCustomizer, 401 this.interceptors); 402 } 403 404 /** 405 * Set the {@link RestTemplateCustomizer RestTemplateCustomizers} that should be 406 * applied to the {@link RestTemplate}. Customizers are applied in the order that they 407 * were added after builder configuration has been applied. Setting this value will 408 * replace any previously configured customizers. 409 * @param restTemplateCustomizers the customizers to set 410 * @return a new builder instance 411 * @see #additionalCustomizers(RestTemplateCustomizer...) 412 */ 413 public RestTemplateBuilder customizers( 414 RestTemplateCustomizer... restTemplateCustomizers) { 415 Assert.notNull(restTemplateCustomizers, 416 "RestTemplateCustomizers must not be null"); 417 return customizers(Arrays.asList(restTemplateCustomizers)); 418 } 419 420 /** 421 * Set the {@link RestTemplateCustomizer RestTemplateCustomizers} that should be 422 * applied to the {@link RestTemplate}. Customizers are applied in the order that they 423 * were added after builder configuration has been applied. Setting this value will 424 * replace any previously configured customizers. 425 * @param restTemplateCustomizers the customizers to set 426 * @return a new builder instance 427 * @see #additionalCustomizers(RestTemplateCustomizer...) 428 */ 429 public RestTemplateBuilder customizers( 430 Collection<? extends RestTemplateCustomizer> restTemplateCustomizers) { 431 Assert.notNull(restTemplateCustomizers, 432 "RestTemplateCustomizers must not be null"); 433 return new RestTemplateBuilder(this.detectRequestFactory, this.rootUri, 434 this.messageConverters, this.requestFactorySupplier, 435 this.uriTemplateHandler, this.errorHandler, this.basicAuthentication, 436 Collections.unmodifiableSet(new LinkedHashSet<RestTemplateCustomizer>( 437 restTemplateCustomizers)), 438 this.requestFactoryCustomizer, this.interceptors); 439 } 440 441 /** 442 * Add {@link RestTemplateCustomizer RestTemplateCustomizers} that should be applied 443 * to the {@link RestTemplate}. Customizers are applied in the order that they were 444 * added after builder configuration has been applied. 445 * @param restTemplateCustomizers the customizers to add 446 * @return a new builder instance 447 * @see #customizers(RestTemplateCustomizer...) 448 */ 449 public RestTemplateBuilder additionalCustomizers( 450 RestTemplateCustomizer... restTemplateCustomizers) { 451 Assert.notNull(restTemplateCustomizers, 452 "RestTemplateCustomizers must not be null"); 453 return additionalCustomizers(Arrays.asList(restTemplateCustomizers)); 454 } 455 456 /** 457 * Add {@link RestTemplateCustomizer RestTemplateCustomizers} that should be applied 458 * to the {@link RestTemplate}. Customizers are applied in the order that they were 459 * added after builder configuration has been applied. 460 * @param customizers the customizers to add 461 * @return a new builder instance 462 * @see #customizers(RestTemplateCustomizer...) 463 */ 464 public RestTemplateBuilder additionalCustomizers( 465 Collection<? extends RestTemplateCustomizer> customizers) { 466 Assert.notNull(customizers, "RestTemplateCustomizers must not be null"); 467 return new RestTemplateBuilder(this.detectRequestFactory, this.rootUri, 468 this.messageConverters, this.requestFactorySupplier, 469 this.uriTemplateHandler, this.errorHandler, this.basicAuthentication, 470 append(this.restTemplateCustomizers, customizers), 471 this.requestFactoryCustomizer, this.interceptors); 472 } 473 474 /** 475 * Sets the connection timeout on the underlying {@link ClientHttpRequestFactory}. 476 * @param connectTimeout the connection timeout 477 * @return a new builder instance. 478 * @since 2.1.0 479 */ 480 public RestTemplateBuilder setConnectTimeout(Duration connectTimeout) { 481 return new RestTemplateBuilder(this.detectRequestFactory, this.rootUri, 482 this.messageConverters, this.requestFactorySupplier, 483 this.uriTemplateHandler, this.errorHandler, this.basicAuthentication, 484 this.restTemplateCustomizers, 485 this.requestFactoryCustomizer.connectTimeout(connectTimeout), 486 this.interceptors); 487 } 488 489 /** 490 * Sets the connection timeout in milliseconds on the underlying 491 * {@link ClientHttpRequestFactory}. 492 * @param connectTimeout the connection timeout in milliseconds 493 * @return a new builder instance. 494 * @deprecated since 2.1.0 in favor of {@link #setConnectTimeout(Duration)} 495 */ 496 @Deprecated 497 public RestTemplateBuilder setConnectTimeout(int connectTimeout) { 498 return setConnectTimeout(Duration.ofMillis(connectTimeout)); 499 } 500 501 /** 502 * Sets the read timeout on the underlying {@link ClientHttpRequestFactory}. 503 * @param readTimeout the read timeout 504 * @return a new builder instance. 505 * @since 2.1.0 506 */ 507 public RestTemplateBuilder setReadTimeout(Duration readTimeout) { 508 return new RestTemplateBuilder(this.detectRequestFactory, this.rootUri, 509 this.messageConverters, this.requestFactorySupplier, 510 this.uriTemplateHandler, this.errorHandler, this.basicAuthentication, 511 this.restTemplateCustomizers, 512 this.requestFactoryCustomizer.readTimeout(readTimeout), 513 this.interceptors); 514 } 515 516 /** 517 * Sets the read timeout in milliseconds on the underlying 518 * {@link ClientHttpRequestFactory}. 519 * @param readTimeout the read timeout in milliseconds 520 * @return a new builder instance. 521 * @deprecated since 2.1.0 in favor of {@link #setReadTimeout(Duration)} 522 */ 523 @Deprecated 524 public RestTemplateBuilder setReadTimeout(int readTimeout) { 525 return setReadTimeout(Duration.ofMillis(readTimeout)); 526 } 527 528 /** 529 * Build a new {@link RestTemplate} instance and configure it using this builder. 530 * @return a configured {@link RestTemplate} instance. 531 * @see #build(Class) 532 * @see #configure(RestTemplate) 533 */ 534 public RestTemplate build() { 535 return build(RestTemplate.class); 536 } 537 538 /** 539 * Build a new {@link RestTemplate} instance of the specified type and configure it 540 * using this builder. 541 * @param <T> the type of rest template 542 * @param restTemplateClass the template type to create 543 * @return a configured {@link RestTemplate} instance. 544 * @see RestTemplateBuilder#build() 545 * @see #configure(RestTemplate) 546 */ 547 548 public <T extends RestTemplate> T build(Class<T> restTemplateClass) { 549 return configure(BeanUtils.instantiateClass(restTemplateClass)); 550 } 551 552 /** 553 * Configure the provided {@link RestTemplate} instance using this builder. 554 * @param <T> the type of rest template 555 * @param restTemplate the {@link RestTemplate} to configure 556 * @return the rest template instance 557 * @see RestTemplateBuilder#build() 558 * @see RestTemplateBuilder#build(Class) 559 */ 560 public <T extends RestTemplate> T configure(T restTemplate) { 561 configureRequestFactory(restTemplate); 562 if (!CollectionUtils.isEmpty(this.messageConverters)) { 563 restTemplate.setMessageConverters(new ArrayList<>(this.messageConverters)); 564 } 565 if (this.uriTemplateHandler != null) { 566 restTemplate.setUriTemplateHandler(this.uriTemplateHandler); 567 } 568 if (this.errorHandler != null) { 569 restTemplate.setErrorHandler(this.errorHandler); 570 } 571 if (this.rootUri != null) { 572 RootUriTemplateHandler.addTo(restTemplate, this.rootUri); 573 } 574 if (this.basicAuthentication != null) { 575 restTemplate.getInterceptors().add(this.basicAuthentication); 576 } 577 restTemplate.getInterceptors().addAll(this.interceptors); 578 if (!CollectionUtils.isEmpty(this.restTemplateCustomizers)) { 579 for (RestTemplateCustomizer customizer : this.restTemplateCustomizers) { 580 customizer.customize(restTemplate); 581 } 582 } 583 return restTemplate; 584 } 585 586 private void configureRequestFactory(RestTemplate restTemplate) { 587 ClientHttpRequestFactory requestFactory = null; 588 if (this.requestFactorySupplier != null) { 589 requestFactory = this.requestFactorySupplier.get(); 590 } 591 else if (this.detectRequestFactory) { 592 requestFactory = new ClientHttpRequestFactorySupplier().get(); 593 } 594 if (requestFactory != null) { 595 if (this.requestFactoryCustomizer != null) { 596 this.requestFactoryCustomizer.accept(requestFactory); 597 } 598 restTemplate.setRequestFactory(requestFactory); 599 } 600 } 601 602 private <T> Set<T> append(Set<T> set, Collection<? extends T> additions) { 603 Set<T> result = new LinkedHashSet<>((set != null) ? set : Collections.emptySet()); 604 result.addAll(additions); 605 return Collections.unmodifiableSet(result); 606 } 607 608 private static class RequestFactoryCustomizer 609 implements Consumer<ClientHttpRequestFactory> { 610 611 private final Duration connectTimeout; 612 613 private final Duration readTimeout; 614 615 RequestFactoryCustomizer() { 616 this(null, null); 617 } 618 619 private RequestFactoryCustomizer(Duration connectTimeout, Duration readTimeout) { 620 this.connectTimeout = connectTimeout; 621 this.readTimeout = readTimeout; 622 } 623 624 public RequestFactoryCustomizer connectTimeout(Duration connectTimeout) { 625 return new RequestFactoryCustomizer(connectTimeout, this.readTimeout); 626 } 627 628 public RequestFactoryCustomizer readTimeout(Duration readTimeout) { 629 return new RequestFactoryCustomizer(this.connectTimeout, readTimeout); 630 } 631 632 @Override 633 public void accept(ClientHttpRequestFactory requestFactory) { 634 ClientHttpRequestFactory unwrappedRequestFactory = unwrapRequestFactoryIfNecessary( 635 requestFactory); 636 if (this.connectTimeout != null) { 637 new TimeoutRequestFactoryCustomizer(this.connectTimeout, 638 "setConnectTimeout").customize(unwrappedRequestFactory); 639 } 640 if (this.readTimeout != null) { 641 new TimeoutRequestFactoryCustomizer(this.readTimeout, "setReadTimeout") 642 .customize(unwrappedRequestFactory); 643 } 644 } 645 646 private ClientHttpRequestFactory unwrapRequestFactoryIfNecessary( 647 ClientHttpRequestFactory requestFactory) { 648 if (!(requestFactory instanceof AbstractClientHttpRequestFactoryWrapper)) { 649 return requestFactory; 650 } 651 ClientHttpRequestFactory unwrappedRequestFactory = requestFactory; 652 Field field = ReflectionUtils.findField( 653 AbstractClientHttpRequestFactoryWrapper.class, "requestFactory"); 654 ReflectionUtils.makeAccessible(field); 655 do { 656 unwrappedRequestFactory = (ClientHttpRequestFactory) ReflectionUtils 657 .getField(field, unwrappedRequestFactory); 658 } 659 while (unwrappedRequestFactory instanceof AbstractClientHttpRequestFactoryWrapper); 660 return unwrappedRequestFactory; 661 } 662 663 /** 664 * {@link ClientHttpRequestFactory} customizer to call a "set timeout" method. 665 */ 666 private static final class TimeoutRequestFactoryCustomizer { 667 668 private final Duration timeout; 669 670 private final String methodName; 671 672 TimeoutRequestFactoryCustomizer(Duration timeout, String methodName) { 673 this.timeout = timeout; 674 this.methodName = methodName; 675 } 676 677 void customize(ClientHttpRequestFactory factory) { 678 ReflectionUtils.invokeMethod(findMethod(factory), factory, 679 Math.toIntExact(this.timeout.toMillis())); 680 } 681 682 private Method findMethod(ClientHttpRequestFactory factory) { 683 Method method = ReflectionUtils.findMethod(factory.getClass(), 684 this.methodName, int.class); 685 if (method != null) { 686 return method; 687 } 688 throw new IllegalStateException("Request factory " + factory.getClass() 689 + " does not have a " + this.methodName + "(int) method"); 690 } 691 692 } 693 694 } 695 696}