Add support for rx.Completable as return value
This commit is contained in:
parent
79bc227c9d
commit
143b5c89dd
|
|
@ -97,7 +97,9 @@ public abstract class AbstractMessageWriterResultHandler extends ContentNegotiat
|
|||
ResolvableType elementType;
|
||||
if (adapter != null) {
|
||||
publisher = adapter.toPublisher(body);
|
||||
elementType = ResolvableType.forMethodParameter(bodyType).getGeneric(0);
|
||||
elementType = adapter.getDescriptor().isNoValue() ?
|
||||
ResolvableType.forClass(Void.class) :
|
||||
ResolvableType.forMethodParameter(bodyType).getGeneric(0);
|
||||
}
|
||||
else {
|
||||
publisher = Mono.justOrEmpty(body);
|
||||
|
|
|
|||
|
|
@ -17,10 +17,12 @@
|
|||
package org.springframework.web.reactive.result.method.annotation;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.ReactiveAdapter;
|
||||
import org.springframework.core.ReactiveAdapterRegistry;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
|
|
@ -101,7 +103,9 @@ public class ResponseBodyResultHandler extends AbstractMessageWriterResultHandle
|
|||
return true;
|
||||
}
|
||||
else {
|
||||
if (getReactiveAdapterRegistry().getAdapterFrom(rawClass, result.getReturnValue()) != null) {
|
||||
Optional<Object> optional = result.getReturnValue();
|
||||
ReactiveAdapter adapter = getReactiveAdapterRegistry().getAdapterFrom(rawClass, optional);
|
||||
if (adapter != null && !adapter.getDescriptor().isNoValue()) {
|
||||
ResolvableType genericType = result.getReturnType().getGeneric(0);
|
||||
if (HttpEntity.class.isAssignableFrom(genericType.getRawClass())) {
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -85,9 +85,12 @@ public class ResponseEntityResultHandler extends AbstractMessageWriterResultHand
|
|||
return true;
|
||||
}
|
||||
else {
|
||||
Optional<Object> returnValue = result.getReturnValue();
|
||||
ReactiveAdapter adapter = getReactiveAdapterRegistry().getAdapterFrom(returnType, returnValue);
|
||||
if (adapter != null && !adapter.getDescriptor().isMultiValue()) {
|
||||
Optional<Object> optional = result.getReturnValue();
|
||||
ReactiveAdapter adapter = getReactiveAdapterRegistry().getAdapterFrom(returnType, optional);
|
||||
if (adapter != null &&
|
||||
!adapter.getDescriptor().isMultiValue() &&
|
||||
!adapter.getDescriptor().isNoValue()) {
|
||||
|
||||
ResolvableType genericType = result.getReturnType().getGeneric(0);
|
||||
return isSupportedType(genericType.getRawClass());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -142,12 +142,19 @@ public class ViewResolutionResultHandler extends ContentNegotiatingResultHandler
|
|||
if (hasModelAttributeAnnotation(result)) {
|
||||
return true;
|
||||
}
|
||||
if (isSupportedType(clazz)) {
|
||||
return true;
|
||||
Optional<Object> optional = result.getReturnValue();
|
||||
ReactiveAdapter adapter = getReactiveAdapterRegistry().getAdapterFrom(clazz, optional);
|
||||
if (adapter != null) {
|
||||
if (adapter.getDescriptor().isNoValue()) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
clazz = result.getReturnType().getGeneric(0).getRawClass();
|
||||
return isSupportedType(clazz);
|
||||
}
|
||||
}
|
||||
if (getReactiveAdapterRegistry().getAdapterFrom(clazz, result.getReturnValue()) != null) {
|
||||
clazz = result.getReturnType().getGeneric(0).getRawClass();
|
||||
return isSupportedType(clazz);
|
||||
else if (isSupportedType(clazz)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
@ -181,7 +188,8 @@ public class ViewResolutionResultHandler extends ContentNegotiatingResultHandler
|
|||
else {
|
||||
valueMono = Mono.empty();
|
||||
}
|
||||
elementType = returnType.getGeneric(0);
|
||||
elementType = adapter.getDescriptor().isNoValue() ?
|
||||
ResolvableType.forClass(Void.class) : returnType.getGeneric(0);
|
||||
}
|
||||
else {
|
||||
valueMono = Mono.justOrEmpty(result.getReturnValue());
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ import org.junit.Test;
|
|||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.TestSubscriber;
|
||||
import rx.Completable;
|
||||
import rx.Observable;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
|
|
@ -110,6 +111,7 @@ public class MessageWriterResultHandlerTests {
|
|||
public void voidReturnType() throws Exception {
|
||||
testVoidReturnType(null, ResolvableType.forType(void.class));
|
||||
testVoidReturnType(Mono.empty(), ResolvableType.forClassWithGenerics(Mono.class, Void.class));
|
||||
testVoidReturnType(Completable.complete(), ResolvableType.forClass(Completable.class));
|
||||
testVoidReturnType(Flux.empty(), ResolvableType.forClassWithGenerics(Flux.class, Void.class));
|
||||
testVoidReturnType(Observable.empty(), ResolvableType.forClassWithGenerics(Observable.class, Void.class));
|
||||
}
|
||||
|
|
@ -269,6 +271,8 @@ public class MessageWriterResultHandlerTests {
|
|||
|
||||
Mono<Void> monoVoid() { return null; }
|
||||
|
||||
Completable completable() { return null; }
|
||||
|
||||
Flux<Void> fluxVoid() { return null; }
|
||||
|
||||
Observable<Void> observableVoid() { return null; }
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ import org.junit.Test;
|
|||
import org.reactivestreams.Publisher;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import rx.Completable;
|
||||
import rx.Observable;
|
||||
import rx.Single;
|
||||
|
||||
|
|
@ -54,9 +55,10 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
|||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.reactive.config.WebReactiveConfiguration;
|
||||
|
||||
import static java.util.Arrays.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.springframework.http.MediaType.*;
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.springframework.http.MediaType.APPLICATION_XML;
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -233,6 +235,24 @@ public class RequestMappingMessageConversionIntegrationTests extends AbstractReq
|
|||
assertEquals(2, getApplicationContext().getBean(PersonCreateController.class).persons.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void personCreateWithMono() throws Exception {
|
||||
ResponseEntity<Void> entity = performPost(
|
||||
"/person-create/mono", JSON, new Person("Robert"), null, Void.class);
|
||||
|
||||
assertEquals(HttpStatus.OK, entity.getStatusCode());
|
||||
assertEquals(1, getApplicationContext().getBean(PersonCreateController.class).persons.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void personCreateWithSingle() throws Exception {
|
||||
ResponseEntity<Void> entity = performPost(
|
||||
"/person-create/single", JSON, new Person("Robert"), null, Void.class);
|
||||
|
||||
assertEquals(HttpStatus.OK, entity.getStatusCode());
|
||||
assertEquals(1, getApplicationContext().getBean(PersonCreateController.class).persons.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void personCreateWithFluxJson() throws Exception {
|
||||
ResponseEntity<Void> entity = performPost("/person-create/flux", JSON,
|
||||
|
|
@ -415,18 +435,28 @@ public class RequestMappingMessageConversionIntegrationTests extends AbstractReq
|
|||
final List<Person> persons = new ArrayList<>();
|
||||
|
||||
@PostMapping("/publisher")
|
||||
public Publisher<Void> createWithPublisher(@RequestBody Publisher<Person> personStream) {
|
||||
return Flux.from(personStream).doOnNext(persons::add).then();
|
||||
public Publisher<Void> createWithPublisher(@RequestBody Publisher<Person> publisher) {
|
||||
return Flux.from(publisher).doOnNext(persons::add).then();
|
||||
}
|
||||
|
||||
@PostMapping("/mono")
|
||||
public Mono<Void> createWithMono(@RequestBody Mono<Person> mono) {
|
||||
return mono.doOnNext(persons::add).then();
|
||||
}
|
||||
|
||||
@PostMapping("/single")
|
||||
public Completable createWithSingle(@RequestBody Single<Person> single) {
|
||||
return single.map(persons::add).toCompletable();
|
||||
}
|
||||
|
||||
@PostMapping("/flux")
|
||||
public Mono<Void> createWithFlux(@RequestBody Flux<Person> personStream) {
|
||||
return personStream.doOnNext(persons::add).then();
|
||||
public Mono<Void> createWithFlux(@RequestBody Flux<Person> flux) {
|
||||
return flux.doOnNext(persons::add).then();
|
||||
}
|
||||
|
||||
@PostMapping("/observable")
|
||||
public Observable<Void> createWithObservable(@RequestBody Observable<Person> personStream) {
|
||||
return personStream.toList().doOnNext(persons::addAll).flatMap(document -> Observable.empty());
|
||||
public Observable<Void> createWithObservable(@RequestBody Observable<Person> observable) {
|
||||
return observable.toList().doOnNext(persons::addAll).flatMap(document -> Observable.empty());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@ import java.util.List;
|
|||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import reactor.core.publisher.Mono;
|
||||
import rx.Completable;
|
||||
import rx.Single;
|
||||
|
||||
import org.springframework.core.codec.ByteBufferEncoder;
|
||||
import org.springframework.core.codec.CharSequenceEncoder;
|
||||
|
|
@ -50,7 +52,7 @@ import org.springframework.web.server.ServerWebExchange;
|
|||
import org.springframework.web.server.adapter.DefaultServerWebExchange;
|
||||
import org.springframework.web.server.session.MockWebSessionManager;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -106,6 +108,9 @@ public class ResponseBodyResultHandlerTests {
|
|||
|
||||
controller = new TestRestController();
|
||||
testSupports(controller, "handleToString", true);
|
||||
testSupports(controller, "handleToMonoString", true);
|
||||
testSupports(controller, "handleToSingleString", true);
|
||||
testSupports(controller, "handleToCompletable", true);
|
||||
testSupports(controller, "handleToResponseEntity", false);
|
||||
testSupports(controller, "handleToMonoResponseEntity", false);
|
||||
}
|
||||
|
|
@ -134,6 +139,18 @@ public class ResponseBodyResultHandlerTests {
|
|||
return null;
|
||||
}
|
||||
|
||||
public Mono<String> handleToMonoString() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Single<String> handleToSingleString() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Completable handleToCompletable() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public ResponseEntity<String> handleToResponseEntity() {
|
||||
return null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ import org.junit.Before;
|
|||
import org.junit.Test;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.TestSubscriber;
|
||||
import rx.Completable;
|
||||
import rx.Single;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
|
|
@ -117,8 +118,13 @@ public class ResponseEntityResultHandlerTests {
|
|||
type = forClassWithGenerics(CompletableFuture.class, responseEntity(String.class));
|
||||
assertTrue(this.resultHandler.supports(handlerResult(value, type)));
|
||||
|
||||
// False
|
||||
|
||||
type = ResolvableType.forClass(String.class);
|
||||
assertFalse(this.resultHandler.supports(handlerResult(value, type)));
|
||||
|
||||
type = ResolvableType.forClass(Completable.class);
|
||||
assertFalse(this.resultHandler.supports(handlerResult(value, type)));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -212,6 +218,8 @@ public class ResponseEntityResultHandlerTests {
|
|||
CompletableFuture<ResponseEntity<String>> completableFuture() { return null; }
|
||||
|
||||
String string() { return null; }
|
||||
|
||||
Completable completable() { return null; }
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ import org.junit.Test;
|
|||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.TestSubscriber;
|
||||
import rx.Completable;
|
||||
import rx.Single;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
|
|
@ -98,6 +99,8 @@ public class ViewResolutionResultHandlerTests {
|
|||
testSupports(ResolvableType.forClassWithGenerics(Mono.class, View.class), true);
|
||||
testSupports(ResolvableType.forClassWithGenerics(Single.class, String.class), true);
|
||||
testSupports(ResolvableType.forClassWithGenerics(Single.class, View.class), true);
|
||||
testSupports(ResolvableType.forClassWithGenerics(Mono.class, Void.class), true);
|
||||
testSupports(ResolvableType.forClass(Completable.class), true);
|
||||
testSupports(ResolvableType.forClass(Model.class), true);
|
||||
testSupports(ResolvableType.forClass(Map.class), true);
|
||||
testSupports(ResolvableType.forClass(TestBean.class), true);
|
||||
|
|
@ -169,6 +172,8 @@ public class ViewResolutionResultHandlerTests {
|
|||
public void defaultViewName() throws Exception {
|
||||
testDefaultViewName(null, ResolvableType.forClass(String.class));
|
||||
testDefaultViewName(Mono.empty(), ResolvableType.forClassWithGenerics(Mono.class, String.class));
|
||||
testDefaultViewName(Mono.empty(), ResolvableType.forClassWithGenerics(Mono.class, Void.class));
|
||||
testDefaultViewName(Completable.complete(), ResolvableType.forClass(Completable.class));
|
||||
}
|
||||
|
||||
private void testDefaultViewName(Object returnValue, ResolvableType type)
|
||||
|
|
@ -387,10 +392,14 @@ public class ViewResolutionResultHandlerTests {
|
|||
|
||||
Mono<View> monoView() { return null; }
|
||||
|
||||
Mono<Void> monoVoid() { return null; }
|
||||
|
||||
Single<String> singleString() { return null; }
|
||||
|
||||
Single<View> singleView() { return null; }
|
||||
|
||||
Completable completable() { return null; }
|
||||
|
||||
Model model() { return null; }
|
||||
|
||||
Map map() { return null; }
|
||||
|
|
|
|||
Loading…
Reference in New Issue