Add Mono and Flux support in @RequestMapping handler methods
This commit is contained in:
parent
1faeb0ec87
commit
ae4b35ced7
|
@ -76,7 +76,14 @@ public class RequestBodyArgumentResolver implements HandlerMethodArgumentResolve
|
||||||
if (this.conversionService.canConvert(Publisher.class, type.getRawClass())) {
|
if (this.conversionService.canConvert(Publisher.class, type.getRawClass())) {
|
||||||
return Mono.just(this.conversionService.convert(elementFlux, type.getRawClass()));
|
return Mono.just(this.conversionService.convert(elementFlux, type.getRawClass()));
|
||||||
}
|
}
|
||||||
|
else if (type.getRawClass() == Flux.class) {
|
||||||
|
return Mono.just(elementFlux);
|
||||||
|
}
|
||||||
|
else if (type.getRawClass() == Mono.class) {
|
||||||
|
return Mono.just(Mono.from(elementFlux));
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO Currently manage only "Foo" parameter, not "List<Foo>" parameters, Stéphane is going to add toIterable/toIterator to Flux to support that use case
|
||||||
return elementFlux.next().map(o -> o);
|
return elementFlux.next().map(o -> o);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.reactivestreams.Publisher;
|
import org.reactivestreams.Publisher;
|
||||||
|
import reactor.Flux;
|
||||||
import reactor.Mono;
|
import reactor.Mono;
|
||||||
import reactor.io.buffer.Buffer;
|
import reactor.io.buffer.Buffer;
|
||||||
import reactor.rx.Promise;
|
import reactor.rx.Promise;
|
||||||
|
@ -61,7 +62,6 @@ import org.springframework.web.bind.annotation.ResponseBody;
|
||||||
import org.springframework.web.client.RestTemplate;
|
import org.springframework.web.client.RestTemplate;
|
||||||
import org.springframework.web.reactive.DispatcherHandler;
|
import org.springframework.web.reactive.DispatcherHandler;
|
||||||
import org.springframework.web.reactive.handler.SimpleHandlerResultHandler;
|
import org.springframework.web.reactive.handler.SimpleHandlerResultHandler;
|
||||||
import org.springframework.web.server.WebToHttpHandlerAdapter;
|
|
||||||
import org.springframework.web.server.WebToHttpHandlerBuilder;
|
import org.springframework.web.server.WebToHttpHandlerBuilder;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
@ -113,7 +113,19 @@ public class RequestMappingIntegrationTests extends AbstractHttpHandlerIntegrati
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void rawHelloResponse() throws Exception {
|
public void rawFluxResponse() throws Exception {
|
||||||
|
|
||||||
|
RestTemplate restTemplate = new RestTemplate();
|
||||||
|
|
||||||
|
URI url = new URI("http://localhost:" + port + "/raw-flux");
|
||||||
|
RequestEntity<Void> request = RequestEntity.get(url).build();
|
||||||
|
ResponseEntity<String> response = restTemplate.exchange(request, String.class);
|
||||||
|
|
||||||
|
assertEquals("Hello!", response.getBody());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void rawObservableResponse() throws Exception {
|
||||||
|
|
||||||
RestTemplate restTemplate = new RestTemplate();
|
RestTemplate restTemplate = new RestTemplate();
|
||||||
|
|
||||||
|
@ -158,6 +170,11 @@ public class RequestMappingIntegrationTests extends AbstractHttpHandlerIntegrati
|
||||||
serializeAsPojo("http://localhost:" + port + "/completable-future");
|
serializeAsPojo("http://localhost:" + port + "/completable-future");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void serializeAsMono() throws Exception {
|
||||||
|
serializeAsPojo("http://localhost:" + port + "/mono");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void serializeAsSingle() throws Exception {
|
public void serializeAsSingle() throws Exception {
|
||||||
serializeAsPojo("http://localhost:" + port + "/single");
|
serializeAsPojo("http://localhost:" + port + "/single");
|
||||||
|
@ -178,6 +195,11 @@ public class RequestMappingIntegrationTests extends AbstractHttpHandlerIntegrati
|
||||||
serializeAsCollection("http://localhost:" + port + "/publisher");
|
serializeAsCollection("http://localhost:" + port + "/publisher");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void serializeAsFlux() throws Exception {
|
||||||
|
serializeAsCollection("http://localhost:" + port + "/flux");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void serializeAsObservable() throws Exception {
|
public void serializeAsObservable() throws Exception {
|
||||||
serializeAsCollection("http://localhost:" + port + "/observable");
|
serializeAsCollection("http://localhost:" + port + "/observable");
|
||||||
|
@ -193,6 +215,11 @@ public class RequestMappingIntegrationTests extends AbstractHttpHandlerIntegrati
|
||||||
capitalizeCollection("http://localhost:" + port + "/publisher-capitalize");
|
capitalizeCollection("http://localhost:" + port + "/publisher-capitalize");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void fluxCapitalize() throws Exception {
|
||||||
|
capitalizeCollection("http://localhost:" + port + "/flux-capitalize");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void observableCapitalize() throws Exception {
|
public void observableCapitalize() throws Exception {
|
||||||
capitalizeCollection("http://localhost:" + port + "/observable-capitalize");
|
capitalizeCollection("http://localhost:" + port + "/observable-capitalize");
|
||||||
|
@ -213,6 +240,11 @@ public class RequestMappingIntegrationTests extends AbstractHttpHandlerIntegrati
|
||||||
capitalizePojo("http://localhost:" + port + "/completable-future-capitalize");
|
capitalizePojo("http://localhost:" + port + "/completable-future-capitalize");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void monoCapitalize() throws Exception {
|
||||||
|
capitalizePojo("http://localhost:" + port + "/mono-capitalize");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void singleCapitalize() throws Exception {
|
public void singleCapitalize() throws Exception {
|
||||||
capitalizePojo("http://localhost:" + port + "/single-capitalize");
|
capitalizePojo("http://localhost:" + port + "/single-capitalize");
|
||||||
|
@ -228,6 +260,11 @@ public class RequestMappingIntegrationTests extends AbstractHttpHandlerIntegrati
|
||||||
create("http://localhost:" + this.port + "/publisher-create");
|
create("http://localhost:" + this.port + "/publisher-create");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void fluxCreate() throws Exception {
|
||||||
|
create("http://localhost:" + this.port + "/flux-create");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void streamCreate() throws Exception {
|
public void streamCreate() throws Exception {
|
||||||
create("http://localhost:" + this.port + "/stream-create");
|
create("http://localhost:" + this.port + "/stream-create");
|
||||||
|
@ -384,12 +421,24 @@ public class RequestMappingIntegrationTests extends AbstractHttpHandlerIntegrati
|
||||||
ResolvableType.forClass(Person.class), MediaType.APPLICATION_JSON);
|
ResolvableType.forClass(Person.class), MediaType.APPLICATION_JSON);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@RequestMapping("/raw-flux")
|
||||||
|
@ResponseBody
|
||||||
|
public Flux<ByteBuffer> rawFluxResponseBody() {
|
||||||
|
return Flux.just(Buffer.wrap("Hello!").byteBuffer());
|
||||||
|
}
|
||||||
|
|
||||||
@RequestMapping("/raw-observable")
|
@RequestMapping("/raw-observable")
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
public Observable<ByteBuffer> rawObservableResponseBody() {
|
public Observable<ByteBuffer> rawObservableResponseBody() {
|
||||||
return Observable.just(Buffer.wrap("Hello!").byteBuffer());
|
return Observable.just(Buffer.wrap("Hello!").byteBuffer());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@RequestMapping("/mono")
|
||||||
|
@ResponseBody
|
||||||
|
public Mono<Person> monoResponseBody() {
|
||||||
|
return Mono.just(new Person("Robert"));
|
||||||
|
}
|
||||||
|
|
||||||
@RequestMapping("/single")
|
@RequestMapping("/single")
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
public Single<Person> singleResponseBody() {
|
public Single<Person> singleResponseBody() {
|
||||||
|
@ -414,6 +463,12 @@ public class RequestMappingIntegrationTests extends AbstractHttpHandlerIntegrati
|
||||||
return Stream.just(new Person("Robert"), new Person("Marie"));
|
return Stream.just(new Person("Robert"), new Person("Marie"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@RequestMapping("/flux")
|
||||||
|
@ResponseBody
|
||||||
|
public Flux<Person> fluxResponseBody() {
|
||||||
|
return Flux.just(new Person("Robert"), new Person("Marie"));
|
||||||
|
}
|
||||||
|
|
||||||
@RequestMapping("/observable")
|
@RequestMapping("/observable")
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
public Observable<Person> observableResponseBody() {
|
public Observable<Person> observableResponseBody() {
|
||||||
|
@ -435,6 +490,15 @@ public class RequestMappingIntegrationTests extends AbstractHttpHandlerIntegrati
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@RequestMapping("/flux-capitalize")
|
||||||
|
@ResponseBody
|
||||||
|
public Flux<Person> fluxCapitalize(@RequestBody Flux<Person> persons) {
|
||||||
|
return persons.map(person -> {
|
||||||
|
person.setName(person.getName().toUpperCase());
|
||||||
|
return person;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@RequestMapping("/observable-capitalize")
|
@RequestMapping("/observable-capitalize")
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
public Observable<Person> observableCapitalize(@RequestBody Observable<Person> persons) {
|
public Observable<Person> observableCapitalize(@RequestBody Observable<Person> persons) {
|
||||||
|
@ -471,6 +535,15 @@ public class RequestMappingIntegrationTests extends AbstractHttpHandlerIntegrati
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@RequestMapping("/mono-capitalize")
|
||||||
|
@ResponseBody
|
||||||
|
public Mono<Person> monoCapitalize(@RequestBody Mono<Person> personFuture) {
|
||||||
|
return personFuture.map(person -> {
|
||||||
|
person.setName(person.getName().toUpperCase());
|
||||||
|
return person;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@RequestMapping("/single-capitalize")
|
@RequestMapping("/single-capitalize")
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
public Single<Person> singleCapitalize(@RequestBody Single<Person> personFuture) {
|
public Single<Person> singleCapitalize(@RequestBody Single<Person> personFuture) {
|
||||||
|
@ -491,12 +564,17 @@ public class RequestMappingIntegrationTests extends AbstractHttpHandlerIntegrati
|
||||||
|
|
||||||
@RequestMapping("/publisher-create")
|
@RequestMapping("/publisher-create")
|
||||||
public Publisher<Void> publisherCreate(@RequestBody Publisher<Person> personStream) {
|
public Publisher<Void> publisherCreate(@RequestBody Publisher<Person> personStream) {
|
||||||
return Stream.from(personStream).toList().doOnSuccess(persons::addAll).after();
|
return Flux.from(personStream).doOnNext(persons::add).after();
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequestMapping("/flux-create")
|
||||||
|
public Mono<Void> fluxCreate(@RequestBody Flux<Person> personStream) {
|
||||||
|
return personStream.doOnNext(persons::add).after();
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping("/stream-create")
|
@RequestMapping("/stream-create")
|
||||||
public Publisher<Void> streamCreate(@RequestBody Stream<Person> personStream) {
|
public Publisher<Void> streamCreate(@RequestBody Stream<Person> personStream) {
|
||||||
return Stream.from(personStream.toList().doOnSuccess(persons::addAll).after()).promise();
|
return personStream.toList().doOnSuccess(persons::addAll).after();
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping("/observable-create")
|
@RequestMapping("/observable-create")
|
||||||
|
@ -519,7 +597,7 @@ public class RequestMappingIntegrationTests extends AbstractHttpHandlerIntegrati
|
||||||
@ExceptionHandler
|
@ExceptionHandler
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
public Publisher<String> handleException(IllegalStateException ex) {
|
public Publisher<String> handleException(IllegalStateException ex) {
|
||||||
return Stream.just("Recovered from error: " + ex.getMessage());
|
return Mono.just("Recovered from error: " + ex.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO add mixed and T request mappings tests
|
//TODO add mixed and T request mappings tests
|
||||||
|
@ -562,6 +640,13 @@ public class RequestMappingIntegrationTests extends AbstractHttpHandlerIntegrati
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return this.name != null ? this.name.hashCode() : 0;
|
return this.name != null ? this.name.hashCode() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Person{" +
|
||||||
|
"name='" + name + '\'' +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue