Skip to content

Commit 2b51cf4

Browse files
committed
Merge pull request #16972 from kstrijbos
* pr/16972: Polish "Make it easier to set bufferRequestBody" Make it easier to set bufferRequestBody Closes gh-16972
2 parents 750d251 + af1a6d8 commit 2b51cf4

File tree

2 files changed

+132
-32
lines changed

2 files changed

+132
-32
lines changed

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

+68-32
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,11 @@
3333

3434
import org.springframework.beans.BeanUtils;
3535
import org.springframework.http.client.AbstractClientHttpRequestFactoryWrapper;
36+
import org.springframework.http.client.ClientHttpRequest;
3637
import org.springframework.http.client.ClientHttpRequestFactory;
3738
import org.springframework.http.client.ClientHttpRequestInterceptor;
39+
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
40+
import org.springframework.http.client.SimpleClientHttpRequestFactory;
3841
import org.springframework.http.converter.HttpMessageConverter;
3942
import org.springframework.util.Assert;
4043
import org.springframework.util.CollectionUtils;
@@ -60,6 +63,7 @@
6063
* @author Andy Wilkinson
6164
* @author Brian Clozel
6265
* @author Dmytro Nosan
66+
* @author Kevin Strijbos
6367
* @since 1.4.0
6468
*/
6569
public class RestTemplateBuilder {
@@ -506,6 +510,24 @@ public RestTemplateBuilder setReadTimeout(Duration readTimeout) {
506510
this.interceptors);
507511
}
508512

513+
/**
514+
* Sets if the underling {@link ClientHttpRequestFactory} should buffer the
515+
* {@linkplain ClientHttpRequest#getBody() request body} internally.
516+
* @param bufferRequestBody value of the bufferRequestBody parameter
517+
* @return a new builder instance.
518+
* @since 2.2.0
519+
* @see SimpleClientHttpRequestFactory#setBufferRequestBody(boolean)
520+
* @see HttpComponentsClientHttpRequestFactory#setBufferRequestBody(boolean)
521+
*/
522+
public RestTemplateBuilder setBufferRequestBody(boolean bufferRequestBody) {
523+
return new RestTemplateBuilder(this.detectRequestFactory, this.rootUri,
524+
this.messageConverters, this.requestFactorySupplier,
525+
this.uriTemplateHandler, this.errorHandler, this.basicAuthentication,
526+
this.restTemplateCustomizers,
527+
this.requestFactoryCustomizer.bufferRequestBody(bufferRequestBody),
528+
this.interceptors);
529+
}
530+
509531
/**
510532
* Build a new {@link RestTemplate} instance and configure it using this builder.
511533
* @return a configured {@link RestTemplate} instance.
@@ -617,34 +639,46 @@ private static class RequestFactoryCustomizer
617639

618640
private final Duration readTimeout;
619641

642+
private final Boolean bufferRequestBody;
643+
620644
RequestFactoryCustomizer() {
621-
this(null, null);
645+
this(null, null, null);
622646
}
623647

624-
private RequestFactoryCustomizer(Duration connectTimeout, Duration readTimeout) {
648+
private RequestFactoryCustomizer(Duration connectTimeout, Duration readTimeout,
649+
Boolean bufferRequestBody) {
625650
this.connectTimeout = connectTimeout;
626651
this.readTimeout = readTimeout;
652+
this.bufferRequestBody = bufferRequestBody;
627653
}
628654

629655
public RequestFactoryCustomizer connectTimeout(Duration connectTimeout) {
630-
return new RequestFactoryCustomizer(connectTimeout, this.readTimeout);
656+
return new RequestFactoryCustomizer(connectTimeout, this.readTimeout,
657+
this.bufferRequestBody);
631658
}
632659

633660
public RequestFactoryCustomizer readTimeout(Duration readTimeout) {
634-
return new RequestFactoryCustomizer(this.connectTimeout, readTimeout);
661+
return new RequestFactoryCustomizer(this.connectTimeout, readTimeout,
662+
this.bufferRequestBody);
663+
}
664+
665+
public RequestFactoryCustomizer bufferRequestBody(boolean bufferRequestBody) {
666+
return new RequestFactoryCustomizer(this.connectTimeout, this.readTimeout,
667+
bufferRequestBody);
635668
}
636669

637670
@Override
638671
public void accept(ClientHttpRequestFactory requestFactory) {
639672
ClientHttpRequestFactory unwrappedRequestFactory = unwrapRequestFactoryIfNecessary(
640673
requestFactory);
641674
if (this.connectTimeout != null) {
642-
new TimeoutRequestFactoryCustomizer(this.connectTimeout,
643-
"setConnectTimeout").customize(unwrappedRequestFactory);
675+
setConnectTimeout(unwrappedRequestFactory);
644676
}
645677
if (this.readTimeout != null) {
646-
new TimeoutRequestFactoryCustomizer(this.readTimeout, "setReadTimeout")
647-
.customize(unwrappedRequestFactory);
678+
setReadTimeout(unwrappedRequestFactory);
679+
}
680+
if (this.bufferRequestBody != null) {
681+
setBufferRequestBody(unwrappedRequestFactory);
648682
}
649683
}
650684

@@ -664,35 +698,37 @@ private ClientHttpRequestFactory unwrapRequestFactoryIfNecessary(
664698
return unwrappedRequestFactory;
665699
}
666700

667-
/**
668-
* {@link ClientHttpRequestFactory} customizer to call a "set timeout" method.
669-
*/
670-
private static final class TimeoutRequestFactoryCustomizer {
671-
672-
private final Duration timeout;
673-
674-
private final String methodName;
701+
private void setConnectTimeout(ClientHttpRequestFactory factory) {
702+
Method method = findMethod(factory, "setConnectTimeout", int.class);
703+
int timeout = Math.toIntExact(this.connectTimeout.toMillis());
704+
invoke(factory, method, timeout);
705+
}
675706

676-
TimeoutRequestFactoryCustomizer(Duration timeout, String methodName) {
677-
this.timeout = timeout;
678-
this.methodName = methodName;
679-
}
707+
private void setReadTimeout(ClientHttpRequestFactory factory) {
708+
Method method = findMethod(factory, "setReadTimeout", int.class);
709+
int timeout = Math.toIntExact(this.readTimeout.toMillis());
710+
invoke(factory, method, timeout);
711+
}
680712

681-
void customize(ClientHttpRequestFactory factory) {
682-
ReflectionUtils.invokeMethod(findMethod(factory), factory,
683-
Math.toIntExact(this.timeout.toMillis()));
684-
}
713+
private void setBufferRequestBody(ClientHttpRequestFactory factory) {
714+
Method method = findMethod(factory, "setBufferRequestBody", boolean.class);
715+
invoke(factory, method, this.bufferRequestBody);
716+
}
685717

686-
private Method findMethod(ClientHttpRequestFactory factory) {
687-
Method method = ReflectionUtils.findMethod(factory.getClass(),
688-
this.methodName, int.class);
689-
if (method != null) {
690-
return method;
691-
}
692-
throw new IllegalStateException("Request factory " + factory.getClass()
693-
+ " does not have a " + this.methodName + "(int) method");
718+
private Method findMethod(ClientHttpRequestFactory requestFactory,
719+
String methodName, Class<?>... parameters) {
720+
Method method = ReflectionUtils.findMethod(requestFactory.getClass(),
721+
methodName, parameters);
722+
if (method != null) {
723+
return method;
694724
}
725+
throw new IllegalStateException("Request factory " + requestFactory.getClass()
726+
+ " does not have a suitable " + methodName + " method");
727+
}
695728

729+
private void invoke(ClientHttpRequestFactory requestFactory, Method method,
730+
Object... parameters) {
731+
ReflectionUtils.invokeMethod(method, requestFactory, parameters);
696732
}
697733

698734
}

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

+64
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747

4848
import static org.assertj.core.api.Assertions.assertThat;
4949
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
50+
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
5051
import static org.mockito.ArgumentMatchers.any;
5152
import static org.mockito.Mockito.inOrder;
5253
import static org.mockito.Mockito.mock;
@@ -63,6 +64,7 @@
6364
* @author Phillip Webb
6465
* @author Andy Wilkinson
6566
* @author Dmytro Nosan
67+
* @author Kevin Strijbos
6668
*/
6769
public class RestTemplateBuilderTests {
6870

@@ -480,6 +482,23 @@ public void readTimeoutCanBeConfiguredOnHttpComponentsRequestFactory() {
480482
"requestConfig")).getSocketTimeout()).isEqualTo(1234);
481483
}
482484

485+
@Test
486+
public void bufferRequestBodyCanBeConfiguredOnHttpComponentsRequestFactory() {
487+
ClientHttpRequestFactory requestFactory = this.builder
488+
.requestFactory(HttpComponentsClientHttpRequestFactory.class)
489+
.setBufferRequestBody(false).build().getRequestFactory();
490+
assertThat(requestFactory).hasFieldOrPropertyWithValue("bufferRequestBody",
491+
false);
492+
requestFactory = this.builder
493+
.requestFactory(HttpComponentsClientHttpRequestFactory.class)
494+
.setBufferRequestBody(true).build().getRequestFactory();
495+
assertThat(requestFactory).hasFieldOrPropertyWithValue("bufferRequestBody", true);
496+
requestFactory = this.builder
497+
.requestFactory(HttpComponentsClientHttpRequestFactory.class).build()
498+
.getRequestFactory();
499+
assertThat(requestFactory).hasFieldOrPropertyWithValue("bufferRequestBody", true);
500+
}
501+
483502
@Test
484503
public void connectTimeoutCanBeConfiguredOnSimpleRequestFactory() {
485504
ClientHttpRequestFactory requestFactory = this.builder
@@ -496,6 +515,21 @@ public void readTimeoutCanBeConfiguredOnSimpleRequestFactory() {
496515
assertThat(requestFactory).hasFieldOrPropertyWithValue("readTimeout", 1234);
497516
}
498517

518+
@Test
519+
public void bufferRequestBodyCanBeConfiguredOnSimpleRequestFactory() {
520+
ClientHttpRequestFactory requestFactory = this.builder
521+
.requestFactory(SimpleClientHttpRequestFactory.class)
522+
.setBufferRequestBody(false).build().getRequestFactory();
523+
assertThat(requestFactory).hasFieldOrPropertyWithValue("bufferRequestBody",
524+
false);
525+
requestFactory = this.builder.requestFactory(SimpleClientHttpRequestFactory.class)
526+
.setBufferRequestBody(true).build().getRequestFactory();
527+
assertThat(requestFactory).hasFieldOrPropertyWithValue("bufferRequestBody", true);
528+
requestFactory = this.builder.requestFactory(SimpleClientHttpRequestFactory.class)
529+
.build().getRequestFactory();
530+
assertThat(requestFactory).hasFieldOrPropertyWithValue("bufferRequestBody", true);
531+
}
532+
499533
@Test
500534
public void connectTimeoutCanBeConfiguredOnOkHttp3RequestFactory() {
501535
ClientHttpRequestFactory requestFactory = this.builder
@@ -516,6 +550,15 @@ public void readTimeoutCanBeConfiguredOnOkHttp3RequestFactory() {
516550
.isEqualTo(1234);
517551
}
518552

553+
@Test
554+
public void bufferRequestBodyCanNotBeConfiguredOnOkHttp3RequestFactory() {
555+
assertThatIllegalStateException()
556+
.isThrownBy(() -> this.builder
557+
.requestFactory(OkHttp3ClientHttpRequestFactory.class)
558+
.setBufferRequestBody(false).build().getRequestFactory())
559+
.withMessageContaining(OkHttp3ClientHttpRequestFactory.class.getName());
560+
}
561+
519562
@Test
520563
public void connectTimeoutCanBeConfiguredOnAWrappedRequestFactory() {
521564
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
@@ -536,6 +579,27 @@ public void readTimeoutCanBeConfiguredOnAWrappedRequestFactory() {
536579
assertThat(requestFactory).hasFieldOrPropertyWithValue("readTimeout", 1234);
537580
}
538581

582+
@Test
583+
public void bufferRequestBodyCanBeConfiguredOnAWrappedRequestFactory() {
584+
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
585+
this.builder
586+
.requestFactory(
587+
() -> new BufferingClientHttpRequestFactory(requestFactory))
588+
.setBufferRequestBody(false).build();
589+
assertThat(requestFactory).hasFieldOrPropertyWithValue("bufferRequestBody",
590+
false);
591+
this.builder
592+
.requestFactory(
593+
() -> new BufferingClientHttpRequestFactory(requestFactory))
594+
.setBufferRequestBody(true).build();
595+
assertThat(requestFactory).hasFieldOrPropertyWithValue("bufferRequestBody", true);
596+
this.builder
597+
.requestFactory(
598+
() -> new BufferingClientHttpRequestFactory(requestFactory))
599+
.build();
600+
assertThat(requestFactory).hasFieldOrPropertyWithValue("bufferRequestBody", true);
601+
}
602+
539603
@Test
540604
public void unwrappingDoesNotAffectRequestFactoryThatIsSetOnTheBuiltTemplate() {
541605
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();

0 commit comments

Comments
 (0)