Skip to content

Commit 22376c2

Browse files
committed
Polishing
See gh-30117
1 parent 47667ab commit 22376c2

File tree

21 files changed

+185
-195
lines changed

21 files changed

+185
-195
lines changed

framework-docs/modules/ROOT/pages/integration/rest-clients.adoc

+5-3
Original file line numberDiff line numberDiff line change
@@ -388,7 +388,8 @@ either using `WebClient`:
388388
[source,java,indent=0,subs="verbatim,quotes"]
389389
----
390390
WebClient client = WebClient.builder().baseUrl("https://api.github.com/").build();
391-
HttpServiceProxyFactory factory = HttpServiceProxyFactory.builder().exchangeAdapter(WebClientAdapter.forClient(webClient)).build();
391+
WebClientAdapter adapter = WebClientAdapter.forClient(webClient)
392+
HttpServiceProxyFactory factory = HttpServiceProxyFactory.builderFor(adapter).build();
392393
393394
RepositoryService service = factory.createClient(RepositoryService.class);
394395
----
@@ -398,8 +399,9 @@ or using `RestTemplate`:
398399
[source,java,indent=0,subs="verbatim,quotes"]
399400
----
400401
RestTemplate restTemplate = new RestTemplate();
401-
restTemplate.setUriTemplateHandler(new DefaultUriBuilderFactory("https://api.github.com/"));
402-
HttpServiceProxyFactory factory = HttpServiceProxyFactory.builder().exchangeAdapter(RestTemplateAdapter.forTemplate(restTemplate)).build();
402+
restTemplate.setUriTemplateHandler(new DefaultUriBuilderFactory("https://api.github.com/"));
403+
RestTemplateAdapter adapter = RestTemplateAdapter.forTemplate(restTemplate);
404+
HttpServiceProxyFactory factory = HttpServiceProxyFactory.builderFor(adapter).build();
403405
404406
RepositoryService service = factory.createClient(RepositoryService.class);
405407
----

spring-web/src/main/java/org/springframework/web/client/support/RestTemplateAdapter.java

+31-34
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,9 @@
1717
package org.springframework.web.client.support;
1818

1919
import java.net.URI;
20+
import java.util.ArrayList;
2021
import java.util.List;
21-
import java.util.stream.Collectors;
22+
import java.util.Map;
2223

2324
import org.springframework.core.ParameterizedTypeReference;
2425
import org.springframework.http.HttpCookie;
@@ -27,19 +28,17 @@
2728
import org.springframework.http.RequestEntity;
2829
import org.springframework.http.ResponseEntity;
2930
import org.springframework.util.Assert;
30-
import org.springframework.util.LinkedMultiValueMap;
31-
import org.springframework.util.MultiValueMap;
3231
import org.springframework.web.client.RestTemplate;
3332
import org.springframework.web.service.invoker.HttpExchangeAdapter;
3433
import org.springframework.web.service.invoker.HttpRequestValues;
3534
import org.springframework.web.service.invoker.HttpServiceProxyFactory;
3635

3736
/**
38-
* An {@link HttpExchangeAdapter} that enables an {@link HttpServiceProxyFactory} to use
37+
* {@link HttpExchangeAdapter} that enables an {@link HttpServiceProxyFactory} to use
3938
* {@link RestTemplate} for request execution.
40-
* <p>
41-
* Use static factory methods in this class to create an {@link HttpServiceProxyFactory}
42-
* configured with a given {@link RestTemplate}.
39+
*
40+
* <p>Use static factory methods in this class to create an
41+
* {@link HttpServiceProxyFactory} configured with a given {@link RestTemplate}.
4342
*
4443
* @author Olga Maciaszek-Sharma
4544
* @since 6.1
@@ -48,11 +47,17 @@ public final class RestTemplateAdapter implements HttpExchangeAdapter {
4847

4948
private final RestTemplate restTemplate;
5049

51-
// Private constructor; use static factory methods to instantiate
50+
5251
private RestTemplateAdapter(RestTemplate restTemplate) {
5352
this.restTemplate = restTemplate;
5453
}
5554

55+
56+
@Override
57+
public boolean supportsRequestAttributes() {
58+
return false;
59+
}
60+
5661
@Override
5762
public void exchange(HttpRequestValues requestValues) {
5863
this.restTemplate.exchange(newRequest(requestValues), Void.class);
@@ -74,14 +79,10 @@ public ResponseEntity<Void> exchangeForBodilessEntity(HttpRequestValues requestV
7479
}
7580

7681
@Override
77-
public <T> ResponseEntity<T> exchangeForEntity(HttpRequestValues requestValues,
78-
ParameterizedTypeReference<T> bodyType) {
79-
return this.restTemplate.exchange(newRequest(requestValues), bodyType);
80-
}
82+
public <T> ResponseEntity<T> exchangeForEntity(
83+
HttpRequestValues requestValues, ParameterizedTypeReference<T> bodyType) {
8184

82-
@Override
83-
public boolean supportsRequestAttributes() {
84-
return false;
85+
return this.restTemplate.exchange(newRequest(requestValues), bodyType);
8586
}
8687

8788
private RequestEntity<?> newRequest(HttpRequestValues requestValues) {
@@ -90,8 +91,9 @@ private RequestEntity<?> newRequest(HttpRequestValues requestValues) {
9091
uri = requestValues.getUri();
9192
}
9293
else if (requestValues.getUriTemplate() != null) {
93-
uri = this.restTemplate.getUriTemplateHandler().expand(requestValues.getUriTemplate(),
94-
requestValues.getUriVariables());
94+
String uriTemplate = requestValues.getUriTemplate();
95+
Map<String, String> variables = requestValues.getUriVariables();
96+
uri = this.restTemplate.getUriTemplateHandler().expand(uriTemplate, variables);
9597
}
9698
else {
9799
throw new IllegalStateException("Neither full URL nor URI template");
@@ -100,35 +102,30 @@ else if (requestValues.getUriTemplate() != null) {
100102
HttpMethod httpMethod = requestValues.getHttpMethod();
101103
Assert.notNull(httpMethod, "HttpMethod is required");
102104

103-
RequestEntity.BodyBuilder builder = RequestEntity.method(httpMethod, uri)
104-
.headers(requestValues.getHeaders());
105+
RequestEntity.BodyBuilder builder = RequestEntity.method(httpMethod, uri);
106+
builder.headers(requestValues.getHeaders());
105107

106108
if (!requestValues.getCookies().isEmpty()) {
107-
MultiValueMap<String, HttpCookie> cookies = new LinkedMultiValueMap<>();
108-
requestValues.getCookies()
109-
.forEach((name, values) -> values.forEach(value ->
110-
cookies.add(name, new HttpCookie(name, value))));
111-
112-
builder.header(HttpHeaders.COOKIE,
113-
cookies.values()
114-
.stream()
115-
.flatMap(List::stream)
116-
.map(HttpCookie::toString)
117-
.collect(Collectors.joining("; ")));
109+
List<String> cookies = new ArrayList<>();
110+
requestValues.getCookies().forEach((name, values) -> values.forEach(value -> {
111+
HttpCookie cookie = new HttpCookie(name, value);
112+
cookies.add(cookie.toString());
113+
}));
114+
builder.header(HttpHeaders.COOKIE, String.join("; ", cookies));
118115
}
119116

120117
if (requestValues.getBodyValue() != null) {
121118
return builder.body(requestValues.getBodyValue());
122119
}
120+
123121
return builder.build();
124122
}
125123

124+
126125
/**
127-
* Create a {@link RestTemplateAdapter} for the given {@link RestTemplate} instance.
128-
* @param restTemplate the {@link RestTemplate} to use
129-
* @return the created adapter instance
126+
* Create a {@link RestTemplateAdapter} with the given {@link RestTemplate}.
130127
*/
131-
public static RestTemplateAdapter forTemplate(RestTemplate restTemplate) {
128+
public static RestTemplateAdapter create(RestTemplate restTemplate) {
132129
return new RestTemplateAdapter(restTemplate);
133130
}
134131

spring-web/src/main/java/org/springframework/web/service/invoker/AbstractReactorHttpExchangeAdapter.java

+10-18
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,8 @@
2929
import org.springframework.util.Assert;
3030

3131
/**
32-
* A base reactive adapter that implements both {@link HttpClientAdapter}
33-
* and {@link HttpExchangeAdapter}. Allows to ensure backwards compatibility
34-
* with the deprecated {@link HttpClientAdapter} and handles blocking from reactive
35-
* publishers to objects where necessary.
32+
* Convenient base class for a {@link ReactorHttpExchangeAdapter} implementation
33+
* adapting to the synchronous {@link HttpExchangeAdapter} contract.
3634
*
3735
* @author Rossen Stoyanchev
3836
* @since 6.1
@@ -55,30 +53,21 @@ protected AbstractReactorHttpExchangeAdapter() {
5553

5654

5755
/**
58-
* Configure the registry for adapting various reactive types.
59-
* <p>By default this is an instance of {@link ReactiveAdapterRegistry} with
60-
* default settings.
56+
* Configure the {@link ReactiveAdapterRegistry} to use.
57+
* <p>By default, this is {@link ReactiveAdapterRegistry#getSharedInstance()}.
6158
*/
6259
public void setReactiveAdapterRegistry(ReactiveAdapterRegistry reactiveAdapterRegistry) {
6360
this.reactiveAdapterRegistry = reactiveAdapterRegistry;
6461
}
6562

66-
/**
67-
* Return the configured reactive type registry of adapters.
68-
*/
6963
@Override
7064
public ReactiveAdapterRegistry getReactiveAdapterRegistry() {
7165
return this.reactiveAdapterRegistry;
7266
}
7367

7468
/**
75-
* Configure how long to block for the response of an HTTP service method with a
76-
* synchronous (blocking) method signature.
77-
* <p>
78-
* By default, this is not set, in which case the behavior depends on connection and
79-
* request timeout settings of the underlying HTTP client. We recommend configuring
80-
* timeout values directly on the underlying HTTP client, which provides more
81-
* control over such settings.
69+
* Configure how long to block for the response of an HTTP service method
70+
* as described in {@link #getBlockTimeout()}.
8271
*/
8372
public void setBlockTimeout(@Nullable Duration blockTimeout) {
8473
this.blockTimeout = blockTimeout;
@@ -90,6 +79,7 @@ public Duration getBlockTimeout() {
9079
return this.blockTimeout;
9180
}
9281

82+
9383
@Override
9484
public void exchange(HttpRequestValues requestValues) {
9585
if (this.blockTimeout != null) {
@@ -126,7 +116,9 @@ public ResponseEntity<Void> exchangeForBodilessEntity(HttpRequestValues requestV
126116
}
127117

128118
@Override
129-
public <T> ResponseEntity<T> exchangeForEntity(HttpRequestValues requestValues, ParameterizedTypeReference<T> bodyType) {
119+
public <T> ResponseEntity<T> exchangeForEntity(
120+
HttpRequestValues requestValues, ParameterizedTypeReference<T> bodyType) {
121+
130122
ResponseEntity<T> entity = (this.blockTimeout != null ?
131123
exchangeForEntityMono(requestValues, bodyType).block(this.blockTimeout) :
132124
exchangeForEntityMono(requestValues, bodyType).block());

spring-web/src/main/java/org/springframework/web/service/invoker/HttpClientAdapter.java

+19-23
Original file line numberDiff line numberDiff line change
@@ -91,59 +91,55 @@ public interface HttpClientAdapter {
9191

9292

9393
/**
94-
* Adapt this {@link HttpClientAdapter} to {@link ReactorHttpExchangeAdapter}.
95-
* @return a {@link ReactorHttpExchangeAdapter} instance created that delegating to
96-
* the underlying {@link HttpClientAdapter} implementation
94+
* Adapt this instance to {@link ReactorHttpExchangeAdapter}.
9795
* @since 6.1
9896
*/
99-
default ReactorHttpExchangeAdapter asHttpExchangeAdapter() {
100-
101-
HttpClientAdapter delegate = this;
97+
default ReactorHttpExchangeAdapter asReactorExchangeAdapter() {
10298

10399
return new AbstractReactorHttpExchangeAdapter() {
104100

105101
@Override
106-
public Mono<Void> exchangeForMono(HttpRequestValues requestValues) {
107-
return delegate.requestToVoid(requestValues);
102+
public boolean supportsRequestAttributes() {
103+
return true;
104+
}
105+
106+
@Override
107+
public Mono<Void> exchangeForMono(HttpRequestValues values) {
108+
return HttpClientAdapter.this.requestToVoid(values);
108109
}
109110

110111
@Override
111-
public Mono<HttpHeaders> exchangeForHeadersMono(HttpRequestValues requestValues) {
112-
return delegate.requestToHeaders(requestValues);
112+
public Mono<HttpHeaders> exchangeForHeadersMono(HttpRequestValues values) {
113+
return HttpClientAdapter.this.requestToHeaders(values);
113114
}
114115

115116
@Override
116-
public <T> Mono<T> exchangeForBodyMono(HttpRequestValues requestValues, ParameterizedTypeReference<T> bodyType) {
117-
return delegate.requestToBody(requestValues, bodyType);
117+
public <T> Mono<T> exchangeForBodyMono(HttpRequestValues values, ParameterizedTypeReference<T> bodyType) {
118+
return HttpClientAdapter.this.requestToBody(values, bodyType);
118119
}
119120

120121
@Override
121-
public <T> Flux<T> exchangeForBodyFlux(HttpRequestValues requestValues, ParameterizedTypeReference<T> bodyType) {
122-
return delegate.requestToBodyFlux(requestValues, bodyType);
122+
public <T> Flux<T> exchangeForBodyFlux(HttpRequestValues values, ParameterizedTypeReference<T> bodyType) {
123+
return HttpClientAdapter.this.requestToBodyFlux(values, bodyType);
123124
}
124125

125126
@Override
126-
public Mono<ResponseEntity<Void>> exchangeForBodilessEntityMono(HttpRequestValues requestValues) {
127-
return delegate.requestToBodilessEntity(requestValues);
127+
public Mono<ResponseEntity<Void>> exchangeForBodilessEntityMono(HttpRequestValues values) {
128+
return HttpClientAdapter.this.requestToBodilessEntity(values);
128129
}
129130

130131
@Override
131132
public <T> Mono<ResponseEntity<T>> exchangeForEntityMono(
132133
HttpRequestValues requestValues, ParameterizedTypeReference<T> bodyType) {
133134

134-
return delegate.requestToEntity(requestValues, bodyType);
135+
return HttpClientAdapter.this.requestToEntity(requestValues, bodyType);
135136
}
136137

137138
@Override
138139
public <T> Mono<ResponseEntity<Flux<T>>> exchangeForEntityFlux(
139140
HttpRequestValues requestValues, ParameterizedTypeReference<T> bodyType) {
140141

141-
return delegate.requestToEntityFlux(requestValues, bodyType);
142-
}
143-
144-
@Override
145-
public boolean supportsRequestAttributes() {
146-
return true;
142+
return HttpClientAdapter.this.requestToEntityFlux(requestValues, bodyType);
147143
}
148144
};
149145
}

spring-web/src/main/java/org/springframework/web/service/invoker/HttpExchangeAdapter.java

+8-6
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@
3030
*/
3131
public interface HttpExchangeAdapter {
3232

33+
/**
34+
* Whether the underlying client supports use of request attributes.
35+
*/
36+
boolean supportsRequestAttributes();
37+
3338
/**
3439
* Perform the given request, and release the response content, if any.
3540
* @param requestValues the request to perform
@@ -49,26 +54,23 @@ public interface HttpExchangeAdapter {
4954
* @param requestValues the request to perform
5055
* @param bodyType the target type to decode to
5156
* @param <T> the type the response is decoded to
52-
* @return the decoded response.
57+
* @return the decoded response body.
5358
*/
5459
@Nullable
5560
<T> T exchangeForBody(HttpRequestValues requestValues, ParameterizedTypeReference<T> bodyType);
5661

5762
/**
5863
* Variant of {@link #exchange(HttpRequestValues)} with additional
5964
* access to the response status and headers.
65+
* @return the response entity with status and headers.
6066
*/
6167
ResponseEntity<Void> exchangeForBodilessEntity(HttpRequestValues requestValues);
6268

6369
/**
6470
* Variant of {@link #exchangeForBody(HttpRequestValues, ParameterizedTypeReference)}
6571
* with additional access to the response status and headers.
72+
* @return the response entity with status, headers, and body.
6673
*/
6774
<T> ResponseEntity<T> exchangeForEntity(HttpRequestValues requestValues, ParameterizedTypeReference<T> bodyType);
6875

69-
/**
70-
* A flag that indicates whether request attributes are supported by a specific client
71-
* adapter.
72-
*/
73-
boolean supportsRequestAttributes();
7476
}

0 commit comments

Comments
 (0)