From 4f733e59b6b101b91cf46b8e95ac1795ac3c84fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B5=B7=E5=AD=90=20Yang?= Date: Wed, 29 Jan 2025 00:30:29 +0800 Subject: [PATCH] :sparkles: Built-in buffering support in RestClient --- .../config/RestTemplateBuilderTests.java | 2 +- .../web/client/MockRestServiceServer.java | 2 +- .../BufferingClientHttpRequestFactory.java | 28 ++++++++-- .../client/InterceptingClientHttpRequest.java | 8 ++- .../InterceptingClientHttpRequestFactory.java | 26 +++++++-- .../http/client/support/HttpAccessor.java | 37 +++++++++++-- .../support/InterceptingHttpAccessor.java | 7 ++- .../infra/web/client/DefaultRestClient.java | 14 ++++- .../web/client/DefaultRestClientBuilder.java | 14 ++++- .../java/infra/web/client/RestClient.java | 12 +++- ...ufferingClientHttpRequestFactoryTests.java | 2 +- .../JdkClientHttpRequestFactoryTests.java | 4 +- .../client/RestClientIntegrationTests.java | 55 ++++++++++++++++++- .../ClientHttpRequestFactoriesTests.java | 2 +- 14 files changed, 183 insertions(+), 30 deletions(-) diff --git a/integration-tests/src/test/java/infra/web/client/config/RestTemplateBuilderTests.java b/integration-tests/src/test/java/infra/web/client/config/RestTemplateBuilderTests.java index 746f1dd51a..90a2791475 100755 --- a/integration-tests/src/test/java/infra/web/client/config/RestTemplateBuilderTests.java +++ b/integration-tests/src/test/java/infra/web/client/config/RestTemplateBuilderTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 - 2024 the original author or authors. + * Copyright 2017 - 2025 the original author or authors. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/today-test/src/main/java/infra/test/web/client/MockRestServiceServer.java b/today-test/src/main/java/infra/test/web/client/MockRestServiceServer.java index 5001831dc9..e78b0b5d74 100644 --- a/today-test/src/main/java/infra/test/web/client/MockRestServiceServer.java +++ b/today-test/src/main/java/infra/test/web/client/MockRestServiceServer.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 - 2024 the original author or authors. + * Copyright 2017 - 2025 the original author or authors. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/today-web/src/main/java/infra/http/client/BufferingClientHttpRequestFactory.java b/today-web/src/main/java/infra/http/client/BufferingClientHttpRequestFactory.java index a65a45e76b..398f175930 100755 --- a/today-web/src/main/java/infra/http/client/BufferingClientHttpRequestFactory.java +++ b/today-web/src/main/java/infra/http/client/BufferingClientHttpRequestFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 - 2024 the original author or authors. + * Copyright 2017 - 2025 the original author or authors. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,8 +19,11 @@ import java.io.IOException; import java.net.URI; +import java.util.function.Predicate; import infra.http.HttpMethod; +import infra.http.HttpRequest; +import infra.lang.Nullable; /** * Wrapper for a {@link ClientHttpRequestFactory} that buffers @@ -35,19 +38,33 @@ */ public class BufferingClientHttpRequestFactory extends ClientHttpRequestFactoryWrapper { + private final Predicate bufferingPredicate; + /** * Create a buffering wrapper for the given {@link ClientHttpRequestFactory}. * * @param requestFactory the target request factory to wrap */ public BufferingClientHttpRequestFactory(ClientHttpRequestFactory requestFactory) { + this(requestFactory, null); + } + + /** + * Constructor variant with an additional predicate to decide whether to + * buffer the response. + * + * @since 5.0 + */ + public BufferingClientHttpRequestFactory(ClientHttpRequestFactory requestFactory, + @Nullable Predicate bufferingPredicate) { super(requestFactory); + this.bufferingPredicate = bufferingPredicate != null ? bufferingPredicate : request -> true; } @Override protected ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod, ClientHttpRequestFactory requestFactory) throws IOException { ClientHttpRequest request = requestFactory.createRequest(uri, httpMethod); - if (shouldBuffer(uri, httpMethod)) { + if (shouldBuffer(request)) { return new BufferingClientHttpRequestWrapper(request); } else { @@ -61,12 +78,11 @@ protected ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod, Client *

The default implementation returns {@code true} for all URIs and methods. * Subclasses can override this method to change this behavior. * - * @param uri the URI - * @param httpMethod the method + * @param request the request * @return {@code true} if the exchange should be buffered; {@code false} otherwise */ - protected boolean shouldBuffer(URI uri, HttpMethod httpMethod) { - return true; + protected boolean shouldBuffer(HttpRequest request) { + return this.bufferingPredicate.test(request); } } diff --git a/today-web/src/main/java/infra/http/client/InterceptingClientHttpRequest.java b/today-web/src/main/java/infra/http/client/InterceptingClientHttpRequest.java index ed9f6f2f5d..691e981c48 100755 --- a/today-web/src/main/java/infra/http/client/InterceptingClientHttpRequest.java +++ b/today-web/src/main/java/infra/http/client/InterceptingClientHttpRequest.java @@ -20,6 +20,7 @@ import java.io.IOException; import java.net.URI; import java.util.List; +import java.util.function.Predicate; import infra.http.HttpHeaders; import infra.http.HttpMethod; @@ -43,13 +44,16 @@ final class InterceptingClientHttpRequest extends AbstractBufferingClientHttpReq private final List interceptors; + private final Predicate bufferingPredicate; + InterceptingClientHttpRequest(ClientHttpRequestFactory requestFactory, - List interceptors, URI uri, HttpMethod method) { + List interceptors, URI uri, HttpMethod method, Predicate bufferingPredicate) { this.requestFactory = requestFactory; this.interceptors = interceptors; this.method = method; this.uri = uri; + this.bufferingPredicate = bufferingPredicate; } @Override @@ -103,7 +107,7 @@ public ClientHttpResponse execute(HttpRequest request, byte[] body) throws IOExc } private boolean shouldBufferResponse(HttpRequest request) { - return false; + return bufferingPredicate.test(request); } } diff --git a/today-web/src/main/java/infra/http/client/InterceptingClientHttpRequestFactory.java b/today-web/src/main/java/infra/http/client/InterceptingClientHttpRequestFactory.java index 2ffe5947e2..bc7ab658fb 100755 --- a/today-web/src/main/java/infra/http/client/InterceptingClientHttpRequestFactory.java +++ b/today-web/src/main/java/infra/http/client/InterceptingClientHttpRequestFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 - 2023 the original author or authors. + * Copyright 2017 - 2025 the original author or authors. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -12,7 +12,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program. If not, see [http://www.gnu.org/licenses/] + * along with this program. If not, see [https://www.gnu.org/licenses/] */ package infra.http.client; @@ -20,8 +20,10 @@ import java.net.URI; import java.util.Collections; import java.util.List; +import java.util.function.Predicate; import infra.http.HttpMethod; +import infra.http.HttpRequest; import infra.lang.Nullable; /** @@ -38,6 +40,8 @@ public class InterceptingClientHttpRequestFactory extends ClientHttpRequestFacto private final List interceptors; + private final Predicate bufferingPredicate; + /** * Create a new instance of the {@code InterceptingClientHttpRequestFactory} with the given parameters. * @@ -45,15 +49,29 @@ public class InterceptingClientHttpRequestFactory extends ClientHttpRequestFacto * @param interceptors the interceptors that are to be applied (can be {@code null}) */ public InterceptingClientHttpRequestFactory(ClientHttpRequestFactory requestFactory, - @Nullable List interceptors) { + @Nullable List interceptors) { + + this(requestFactory, interceptors, null); + } + + /** + * Constructor variant with an additional predicate to decide whether to + * buffer the response. + * + * @since 5.0 + */ + public InterceptingClientHttpRequestFactory(ClientHttpRequestFactory requestFactory, + @Nullable List interceptors, + @Nullable Predicate bufferingPredicate) { super(requestFactory); this.interceptors = interceptors != null ? interceptors : Collections.emptyList(); + this.bufferingPredicate = bufferingPredicate != null ? bufferingPredicate : req -> false; } @Override protected ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod, ClientHttpRequestFactory requestFactory) { - return new InterceptingClientHttpRequest(requestFactory, this.interceptors, uri, httpMethod); + return new InterceptingClientHttpRequest(requestFactory, this.interceptors, uri, httpMethod, bufferingPredicate); } } diff --git a/today-web/src/main/java/infra/http/client/support/HttpAccessor.java b/today-web/src/main/java/infra/http/client/support/HttpAccessor.java index 10e6817691..53d0aafb21 100755 --- a/today-web/src/main/java/infra/http/client/support/HttpAccessor.java +++ b/today-web/src/main/java/infra/http/client/support/HttpAccessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 - 2024 the original author or authors. + * Copyright 2017 - 2025 the original author or authors. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -21,14 +21,18 @@ import java.net.URI; import java.util.ArrayList; import java.util.List; +import java.util.function.Predicate; import infra.core.annotation.AnnotationAwareOrderComparator; import infra.http.HttpMethod; +import infra.http.HttpRequest; +import infra.http.client.BufferingClientHttpRequestFactory; import infra.http.client.ClientHttpRequest; import infra.http.client.ClientHttpRequestFactory; import infra.http.client.ClientHttpRequestInitializer; import infra.http.client.JdkClientHttpRequestFactory; import infra.lang.Assert; +import infra.lang.Nullable; import infra.logging.Logger; import infra.logging.LoggerFactory; @@ -54,9 +58,12 @@ public abstract class HttpAccessor { /** Logger available to subclasses. */ protected final Logger logger = LoggerFactory.getLogger(getClass()); + private final ArrayList httpRequestInitializers = new ArrayList<>(); + private ClientHttpRequestFactory requestFactory = new JdkClientHttpRequestFactory(); - private final ArrayList httpRequestInitializers = new ArrayList<>(); + @Nullable + private Predicate bufferingPredicate; /** * Set the request factory that this accessor uses for obtaining client request handles. @@ -78,7 +85,8 @@ public void setRequestFactory(ClientHttpRequestFactory requestFactory) { * Return the request factory that this accessor uses for obtaining client request handles. */ public ClientHttpRequestFactory getRequestFactory() { - return this.requestFactory; + return this.bufferingPredicate != null ? new BufferingClientHttpRequestFactory( + this.requestFactory, this.bufferingPredicate) : this.requestFactory; } /** @@ -87,7 +95,6 @@ public ClientHttpRequestFactory getRequestFactory() { * {@linkplain AnnotationAwareOrderComparator#sort(List) order}. */ public void setHttpRequestInitializers(List requestInitializers) { - if (this.httpRequestInitializers != requestInitializers) { this.httpRequestInitializers.clear(); this.httpRequestInitializers.addAll(requestInitializers); @@ -109,6 +116,28 @@ public List getHttpRequestInitializers() { return this.httpRequestInitializers; } + /** + * Enable buffering of request and response, aggregating all content before + * it is sent, and making it possible to read the response body repeatedly. + * + * @param predicate to determine whether to buffer for the given request + * @since 5.0 + */ + public void setBufferingPredicate(@Nullable Predicate predicate) { + this.bufferingPredicate = predicate; + } + + /** + * Return the {@link #setBufferingPredicate(Predicate) configured} predicate + * to determine whether to buffer request and response content. + * + * @since 5.0 + */ + @Nullable + public Predicate getBufferingPredicate() { + return this.bufferingPredicate; + } + /** * Create a new {@link ClientHttpRequest} via this template's {@link ClientHttpRequestFactory}. * diff --git a/today-web/src/main/java/infra/http/client/support/InterceptingHttpAccessor.java b/today-web/src/main/java/infra/http/client/support/InterceptingHttpAccessor.java index 2952203e76..4934abeafe 100755 --- a/today-web/src/main/java/infra/http/client/support/InterceptingHttpAccessor.java +++ b/today-web/src/main/java/infra/http/client/support/InterceptingHttpAccessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 - 2023 the original author or authors. + * Copyright 2017 - 2025 the original author or authors. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -12,7 +12,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program. If not, see [http://www.gnu.org/licenses/] + * along with this program. If not, see [https://www.gnu.org/licenses/] */ package infra.http.client.support; @@ -125,7 +125,8 @@ public ClientHttpRequestFactory getRequestFactory() { synchronized(this) { factory = this.interceptingRequestFactory; if (factory == null) { - factory = new InterceptingClientHttpRequestFactory(super.getRequestFactory(), interceptors); + factory = new InterceptingClientHttpRequestFactory( + super.getRequestFactory(), interceptors, getBufferingPredicate()); this.interceptingRequestFactory = factory; } } diff --git a/today-web/src/main/java/infra/web/client/DefaultRestClient.java b/today-web/src/main/java/infra/web/client/DefaultRestClient.java index 8dfba2c139..4184b5275d 100755 --- a/today-web/src/main/java/infra/web/client/DefaultRestClient.java +++ b/today-web/src/main/java/infra/web/client/DefaultRestClient.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 - 2024 the original author or authors. + * Copyright 2017 - 2025 the original author or authors. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -44,6 +44,7 @@ import infra.http.MediaType; import infra.http.ResponseEntity; import infra.http.StreamingHttpOutputMessage; +import infra.http.client.BufferingClientHttpRequestFactory; import infra.http.client.ClientHttpRequest; import infra.http.client.ClientHttpRequestFactory; import infra.http.client.ClientHttpRequestInitializer; @@ -110,6 +111,9 @@ final class DefaultRestClient implements RestClient { private final boolean detectEmptyMessageBody; + @Nullable + private final Predicate bufferingPredicate; + DefaultRestClient(ClientHttpRequestFactory clientRequestFactory, @Nullable List interceptors, @Nullable List initializers, @@ -117,6 +121,7 @@ final class DefaultRestClient implements RestClient { @Nullable MultiValueMap defaultCookies, @Nullable Consumer> defaultRequest, @Nullable List statusHandlers, + @Nullable Predicate bufferingPredicate, List> messageConverters, DefaultRestClientBuilder builder, boolean ignoreStatusHandlers, boolean detectEmptyMessageBody) { @@ -128,6 +133,7 @@ final class DefaultRestClient implements RestClient { this.defaultCookies = defaultCookies; this.defaultRequest = defaultRequest; this.defaultStatusHandlers = statusHandlers; + this.bufferingPredicate = bufferingPredicate; this.messageConverters = messageConverters; this.builder = builder; this.defaultStatusHandler = StatusHandler.defaultHandler(messageConverters); @@ -603,10 +609,14 @@ private ClientHttpRequest createRequest(URI uri) throws ResourceAccessException if (interceptors != null) { factory = interceptingRequestFactory; if (factory == null) { - factory = new InterceptingClientHttpRequestFactory(clientRequestFactory, interceptors); + factory = new InterceptingClientHttpRequestFactory( + clientRequestFactory, interceptors, bufferingPredicate); interceptingRequestFactory = factory; } } + else if (bufferingPredicate != null) { + factory = new BufferingClientHttpRequestFactory(clientRequestFactory, bufferingPredicate); + } else { factory = clientRequestFactory; } diff --git a/today-web/src/main/java/infra/web/client/DefaultRestClientBuilder.java b/today-web/src/main/java/infra/web/client/DefaultRestClientBuilder.java index 1c404ada65..65326d2d85 100755 --- a/today-web/src/main/java/infra/web/client/DefaultRestClientBuilder.java +++ b/today-web/src/main/java/infra/web/client/DefaultRestClientBuilder.java @@ -27,6 +27,7 @@ import java.util.function.Predicate; import infra.http.HttpHeaders; +import infra.http.HttpRequest; import infra.http.HttpStatusCode; import infra.http.client.ClientHttpRequestFactory; import infra.http.client.ClientHttpRequestInitializer; @@ -135,6 +136,9 @@ final class DefaultRestClientBuilder implements RestClient.Builder { @Nullable private List initializers; + @Nullable + private Predicate bufferingPredicate; + private boolean ignoreStatus = false; private boolean detectEmptyMessageBody = true; @@ -150,6 +154,7 @@ public DefaultRestClientBuilder(DefaultRestClientBuilder other) { this.defaultRequest = other.defaultRequest; this.requestFactory = other.requestFactory; this.uriBuilderFactory = other.uriBuilderFactory; + this.bufferingPredicate = other.bufferingPredicate; this.interceptors = other.interceptors != null ? new ArrayList<>(other.interceptors) : null; this.initializers = other.initializers != null ? new ArrayList<>(other.initializers) : null; @@ -169,6 +174,7 @@ public DefaultRestClientBuilder(RestTemplate restTemplate) { this.requestFactory = getRequestFactory(restTemplate); this.messageConverters = new ArrayList<>(restTemplate.getMessageConverters()); + this.bufferingPredicate = restTemplate.getBufferingPredicate(); if (CollectionUtils.isNotEmpty(restTemplate.getInterceptors())) { this.interceptors = new ArrayList<>(restTemplate.getInterceptors()); @@ -346,6 +352,12 @@ public RestClient.Builder requestInterceptors(Consumer predicate) { + bufferingPredicate = predicate; + return this; + } + private List initInterceptors() { if (this.interceptors == null) { this.interceptors = new ArrayList<>(); @@ -452,7 +464,7 @@ public RestClient build() { return new DefaultRestClient(requestFactory, this.interceptors, this.initializers, uriBuilderFactory, - defaultHeaders, defaultCookies, this.defaultRequest, this.statusHandlers, + defaultHeaders, defaultCookies, this.defaultRequest, this.statusHandlers, bufferingPredicate, messageConverters, new DefaultRestClientBuilder(this), ignoreStatus, detectEmptyMessageBody); } diff --git a/today-web/src/main/java/infra/web/client/RestClient.java b/today-web/src/main/java/infra/web/client/RestClient.java index b8ed52c5a1..6877900598 100755 --- a/today-web/src/main/java/infra/web/client/RestClient.java +++ b/today-web/src/main/java/infra/web/client/RestClient.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 - 2024 the original author or authors. + * Copyright 2017 - 2025 the original author or authors. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -496,6 +496,16 @@ default Builder ignoreStatus() { */ Builder requestInterceptors(Consumer> interceptorsConsumer); + /** + * Enable buffering of request and response, aggregating all content before + * it is sent, and making it possible to read the response body repeatedly. + * + * @param predicate to determine whether to buffer for the given request + * @return this builder + * @since 5.0 + */ + Builder bufferContent(Predicate predicate); + /** * Add the given request initializer to the end of the initializer chain. * diff --git a/today-web/src/test/java/infra/http/client/BufferingClientHttpRequestFactoryTests.java b/today-web/src/test/java/infra/http/client/BufferingClientHttpRequestFactoryTests.java index bbd92cfb23..9759aa3d83 100755 --- a/today-web/src/test/java/infra/http/client/BufferingClientHttpRequestFactoryTests.java +++ b/today-web/src/test/java/infra/http/client/BufferingClientHttpRequestFactoryTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 - 2024 the original author or authors. + * Copyright 2017 - 2025 the original author or authors. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/today-web/src/test/java/infra/http/client/JdkClientHttpRequestFactoryTests.java b/today-web/src/test/java/infra/http/client/JdkClientHttpRequestFactoryTests.java index 04ebbd24fa..b1bb8076a1 100755 --- a/today-web/src/test/java/infra/http/client/JdkClientHttpRequestFactoryTests.java +++ b/today-web/src/test/java/infra/http/client/JdkClientHttpRequestFactoryTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 - 2023 the original author or authors. + * Copyright 2017 - 2025 the original author or authors. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -12,7 +12,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program. If not, see [http://www.gnu.org/licenses/] + * along with this program. If not, see [https://www.gnu.org/licenses/] */ package infra.http.client; diff --git a/today-web/src/test/java/infra/web/client/RestClientIntegrationTests.java b/today-web/src/test/java/infra/web/client/RestClientIntegrationTests.java index c3d8f4ac8d..fbb4c6967b 100755 --- a/today-web/src/test/java/infra/web/client/RestClientIntegrationTests.java +++ b/today-web/src/test/java/infra/web/client/RestClientIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 - 2024 the original author or authors. + * Copyright 2017 - 2025 the original author or authors. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -51,6 +51,7 @@ import infra.http.client.JdkClientHttpRequestFactory; import infra.http.client.ReactorClientHttpRequestFactory; import infra.util.CollectionUtils; +import infra.util.FileCopyUtils; import infra.util.LinkedMultiValueMap; import infra.util.MultiValueMap; import infra.util.concurrent.Future; @@ -59,6 +60,7 @@ import okhttp3.mockwebserver.MockWebServer; import okhttp3.mockwebserver.RecordedRequest; +import static java.nio.charset.StandardCharsets.UTF_8; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.junit.jupiter.api.Assumptions.assumeFalse; @@ -816,6 +818,57 @@ void requestInterceptor(ClientHttpRequestFactory requestFactory) { expectRequest(request -> assertThat(request.getHeader("foo")).isEqualTo("bar")); } + @ParameterizedRestClientTest + void requestInterceptorWithResponseBuffering(ClientHttpRequestFactory requestFactory) { + startServer(requestFactory); + + prepareResponse(response -> + response.setHeader("Content-Type", "text/plain").setBody("Hello Infra!")); + + RestClient interceptedClient = this.restClient.mutate() + .requestInterceptor((request, body, execution) -> { + ClientHttpResponse response = execution.execute(request, body); + byte[] result = FileCopyUtils.copyToByteArray(response.getBody()); + assertThat(result).isEqualTo("Hello Infra!".getBytes(UTF_8)); + return response; + }) + .bufferContent(request -> true) + .build(); + + String result = interceptedClient.get() + .uri("/greeting") + .retrieve() + .body(String.class); + + expectRequestCount(1); + assertThat(result).isEqualTo("Hello Infra!"); + } + + @ParameterizedRestClientTest + void bufferContent(ClientHttpRequestFactory requestFactory) { + startServer(requestFactory); + + prepareResponse(response -> + response.setHeader("Content-Type", "text/plain").setBody("Hello Infra!")); + + RestClient bufferingClient = this.restClient.mutate() + .bufferContent(request -> true) + .build(); + + String result = bufferingClient.get() + .uri("/greeting") + .exchange((request, response) -> { + byte[] bytes = FileCopyUtils.copyToByteArray(response.getBody()); + assertThat(bytes).isEqualTo("Hello Infra!".getBytes(UTF_8)); + bytes = FileCopyUtils.copyToByteArray(response.getBody()); + assertThat(bytes).isEqualTo("Hello Infra!".getBytes(UTF_8)); + return new String(bytes, UTF_8); + }); + + expectRequestCount(1); + assertThat(result).isEqualTo("Hello Infra!"); + } + @ParameterizedRestClientTest void retrieveDefaultCookiesAsCookieHeader(ClientHttpRequestFactory requestFactory) { startServer(requestFactory); diff --git a/today-web/src/test/java/infra/web/client/config/ClientHttpRequestFactoriesTests.java b/today-web/src/test/java/infra/web/client/config/ClientHttpRequestFactoriesTests.java index 5a0a488bc7..08a6f028fb 100755 --- a/today-web/src/test/java/infra/web/client/config/ClientHttpRequestFactoriesTests.java +++ b/today-web/src/test/java/infra/web/client/config/ClientHttpRequestFactoriesTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 - 2024 the original author or authors. + * Copyright 2017 - 2025 the original author or authors. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by