Allow HandlerFunction to return Mono<ServerResponse>

This commit makes it possible for handler functions to return
asynchronous status codes and headers, by making HandlerFunction.handle
return a Mono<ServerResponse> instead of a ServerResponse. As a
consequence, all other types that deal with HandlerFunctions
(RouterFunction, HandlerFilterFunction, etc.) had to change as well.

However, when combining the above change with method references (a very
typical use case), resulting signatures would have been something like:

```
public Mono<ServerResponse<Mono<Person>>> getPerson(ServerRequest request)
```

which was too ugly to consider, especially the two uses of Mono. It was
considered to merge ServerResponse with the last Mono, essentialy making
ServerResponse always contain a Publisher, but this had unfortunate
consequences in view rendering.

It was therefore decided to drop the parameterization of ServerResponse,
as the only usage of the extra type information was to manipulate the
response objects in a filter. Even before the above change this was
suggested; it just made the change even more necessary.

As a consequence, `BodyInserter` could be turned into a real
`FunctionalInterface`, which resulted in changes in ClientRequest.

We did, however, make HandlerFunction.handle return a `Mono<? extends
ServerResponse>`, adding little complexity, but allowing for
future `ServerResponse` subtypes that do expose type information, if
it's needed. For instance, a RenderingResponse could expose the view
name and model.

Issue: SPR-14870
This commit is contained in:
Arjen Poutsma
2016-12-07 09:34:57 +01:00
parent 4021d239ab
commit 582e625fcf
27 changed files with 570 additions and 525 deletions

View File

@@ -46,7 +46,6 @@ import org.springframework.mock.http.server.reactive.test.MockServerHttpResponse
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
/**
* @author Arjen Poutsma
@@ -83,8 +82,6 @@ public class BodyInsertersTests {
String body = "foo";
BodyInserter<String, ReactiveHttpOutputMessage> inserter = BodyInserters.fromObject(body);
assertEquals(body, inserter.t());
MockServerHttpResponse response = new MockServerHttpResponse();
Mono<Void> result = inserter.insert(response, this.context);
StepVerifier.create(result).expectComplete().verify();
@@ -102,8 +99,6 @@ public class BodyInsertersTests {
Flux<String> body = Flux.just("foo");
BodyInserter<Flux<String>, ReactiveHttpOutputMessage> inserter = BodyInserters.fromPublisher(body, String.class);
assertEquals(body, inserter.t());
MockServerHttpResponse response = new MockServerHttpResponse();
Mono<Void> result = inserter.insert(response, this.context);
StepVerifier.create(result).expectComplete().verify();
@@ -121,8 +116,6 @@ public class BodyInsertersTests {
Resource body = new ClassPathResource("response.txt", getClass());
BodyInserter<Resource, ReactiveHttpOutputMessage> inserter = BodyInserters.fromResource(body);
assertEquals(body, inserter.t());
MockServerHttpResponse response = new MockServerHttpResponse();
Mono<Void> result = inserter.insert(response, this.context);
StepVerifier.create(result).expectComplete().verify();
@@ -146,8 +139,6 @@ public class BodyInsertersTests {
BodyInserter<Flux<ServerSentEvent<String>>, ServerHttpResponse> inserter =
BodyInserters.fromServerSentEvents(body);
assertEquals(body, inserter.t());
MockServerHttpResponse response = new MockServerHttpResponse();
Mono<Void> result = inserter.insert(response, this.context);
StepVerifier.create(result).expectNextCount(0).expectComplete().verify();
@@ -159,8 +150,6 @@ public class BodyInsertersTests {
BodyInserter<Flux<String>, ServerHttpResponse> inserter =
BodyInserters.fromServerSentEvents(body, String.class);
assertEquals(body, inserter.t());
MockServerHttpResponse response = new MockServerHttpResponse();
Mono<Void> result = inserter.insert(response, this.context);
StepVerifier.create(result).expectNextCount(0).expectComplete().verify();
@@ -175,8 +164,6 @@ public class BodyInsertersTests {
BodyInserter<Flux<DataBuffer>, ReactiveHttpOutputMessage> inserter = BodyInserters.fromDataBuffers(body);
assertEquals(body, inserter.t());
MockServerHttpResponse response = new MockServerHttpResponse();
Mono<Void> result = inserter.insert(response, this.context);
StepVerifier.create(result).expectComplete().verify();

View File

@@ -24,8 +24,6 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.function.BiFunction;
import java.util.function.Supplier;
import org.junit.Test;
import reactor.core.publisher.Mono;
@@ -186,8 +184,7 @@ public class DefaultClientRequestBuilderTests {
@Test
public void bodyInserter() throws Exception {
String body = "foo";
Supplier<String> supplier = () -> body;
BiFunction<ClientHttpRequest, BodyInserter.Context, Mono<Void>> writer =
BodyInserter<String, ClientHttpRequest> inserter =
(response, strategies) -> {
byte[] bodyBytes = body.getBytes(UTF_8);
ByteBuffer byteBuffer = ByteBuffer.wrap(bodyBytes);
@@ -197,8 +194,7 @@ public class DefaultClientRequestBuilderTests {
};
ClientRequest<String> result = ClientRequest.POST("http://example.com")
.body(BodyInserter.of(writer, supplier));
assertEquals(body, result.body());
.body(inserter);
MockClientHttpRequest request = new MockClientHttpRequest();