Use ParameterizedTypeReference in public-facing WebFlux APIs
This commit changes the use of `ResolvableType` to `ParameterizedTypeReference` in all public-facing WebFlux APIs. This change removes the necessity for providing the parameterized type information twice: once for creating the `ResolvableType`, and once for specifying a `BodyExtractor`. Issue: SPR-15636
This commit is contained in:
@@ -25,6 +25,7 @@ import org.reactivestreams.Publisher;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
import org.springframework.http.HttpMessage;
|
||||
@@ -68,11 +69,25 @@ public abstract class BodyExtractors {
|
||||
|
||||
/**
|
||||
* Return a {@code BodyExtractor} that reads into a Reactor {@link Mono}.
|
||||
* @param elementType the type of element in the {@code Mono}
|
||||
* The given {@link ParameterizedTypeReference} is used to pass generic type information, for
|
||||
* instance when using the {@link org.springframework.web.reactive.function.client.WebClient WebClient}
|
||||
* <pre class="code">
|
||||
* Mono<Map<String, String>> body = this.webClient
|
||||
* .get()
|
||||
* .uri("http://example.com")
|
||||
* .exchange()
|
||||
* .flatMap(r -> r.body(toMono(new ParameterizedTypeReference<Map<String,String>>() {})));
|
||||
* </pre>
|
||||
* @param typeReference a reference to the type of element in the {@code Mono}
|
||||
* @param <T> the element type
|
||||
* @return a {@code BodyExtractor} that reads a mono
|
||||
*/
|
||||
public static <T> BodyExtractor<Mono<T>, ReactiveHttpInputMessage> toMono(ResolvableType elementType) {
|
||||
public static <T> BodyExtractor<Mono<T>, ReactiveHttpInputMessage> toMono(ParameterizedTypeReference<T> typeReference) {
|
||||
Assert.notNull(typeReference, "'typeReference' must not be null");
|
||||
return toMono(ResolvableType.forType(typeReference.getType()));
|
||||
}
|
||||
|
||||
static <T> BodyExtractor<Mono<T>, ReactiveHttpInputMessage> toMono(ResolvableType elementType) {
|
||||
Assert.notNull(elementType, "'elementType' must not be null");
|
||||
return (inputMessage, context) -> readWithMessageReaders(inputMessage, context,
|
||||
elementType,
|
||||
@@ -93,7 +108,7 @@ public abstract class BodyExtractors {
|
||||
* Return a {@code BodyExtractor} that reads into a Reactor {@link Flux}.
|
||||
* @param elementClass the class of element in the {@code Flux}
|
||||
* @param <T> the element type
|
||||
* @return a {@code BodyExtractor} that reads a mono
|
||||
* @return a {@code BodyExtractor} that reads a flux
|
||||
*/
|
||||
public static <T> BodyExtractor<Flux<T>, ReactiveHttpInputMessage> toFlux(Class<? extends T> elementClass) {
|
||||
Assert.notNull(elementClass, "'elementClass' must not be null");
|
||||
@@ -102,11 +117,25 @@ public abstract class BodyExtractors {
|
||||
|
||||
/**
|
||||
* Return a {@code BodyExtractor} that reads into a Reactor {@link Flux}.
|
||||
* @param elementType the type of element in the {@code Flux}
|
||||
* The given {@link ParameterizedTypeReference} is used to pass generic type information, for
|
||||
* instance when using the {@link org.springframework.web.reactive.function.client.WebClient WebClient}
|
||||
* <pre class="code">
|
||||
* Flux<ServerSentEvent<String>> body = this.webClient
|
||||
* .get()
|
||||
* .uri("http://example.com")
|
||||
* .exchange()
|
||||
* .flatMap(r -> r.body(toFlux(new ParameterizedTypeReference<ServerSentEvent<String>>() {})));
|
||||
* </pre>
|
||||
* @param typeReference a reference to the type of element in the {@code Flux}
|
||||
* @param <T> the element type
|
||||
* @return a {@code BodyExtractor} that reads a mono
|
||||
* @return a {@code BodyExtractor} that reads a flux
|
||||
*/
|
||||
public static <T> BodyExtractor<Flux<T>, ReactiveHttpInputMessage> toFlux(ResolvableType elementType) {
|
||||
public static <T> BodyExtractor<Flux<T>, ReactiveHttpInputMessage> toFlux(ParameterizedTypeReference<T> typeReference) {
|
||||
Assert.notNull(typeReference, "'typeReference' must not be null");
|
||||
return toFlux(ResolvableType.forType(typeReference.getType()));
|
||||
}
|
||||
|
||||
static <T> BodyExtractor<Flux<T>, ReactiveHttpInputMessage> toFlux(ResolvableType elementType) {
|
||||
Assert.notNull(elementType, "'elementType' must not be null");
|
||||
return (inputMessage, context) -> readWithMessageReaders(inputMessage, context,
|
||||
elementType,
|
||||
|
||||
@@ -23,6 +23,7 @@ import java.util.stream.Collectors;
|
||||
import org.reactivestreams.Publisher;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
@@ -100,17 +101,17 @@ public abstract class BodyInserters {
|
||||
/**
|
||||
* Return a {@code BodyInserter} that writes the given {@link Publisher}.
|
||||
* @param publisher the publisher to stream to the response body
|
||||
* @param elementType the type of elements contained in the publisher
|
||||
* @param typeReference the type of elements contained in the publisher
|
||||
* @param <T> the type of the elements contained in the publisher
|
||||
* @param <P> the type of the {@code Publisher}
|
||||
* @return a {@code BodyInserter} that writes a {@code Publisher}
|
||||
*/
|
||||
public static <T, P extends Publisher<T>> BodyInserter<P, ReactiveHttpOutputMessage> fromPublisher(
|
||||
P publisher, ResolvableType elementType) {
|
||||
P publisher, ParameterizedTypeReference<T> typeReference) {
|
||||
|
||||
Assert.notNull(publisher, "'publisher' must not be null");
|
||||
Assert.notNull(elementType, "'elementType' must not be null");
|
||||
return bodyInserterFor(publisher, elementType);
|
||||
Assert.notNull(typeReference, "'typeReference' must not be null");
|
||||
return bodyInserterFor(publisher, ResolvableType.forType(typeReference.getType()));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -197,7 +198,7 @@ public abstract class BodyInserters {
|
||||
* Return a {@code BodyInserter} that writes the given {@code Publisher} publisher as
|
||||
* Server-Sent Events.
|
||||
* @param eventsPublisher the publisher to write to the response body as Server-Sent Events
|
||||
* @param eventType the type of event contained in the publisher
|
||||
* @param typeReference the type of event contained in the publisher
|
||||
* @param <T> the type of the elements contained in the publisher
|
||||
* @return a {@code BodyInserter} that writes the given {@code Publisher} publisher as
|
||||
* Server-Sent Events
|
||||
@@ -207,6 +208,15 @@ public abstract class BodyInserters {
|
||||
// ReactiveHttpOutputMessage like other methods, since sending SSEs only typically happens on
|
||||
// the server-side
|
||||
public static <T, S extends Publisher<T>> BodyInserter<S, ServerHttpResponse> fromServerSentEvents(S eventsPublisher,
|
||||
ParameterizedTypeReference<T> typeReference) {
|
||||
|
||||
Assert.notNull(eventsPublisher, "'eventsPublisher' must not be null");
|
||||
Assert.notNull(typeReference, "'typeReference' must not be null");
|
||||
return fromServerSentEvents(eventsPublisher,
|
||||
ResolvableType.forType(typeReference.getType()));
|
||||
}
|
||||
|
||||
static <T, S extends Publisher<T>> BodyInserter<S, ServerHttpResponse> fromServerSentEvents(S eventsPublisher,
|
||||
ResolvableType eventType) {
|
||||
|
||||
Assert.notNull(eventsPublisher, "'eventsPublisher' must not be null");
|
||||
|
||||
@@ -23,7 +23,7 @@ import java.util.Set;
|
||||
import org.reactivestreams.Publisher;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.http.CacheControl;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
@@ -81,14 +81,14 @@ public interface EntityResponse<T> extends ServerResponse {
|
||||
/**
|
||||
* Create a builder with the given publisher.
|
||||
* @param publisher the publisher that represents the body of the response
|
||||
* @param elementType the type of elements contained in the publisher
|
||||
* @param typeReference the type of elements contained in the publisher
|
||||
* @param <T> the type of the elements contained in the publisher
|
||||
* @param <P> the type of the {@code Publisher}
|
||||
* @return the created builder
|
||||
*/
|
||||
static <T, P extends Publisher<T>> Builder<P> fromPublisher(P publisher, ResolvableType elementType) {
|
||||
static <T, P extends Publisher<T>> Builder<P> fromPublisher(P publisher, ParameterizedTypeReference<T> typeReference) {
|
||||
return new DefaultEntityResponseBuilder<>(publisher,
|
||||
BodyInserters.fromPublisher(publisher, elementType));
|
||||
BodyInserters.fromPublisher(publisher, typeReference));
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user