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:
Arjen Poutsma
2017-06-07 17:29:56 +02:00
parent b6c09fa76a
commit 5e954dcba0
10 changed files with 119 additions and 58 deletions

View File

@@ -21,6 +21,7 @@ import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@@ -32,6 +33,7 @@ import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.core.codec.ByteBufferDecoder;
import org.springframework.core.codec.StringDecoder;
import org.springframework.core.io.buffer.DataBuffer;
@@ -120,6 +122,28 @@ public class BodyExtractorsTests {
.verify();
}
@Test
public void toMonoParameterizedTypeReference() throws Exception {
ParameterizedTypeReference<Map<String, String>> typeReference = new ParameterizedTypeReference<Map<String, String>>() {};
BodyExtractor<Mono<Map<String, String>>, ReactiveHttpInputMessage> extractor = BodyExtractors.toMono(typeReference);
DefaultDataBufferFactory factory = new DefaultDataBufferFactory();
DefaultDataBuffer dataBuffer =
factory.wrap(ByteBuffer.wrap("{\"username\":\"foo\",\"password\":\"bar\"}".getBytes(StandardCharsets.UTF_8)));
Flux<DataBuffer> body = Flux.just(dataBuffer);
MockServerHttpRequest request = MockServerHttpRequest.post("/").contentType(MediaType.APPLICATION_JSON).body(body);
Mono<Map<String, String>> result = extractor.extract(request, this.context);
Map<String, String > expected = new LinkedHashMap<>();
expected.put("username", "foo");
expected.put("password", "bar");
StepVerifier.create(result)
.expectNext(expected)
.expectComplete()
.verify();
}
@Test
public void toMonoWithHints() throws Exception {
BodyExtractor<Mono<User>, ReactiveHttpInputMessage> extractor = BodyExtractors.toMono(User.class);

View File

@@ -30,7 +30,7 @@ import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
import org.springframework.core.ResolvableType;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.core.codec.CharSequenceEncoder;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
@@ -70,10 +70,10 @@ public class DefaultEntityResponseBuilderTests {
}
@Test
public void fromPublisherResolvableType() throws Exception {
public void fromPublisher() throws Exception {
Flux<String> body = Flux.just("foo", "bar");
ResolvableType type = ResolvableType.forClass(String.class);
EntityResponse<Flux<String>> response = EntityResponse.fromPublisher(body, type).build().block();
ParameterizedTypeReference<String> typeReference = new ParameterizedTypeReference<String>() {};
EntityResponse<Flux<String>> response = EntityResponse.fromPublisher(body, typeReference).build().block();
assertSame(body, response.entity());
}

View File

@@ -24,15 +24,15 @@ import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.codec.ServerSentEvent;
import org.springframework.web.reactive.function.client.WebClient;
import static org.junit.Assert.*;
import static org.springframework.core.ResolvableType.*;
import static org.springframework.http.MediaType.*;
import static org.springframework.web.reactive.function.BodyExtractors.*;
import static org.springframework.web.reactive.function.BodyInserters.*;
import static org.springframework.web.reactive.function.server.RouterFunctions.*;
import static org.springframework.http.MediaType.TEXT_EVENT_STREAM;
import static org.springframework.web.reactive.function.BodyExtractors.toFlux;
import static org.springframework.web.reactive.function.BodyInserters.fromServerSentEvents;
import static org.springframework.web.reactive.function.server.RouterFunctions.route;
/**
* @author Arjen Poutsma
@@ -94,7 +94,7 @@ public class SseHandlerFunctionIntegrationTests extends AbstractRouterFunctionIn
.accept(TEXT_EVENT_STREAM)
.exchange()
.flatMapMany(response -> response.body(toFlux(
forClassWithGenerics(ServerSentEvent.class, String.class))));
new ParameterizedTypeReference<ServerSentEvent<String>>() {})));
StepVerifier.create(result)
.consumeNextWith( event -> {

View File

@@ -26,6 +26,7 @@ import reactor.test.StepVerifier;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.core.ResolvableType;
import org.springframework.http.codec.ServerSentEvent;
import org.springframework.http.server.reactive.AbstractHttpHandlerIntegrationTests;
@@ -38,9 +39,9 @@ import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.server.adapter.WebHttpHandlerBuilder;
import static org.junit.Assert.*;
import static org.springframework.core.ResolvableType.*;
import static org.springframework.http.MediaType.*;
import static org.springframework.web.reactive.function.BodyExtractors.*;
import static org.springframework.core.ResolvableType.forClassWithGenerics;
import static org.springframework.http.MediaType.TEXT_EVENT_STREAM;
import static org.springframework.web.reactive.function.BodyExtractors.toFlux;
/**
* @author Sebastien Deleuze
@@ -106,7 +107,7 @@ public class SseIntegrationTests extends AbstractHttpHandlerIntegrationTests {
.uri("/event")
.accept(TEXT_EVENT_STREAM)
.exchange()
.flatMapMany(response -> response.body(toFlux(type)));
.flatMapMany(response -> response.body(toFlux(new ParameterizedTypeReference<ServerSentEvent<String>>() {})));
StepVerifier.create(result)
.consumeNextWith( event -> {
@@ -133,8 +134,7 @@ public class SseIntegrationTests extends AbstractHttpHandlerIntegrationTests {
.uri("/event")
.accept(TEXT_EVENT_STREAM)
.exchange()
.flatMapMany(response -> response.body(toFlux(
forClassWithGenerics(ServerSentEvent.class, String.class))));
.flatMapMany(response -> response.body(toFlux(new ParameterizedTypeReference<ServerSentEvent<String>>() {})));
StepVerifier.create(result)
.consumeNextWith( event -> {