Skip to content

Commit 805b715

Browse files
committed
Add ParameterizedTypeReference variants to bodyTo[Mono|Flux], toEntity[List]
This commit introduces overloaded variants of `bodytoMono`, `bodyToFlux`, `toEntity`, and `toEntityList` that take a `ParameterizedTypeReference`. It also adds similar methods to `WebClient.ResponseSpec`. Issue: SPR-15725
1 parent 095cc22 commit 805b715

File tree

6 files changed

+301
-6
lines changed

6 files changed

+301
-6
lines changed

spring-webflux/src/main/java/org/springframework/web/reactive/function/client/ClientResponse.java

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import reactor.core.publisher.Flux;
2424
import reactor.core.publisher.Mono;
2525

26+
import org.springframework.core.ParameterizedTypeReference;
2627
import org.springframework.http.HttpHeaders;
2728
import org.springframework.http.HttpStatus;
2829
import org.springframework.http.MediaType;
@@ -75,6 +76,14 @@ public interface ClientResponse {
7576
*/
7677
<T> Mono<T> bodyToMono(Class<? extends T> elementClass);
7778

79+
/**
80+
* Extract the body to a {@code Mono}.
81+
* @param typeReference a type reference describing the expected response body type
82+
* @param <T> the element type
83+
* @return a mono containing the body of the given type {@code T}
84+
*/
85+
<T> Mono<T> bodyToMono(ParameterizedTypeReference<T> typeReference);
86+
7887
/**
7988
* Extract the body to a {@code Flux}.
8089
* @param elementClass the class of element in the {@code Flux}
@@ -83,6 +92,14 @@ public interface ClientResponse {
8392
*/
8493
<T> Flux<T> bodyToFlux(Class<? extends T> elementClass);
8594

95+
/**
96+
* Extract the body to a {@code Flux}.
97+
* @param typeReference a type reference describing the expected response body type
98+
* @param <T> the element type
99+
* @return a flux containing the body of the given type {@code T}
100+
*/
101+
<T> Flux<T> bodyToFlux(ParameterizedTypeReference<T> typeReference);
102+
86103
/**
87104
* Return this response as a delayed {@code ResponseEntity}.
88105
* @param bodyType the expected response body type
@@ -91,6 +108,14 @@ public interface ClientResponse {
91108
*/
92109
<T> Mono<ResponseEntity<T>> toEntity(Class<T> bodyType);
93110

111+
/**
112+
* Return this response as a delayed {@code ResponseEntity}.
113+
* @param typeReference a type reference describing the expected response body type
114+
* @param <T> response body type
115+
* @return {@code Mono} with the {@code ResponseEntity}
116+
*/
117+
<T> Mono<ResponseEntity<T>> toEntity(ParameterizedTypeReference<T> typeReference);
118+
94119
/**
95120
* Return this response as a delayed list of {@code ResponseEntity}s.
96121
* @param elementType the expected response body list element type
@@ -99,6 +124,14 @@ public interface ClientResponse {
99124
*/
100125
<T> Mono<ResponseEntity<List<T>>> toEntityList(Class<T> elementType);
101126

127+
/**
128+
* Return this response as a delayed list of {@code ResponseEntity}s.
129+
* @param typeReference a type reference describing the expected response body type
130+
* @param <T> the type of elements in the list
131+
* @return {@code Mono} with the list of {@code ResponseEntity}s
132+
*/
133+
<T> Mono<ResponseEntity<List<T>>> toEntityList(ParameterizedTypeReference<T> typeReference);
134+
102135

103136
/**
104137
* Represents the headers of the HTTP response.

spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultClientResponse.java

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import reactor.core.publisher.Flux;
2626
import reactor.core.publisher.Mono;
2727

28+
import org.springframework.core.ParameterizedTypeReference;
2829
import org.springframework.http.HttpHeaders;
2930
import org.springframework.http.HttpStatus;
3031
import org.springframework.http.MediaType;
@@ -99,26 +100,55 @@ public <T> Mono<T> bodyToMono(Class<? extends T> elementClass) {
99100
return body(BodyExtractors.toMono(elementClass));
100101
}
101102

103+
@Override
104+
public <T> Mono<T> bodyToMono(ParameterizedTypeReference<T> typeReference) {
105+
return body(BodyExtractors.toMono(typeReference));
106+
}
107+
102108
@Override
103109
public <T> Flux<T> bodyToFlux(Class<? extends T> elementClass) {
104110
return body(BodyExtractors.toFlux(elementClass));
105111
}
106112

113+
@Override
114+
public <T> Flux<T> bodyToFlux(ParameterizedTypeReference<T> typeReference) {
115+
return body(BodyExtractors.toFlux(typeReference));
116+
}
117+
107118
@Override
108119
public <T> Mono<ResponseEntity<T>> toEntity(Class<T> bodyType) {
120+
return toEntityInternal(bodyToMono(bodyType));
121+
}
122+
123+
@Override
124+
public <T> Mono<ResponseEntity<T>> toEntity(ParameterizedTypeReference<T> typeReference) {
125+
return toEntityInternal(bodyToMono(typeReference));
126+
}
127+
128+
private <T> Mono<ResponseEntity<T>> toEntityInternal(Mono<T> bodyMono) {
109129
HttpHeaders headers = headers().asHttpHeaders();
110130
HttpStatus statusCode = statusCode();
111-
return bodyToMono(bodyType)
131+
return bodyMono
112132
.map(body -> new ResponseEntity<>(body, headers, statusCode))
113133
.switchIfEmpty(Mono.defer(
114134
() -> Mono.just(new ResponseEntity<>(headers, statusCode))));
115135
}
116136

117137
@Override
118138
public <T> Mono<ResponseEntity<List<T>>> toEntityList(Class<T> responseType) {
139+
return toEntityListInternal(bodyToFlux(responseType));
140+
}
141+
142+
@Override
143+
public <T> Mono<ResponseEntity<List<T>>> toEntityList(
144+
ParameterizedTypeReference<T> typeReference) {
145+
return toEntityListInternal(bodyToFlux(typeReference));
146+
}
147+
148+
private <T> Mono<ResponseEntity<List<T>>> toEntityListInternal(Flux<T> bodyFlux) {
119149
HttpHeaders headers = headers().asHttpHeaders();
120150
HttpStatus statusCode = statusCode();
121-
return bodyToFlux(responseType)
151+
return bodyFlux
122152
.collectList()
123153
.map(body -> new ResponseEntity<>(body, headers, statusCode));
124154
}

spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultWebClient.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import reactor.core.publisher.Flux;
3636
import reactor.core.publisher.Mono;
3737

38+
import org.springframework.core.ParameterizedTypeReference;
3839
import org.springframework.http.HttpHeaders;
3940
import org.springframework.http.HttpMethod;
4041
import org.springframework.http.HttpStatus;
@@ -422,13 +423,27 @@ public <T> Mono<T> bodyToMono(Class<T> bodyType) {
422423
Mono::error));
423424
}
424425

426+
@Override
427+
public <T> Mono<T> bodyToMono(ParameterizedTypeReference<T> typeReference) {
428+
return this.responseMono.flatMap(
429+
response -> bodyToPublisher(response, BodyExtractors.toMono(typeReference),
430+
Mono::error));
431+
}
432+
425433
@Override
426434
public <T> Flux<T> bodyToFlux(Class<T> elementType) {
427435
return this.responseMono.flatMapMany(
428436
response -> bodyToPublisher(response, BodyExtractors.toFlux(elementType),
429437
Flux::error));
430438
}
431439

440+
@Override
441+
public <T> Flux<T> bodyToFlux(ParameterizedTypeReference<T> typeReference) {
442+
return this.responseMono.flatMapMany(
443+
response -> bodyToPublisher(response, BodyExtractors.toFlux(typeReference),
444+
Flux::error));
445+
}
446+
432447
private <T extends Publisher<?>> T bodyToPublisher(ClientResponse response,
433448
BodyExtractor<T, ? super ClientHttpResponse> extractor,
434449
Function<Throwable, T> errorFunction) {

spring-webflux/src/main/java/org/springframework/web/reactive/function/client/WebClient.java

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import reactor.core.publisher.Flux;
3030
import reactor.core.publisher.Mono;
3131

32+
import org.springframework.core.ParameterizedTypeReference;
3233
import org.springframework.http.HttpHeaders;
3334
import org.springframework.http.HttpMethod;
3435
import org.springframework.http.HttpStatus;
@@ -559,8 +560,9 @@ ResponseSpec onStatus(Predicate<HttpStatus> statusPredicate,
559560
Function<ClientResponse, ? extends Throwable> exceptionFunction);
560561

561562
/**
562-
* Extract the body to a {@code Mono}. If the response has status code 4xx or 5xx, the
563-
* {@code Mono} will contain a {@link WebClientException}.
563+
* Extract the body to a {@code Mono}. By default, if the response has status code 4xx or
564+
* 5xx, the {@code Mono} will contain a {@link WebClientException}. This can be overridden
565+
* with {@link #onStatus(Predicate, Function)}.
564566
* @param bodyType the expected response body type
565567
* @param <T> response body type
566568
* @return a mono containing the body, or a {@link WebClientException} if the status code is
@@ -569,15 +571,38 @@ ResponseSpec onStatus(Predicate<HttpStatus> statusPredicate,
569571
<T> Mono<T> bodyToMono(Class<T> bodyType);
570572

571573
/**
572-
* Extract the body to a {@code Flux}. If the response has status code 4xx or 5xx, the
573-
* {@code Flux} will contain a {@link WebClientException}.
574+
* Extract the body to a {@code Mono}. By default, if the response has status code 4xx or
575+
* 5xx, the {@code Mono} will contain a {@link WebClientException}. This can be overridden
576+
* with {@link #onStatus(Predicate, Function)}.
577+
* @param typeReference a type reference describing the expected response body type
578+
* @param <T> response body type
579+
* @return a mono containing the body, or a {@link WebClientException} if the status code is
580+
* 4xx or 5xx
581+
*/
582+
<T> Mono<T> bodyToMono(ParameterizedTypeReference<T> typeReference);
583+
584+
/**
585+
* Extract the body to a {@code Flux}. By default, if the response has status code 4xx or
586+
* 5xx, the {@code Flux} will contain a {@link WebClientException}. This can be overridden
587+
* with {@link #onStatus(Predicate, Function)}.
574588
* @param elementType the type of element in the response
575589
* @param <T> the type of elements in the response
576590
* @return a flux containing the body, or a {@link WebClientException} if the status code is
577591
* 4xx or 5xx
578592
*/
579593
<T> Flux<T> bodyToFlux(Class<T> elementType);
580594

595+
/**
596+
* Extract the body to a {@code Flux}. By default, if the response has status code 4xx or
597+
* 5xx, the {@code Flux} will contain a {@link WebClientException}. This can be overridden
598+
* with {@link #onStatus(Predicate, Function)}.
599+
* @param typeReference a type reference describing the expected response body type
600+
* @param <T> the type of elements in the response
601+
* @return a flux containing the body, or a {@link WebClientException} if the status code is
602+
* 4xx or 5xx
603+
*/
604+
<T> Flux<T> bodyToFlux(ParameterizedTypeReference<T> typeReference);
605+
581606
}
582607

583608

0 commit comments

Comments
 (0)