Skip to content

Commit bf82ed7

Browse files
committed
Add HttpExchangeAdapter
See gh-30117
1 parent 1b27a7b commit bf82ed7

File tree

9 files changed

+544
-73
lines changed

9 files changed

+544
-73
lines changed
Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
/*
2+
* Copyright 2002-2023 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.web.service.invoker;
18+
19+
import java.time.Duration;
20+
21+
import reactor.core.publisher.Flux;
22+
import reactor.core.publisher.Mono;
23+
24+
import org.springframework.core.ParameterizedTypeReference;
25+
import org.springframework.core.ReactiveAdapterRegistry;
26+
import org.springframework.http.HttpHeaders;
27+
import org.springframework.http.ResponseEntity;
28+
import org.springframework.lang.Nullable;
29+
import org.springframework.util.Assert;
30+
31+
/**
32+
*
33+
* @author Rossen Stoyanchev
34+
* @since 6.1
35+
*/
36+
@SuppressWarnings("removal")
37+
public abstract class AbstractReactorHttpExchangeAdapter
38+
implements ReactorHttpExchangeAdapter, org.springframework.web.service.invoker.HttpClientAdapter {
39+
40+
private ReactiveAdapterRegistry reactiveAdapterRegistry = ReactiveAdapterRegistry.getSharedInstance();
41+
42+
@Nullable
43+
private Duration blockTimeout;
44+
45+
46+
/**
47+
* Protected constructor, for subclasses.
48+
*/
49+
protected AbstractReactorHttpExchangeAdapter() {
50+
}
51+
52+
53+
/**
54+
*
55+
* @param reactiveAdapterRegistry
56+
*/
57+
public void setReactiveAdapterRegistry(ReactiveAdapterRegistry reactiveAdapterRegistry) {
58+
this.reactiveAdapterRegistry = reactiveAdapterRegistry;
59+
}
60+
61+
/**
62+
*
63+
* @return
64+
*/
65+
@Override
66+
public ReactiveAdapterRegistry getReactiveAdapterRegistry() {
67+
return this.reactiveAdapterRegistry;
68+
}
69+
70+
/**
71+
*
72+
* @param blockTimeout
73+
*/
74+
public void setBlockTimeout(@Nullable Duration blockTimeout) {
75+
this.blockTimeout = blockTimeout;
76+
}
77+
78+
/**
79+
*
80+
* @return
81+
*/
82+
@Override
83+
@Nullable
84+
public Duration getBlockTimeout() {
85+
return this.blockTimeout;
86+
}
87+
88+
89+
@Override
90+
public void exchange(HttpRequestValues requestValues) {
91+
if (this.blockTimeout != null) {
92+
exchangeForMono(requestValues).block(this.blockTimeout);
93+
}
94+
else {
95+
exchangeForMono(requestValues).block();
96+
}
97+
}
98+
99+
@Override
100+
public HttpHeaders exchangeForHeaders(HttpRequestValues requestValues) {
101+
HttpHeaders headers = (this.blockTimeout != null ?
102+
exchangeForHeadersMono(requestValues).block(this.blockTimeout) :
103+
exchangeForHeadersMono(requestValues).block());
104+
Assert.state(headers != null, "Expected HttpHeaders");
105+
return headers;
106+
}
107+
108+
@Override
109+
public <T> T exchangeForBody(HttpRequestValues requestValues, ParameterizedTypeReference<T> bodyType) {
110+
return (this.blockTimeout != null ?
111+
exchangeForBodyMono(requestValues, bodyType).block(this.blockTimeout) :
112+
exchangeForBodyMono(requestValues, bodyType).block());
113+
}
114+
115+
@Override
116+
public ResponseEntity<Void> exchangeForBodilessEntity(HttpRequestValues requestValues) {
117+
ResponseEntity<Void> entity = (this.blockTimeout != null ?
118+
exchangeForBodilessEntityMono(requestValues).block(this.blockTimeout) :
119+
exchangeForBodilessEntityMono(requestValues).block());
120+
Assert.state(entity != null, "Expected ResponseEntity");
121+
return entity;
122+
}
123+
124+
@Override
125+
public <T> ResponseEntity<T> exchangeForEntity(HttpRequestValues requestValues, ParameterizedTypeReference<T> bodyType) {
126+
ResponseEntity<T> entity = (this.blockTimeout != null ?
127+
exchangeForEntityMono(requestValues, bodyType).block(this.blockTimeout) :
128+
exchangeForEntityMono(requestValues, bodyType).block());
129+
Assert.state(entity != null, "Expected ResponseEntity");
130+
return entity;
131+
}
132+
133+
134+
// HttpClientAdapter implementation
135+
136+
@Override
137+
public Mono<Void> requestToVoid(HttpRequestValues requestValues) {
138+
return exchangeForMono(requestValues);
139+
}
140+
141+
@Override
142+
public Mono<HttpHeaders> requestToHeaders(HttpRequestValues requestValues) {
143+
return exchangeForHeadersMono(requestValues);
144+
}
145+
146+
@Override
147+
public <T> Mono<T> requestToBody(HttpRequestValues requestValues, ParameterizedTypeReference<T> bodyType) {
148+
return exchangeForBodyMono(requestValues, bodyType);
149+
}
150+
151+
@Override
152+
public <T> Flux<T> requestToBodyFlux(HttpRequestValues requestValues, ParameterizedTypeReference<T> bodyType) {
153+
return exchangeForBodyFlux(requestValues, bodyType);
154+
}
155+
156+
@Override
157+
public Mono<ResponseEntity<Void>> requestToBodilessEntity(HttpRequestValues requestValues) {
158+
return exchangeForBodilessEntityMono(requestValues);
159+
}
160+
161+
@Override
162+
public <T> Mono<ResponseEntity<T>> requestToEntity(
163+
HttpRequestValues requestValues, ParameterizedTypeReference<T> bodyType) {
164+
165+
return exchangeForEntityMono(requestValues, bodyType);
166+
}
167+
168+
@Override
169+
public <T> Mono<ResponseEntity<Flux<T>>> requestToEntityFlux(
170+
HttpRequestValues requestValues, ParameterizedTypeReference<T> bodyType) {
171+
172+
return exchangeForEntityFlux(requestValues, bodyType);
173+
}
174+
175+
}

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

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2022 the original author or authors.
2+
* Copyright 2002-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -29,7 +29,9 @@
2929
*
3030
* @author Rossen Stoyanchev
3131
* @since 6.0
32+
* @deprecated in favor of {@link ReactorHttpExchangeAdapter}
3233
*/
34+
@Deprecated(since = "6.1", forRemoval = true)
3335
public interface HttpClientAdapter {
3436

3537
/**
@@ -86,4 +88,55 @@ public interface HttpClientAdapter {
8688
*/
8789
<T> Mono<ResponseEntity<Flux<T>>> requestToEntityFlux(HttpRequestValues requestValues, ParameterizedTypeReference<T> bodyType);
8890

91+
92+
/**
93+
* Adapt this {@link HttpClientAdapter} to {@link ReactorHttpExchangeAdapter}.
94+
* @return
95+
* @since 6.1
96+
*/
97+
default ReactorHttpExchangeAdapter asHttpExchangeAdapter() {
98+
99+
return new AbstractReactorHttpExchangeAdapter() {
100+
101+
@Override
102+
public Mono<Void> exchangeForMono(HttpRequestValues requestValues) {
103+
return requestToVoid(requestValues);
104+
}
105+
106+
@Override
107+
public Mono<HttpHeaders> exchangeForHeadersMono(HttpRequestValues requestValues) {
108+
return requestToHeaders(requestValues);
109+
}
110+
111+
@Override
112+
public <T> Mono<T> exchangeForBodyMono(HttpRequestValues requestValues, ParameterizedTypeReference<T> bodyType) {
113+
return requestToBody(requestValues, bodyType);
114+
}
115+
116+
@Override
117+
public <T> Flux<T> exchangeForBodyFlux(HttpRequestValues requestValues, ParameterizedTypeReference<T> bodyType) {
118+
return requestToBodyFlux(requestValues, bodyType);
119+
}
120+
121+
@Override
122+
public Mono<ResponseEntity<Void>> exchangeForBodilessEntityMono(HttpRequestValues requestValues) {
123+
return requestToBodilessEntity(requestValues);
124+
}
125+
126+
@Override
127+
public <T> Mono<ResponseEntity<T>> exchangeForEntityMono(
128+
HttpRequestValues requestValues, ParameterizedTypeReference<T> bodyType) {
129+
130+
return requestToEntity(requestValues, bodyType);
131+
}
132+
133+
@Override
134+
public <T> Mono<ResponseEntity<Flux<T>>> exchangeForEntityFlux(
135+
HttpRequestValues requestValues, ParameterizedTypeReference<T> bodyType) {
136+
137+
return requestToEntityFlux(requestValues, bodyType);
138+
}
139+
};
140+
}
141+
89142
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*
2+
* Copyright 2002-2023 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.web.service.invoker;
18+
19+
import org.springframework.core.ParameterizedTypeReference;
20+
import org.springframework.http.HttpHeaders;
21+
import org.springframework.http.ResponseEntity;
22+
import org.springframework.lang.Nullable;
23+
24+
/**
25+
* Contract to abstract an underlying HTTP client and decouple it from the
26+
* {@linkplain HttpServiceProxyFactory#createClient(Class) HTTP service proxy}.
27+
*
28+
* @author Rossen Stoyanchev
29+
* @since 6.1
30+
*/
31+
public interface HttpExchangeAdapter {
32+
33+
/**
34+
* Perform the given request, and release the response content, if any.
35+
* @param requestValues the request to perform
36+
*/
37+
void exchange(HttpRequestValues requestValues);
38+
39+
/**
40+
* Perform the given request, release the response content, and return the
41+
* response headers.
42+
* @param requestValues the request to perform
43+
* @return the response headers
44+
*/
45+
HttpHeaders exchangeForHeaders(HttpRequestValues requestValues);
46+
47+
/**
48+
* Perform the given request and decode the response content to the given type.
49+
* @param requestValues the request to perform
50+
* @param bodyType the target type to decode to
51+
* @return the decoded response.
52+
* @param <T> the type the response is decoded to
53+
*/
54+
@Nullable
55+
<T> T exchangeForBody(HttpRequestValues requestValues, ParameterizedTypeReference<T> bodyType);
56+
57+
/**
58+
* Variant of {@link #exchange(HttpRequestValues)} with additional
59+
* access to the response status and headers.
60+
*/
61+
ResponseEntity<Void> exchangeForBodilessEntity(HttpRequestValues requestValues);
62+
63+
/**
64+
* Variant of {@link #exchangeForBody(HttpRequestValues, ParameterizedTypeReference)}
65+
* with additional access to the response status and headers.
66+
*/
67+
<T> ResponseEntity<T> exchangeForEntity(HttpRequestValues requestValues, ParameterizedTypeReference<T> bodyType);
68+
69+
}

0 commit comments

Comments
 (0)