From b83cb4a9479ae8c3b2e37f2a797c2648c6c2f25a Mon Sep 17 00:00:00 2001 From: rstoyanchev Date: Wed, 25 Feb 2026 12:42:48 +0000 Subject: [PATCH] Make newRequest methods public The methods to build a request in RestClientAdapter and WebClientAdapter are now public to make it easier to create a custom adapter that wraps the built-in ones and delegates for methods that can be the same. Closes gh-36374 --- .../web/client/support/RestClientAdapter.java | 64 +++++++++++-------- .../client/support/WebClientAdapter.java | 54 ++++++++-------- 2 files changed, 65 insertions(+), 53 deletions(-) diff --git a/spring-web/src/main/java/org/springframework/web/client/support/RestClientAdapter.java b/spring-web/src/main/java/org/springframework/web/client/support/RestClientAdapter.java index c98fc680a54..dcc5925c39b 100644 --- a/spring-web/src/main/java/org/springframework/web/client/support/RestClientAdapter.java +++ b/spring-web/src/main/java/org/springframework/web/client/support/RestClientAdapter.java @@ -86,63 +86,71 @@ public final class RestClientAdapter implements HttpExchangeAdapter { return newRequest(values).retrieve().toEntity(bodyType); } - @SuppressWarnings("unchecked") - private RestClient.RequestBodySpec newRequest(HttpRequestValues values) { - - HttpMethod httpMethod = values.getHttpMethod(); - Assert.notNull(httpMethod, "HttpMethod is required"); + /** + * Build a request from the given {@code HttpRequestValues}. + * @param values the values to use + * @return the request spec + * @since 7.0.6 + */ + public RestClient.RequestBodySpec newRequest(HttpRequestValues values) { + HttpMethod method = values.getHttpMethod(); + Assert.notNull(method, "HttpMethod is required"); + RestClient.RequestBodyUriSpec uriSpec = this.restClient.method(method); + RestClient.RequestBodySpec spec = setUri(uriSpec, values); + spec.headers(headers -> headers.putAll(values.getHeaders())); + setCookieHeader(spec, values); + spec.apiVersion(values.getApiVersion()); + spec.attributes(attributes -> attributes.putAll(values.getAttributes())); + setBody(spec, values); + return spec; + } - RestClient.RequestBodyUriSpec uriSpec = this.restClient.method(httpMethod); + private static RestClient.RequestBodySpec setUri( + RestClient.RequestBodyUriSpec spec, HttpRequestValues values) { - RestClient.RequestBodySpec bodySpec; if (values.getUri() != null) { - bodySpec = uriSpec.uri(values.getUri()); + return spec.uri(values.getUri()); } - else if (values.getUriTemplate() != null) { + + if (values.getUriTemplate() != null) { UriBuilderFactory uriBuilderFactory = values.getUriBuilderFactory(); if (uriBuilderFactory != null) { URI uri = uriBuilderFactory.expand(values.getUriTemplate(), values.getUriVariables()); - bodySpec = uriSpec.uri(uri); + return spec.uri(uri); } else { - bodySpec = uriSpec.uri(values.getUriTemplate(), values.getUriVariables()); + return spec.uri(values.getUriTemplate(), values.getUriVariables()); } } - else { - throw new IllegalStateException("Neither full URL nor URI template"); - } - bodySpec.headers(headers -> headers.putAll(values.getHeaders())); + throw new IllegalStateException("Neither full URL nor URI template"); + } + private static void setCookieHeader(RestClient.RequestBodySpec spec, HttpRequestValues values) { if (!values.getCookies().isEmpty()) { List cookies = new ArrayList<>(); values.getCookies().forEach((name, cookieValues) -> cookieValues.forEach(value -> { HttpCookie cookie = new HttpCookie(name, value); cookies.add(cookie.toString()); })); - bodySpec.header(HttpHeaders.COOKIE, String.join("; ", cookies)); - } - - if (values.getApiVersion() != null) { - bodySpec.apiVersion(values.getApiVersion()); + spec.header(HttpHeaders.COOKIE, String.join("; ", cookies)); } + } - bodySpec.attributes(attributes -> attributes.putAll(values.getAttributes())); - - B body = (B) values.getBodyValue(); + @SuppressWarnings("unchecked") + private void setBody(RestClient.RequestBodySpec spec, HttpRequestValues values) { + Object body = values.getBodyValue(); if (body != null) { if (body instanceof StreamingHttpOutputMessage.Body streamingBody) { - bodySpec.body(streamingBody); + spec.body(streamingBody); } else if (values.getBodyValueType() != null) { - bodySpec.body(body, (ParameterizedTypeReference) values.getBodyValueType()); + spec.body((B) body, (ParameterizedTypeReference) values.getBodyValueType()); } else { - bodySpec.body(body); + spec.body(body); } } - - return bodySpec; } diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/support/WebClientAdapter.java b/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/support/WebClientAdapter.java index 3bf72c4e38d..97c9410fbd4 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/support/WebClientAdapter.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/function/client/support/WebClientAdapter.java @@ -98,49 +98,55 @@ public final class WebClientAdapter extends AbstractReactorHttpExchangeAdapter { return newRequest(requestValues).retrieve().toEntityFlux(bodyType); } - @SuppressWarnings({"ReactiveStreamsUnusedPublisher", "unchecked"}) - private WebClient.RequestBodySpec newRequest(HttpRequestValues values) { - + /** + * Build a request from the given {@code HttpRequestValues}. + * @param values the values to use + * @return the request spec + * @since 7.0.6 + */ + public WebClient.RequestBodySpec newRequest(HttpRequestValues values) { HttpMethod httpMethod = values.getHttpMethod(); Assert.notNull(httpMethod, "HttpMethod is required"); - WebClient.RequestBodyUriSpec uriSpec = this.webClient.method(httpMethod); + WebClient.RequestBodySpec bodySpec = setUri(uriSpec, values); + bodySpec.headers(headers -> headers.putAll(values.getHeaders())); + bodySpec.cookies(cookies -> cookies.putAll(values.getCookies())); + bodySpec.apiVersion(values.getApiVersion()); + bodySpec.attributes(attributes -> attributes.putAll(values.getAttributes())); + setBody(bodySpec, values); + return bodySpec; + } + + private static WebClient.RequestBodySpec setUri( + WebClient.RequestBodyUriSpec spec, HttpRequestValues values) { - WebClient.RequestBodySpec bodySpec; if (values.getUri() != null) { - bodySpec = uriSpec.uri(values.getUri()); + return spec.uri(values.getUri()); } - else if (values.getUriTemplate() != null) { + if (values.getUriTemplate() != null) { UriBuilderFactory uriBuilderFactory = values.getUriBuilderFactory(); if(uriBuilderFactory != null){ URI uri = uriBuilderFactory.expand(values.getUriTemplate(), values.getUriVariables()); - bodySpec = uriSpec.uri(uri); + return spec.uri(uri); } else { - bodySpec = uriSpec.uri(values.getUriTemplate(), values.getUriVariables()); + return spec.uri(values.getUriTemplate(), values.getUriVariables()); } } - else { - throw new IllegalStateException("Neither full URL nor URI template"); - } - - bodySpec.headers(headers -> headers.putAll(values.getHeaders())); - bodySpec.cookies(cookies -> cookies.putAll(values.getCookies())); - - if (values.getApiVersion() != null) { - bodySpec.apiVersion(values.getApiVersion()); - } - bodySpec.attributes(attributes -> attributes.putAll(values.getAttributes())); + throw new IllegalStateException("Neither full URL nor URI template"); + } + @SuppressWarnings({"ReactiveStreamsUnusedPublisher", "unchecked"}) + private void setBody(WebClient.RequestBodySpec spec, HttpRequestValues values) { if (values.getBodyValue() != null) { if (values.getBodyValueType() != null) { B body = (B) values.getBodyValue(); - bodySpec.bodyValue(body, (ParameterizedTypeReference) values.getBodyValueType()); + spec.bodyValue(body, (ParameterizedTypeReference) values.getBodyValueType()); } else { - bodySpec.bodyValue(values.getBodyValue()); + spec.bodyValue(values.getBodyValue()); } } else if (values instanceof ReactiveHttpRequestValues rhrv) { @@ -148,11 +154,9 @@ public final class WebClientAdapter extends AbstractReactorHttpExchangeAdapter { if (body != null) { ParameterizedTypeReference elementType = rhrv.getBodyPublisherElementType(); Assert.notNull(elementType, "Publisher body element type is required"); - bodySpec.body(body, elementType); + spec.body(body, elementType); } } - - return bodySpec; }