Refactor ReactiveAdapter hierarchy
Collapse ReactiveAdapter hierarchy into a single class that simply delegates to functions for converting to/from a Publisher. A private ReactorAdapter extension automaticlaly wraps adapted, "raw" Publisher's as Flux or Mono depending on the semantics of the target reactive type. Issue: SPR-14902
This commit is contained in:
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package org.springframework.core.convert.support;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import io.reactivex.Flowable;
|
||||
@@ -31,59 +33,211 @@ import rx.Single;
|
||||
import org.springframework.core.ReactiveAdapter;
|
||||
import org.springframework.core.ReactiveAdapterRegistry;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link ReactiveAdapterRegistry}.
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public class ReactiveAdapterRegistryTests {
|
||||
|
||||
private ReactiveAdapterRegistry adapterRegistry;
|
||||
private ReactiveAdapterRegistry registry;
|
||||
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
this.adapterRegistry = new ReactiveAdapterRegistry();
|
||||
this.registry = new ReactiveAdapterRegistry();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void getDefaultAdapters() throws Exception {
|
||||
testMonoAdapter(Mono.class);
|
||||
testFluxAdapter(Flux.class);
|
||||
testFluxAdapter(Publisher.class);
|
||||
testMonoAdapter(CompletableFuture.class);
|
||||
testFluxAdapter(Observable.class);
|
||||
testMonoAdapter(Single.class);
|
||||
testMonoAdapter(Completable.class);
|
||||
testFluxAdapter(Flowable.class);
|
||||
testFluxAdapter(io.reactivex.Observable.class);
|
||||
testMonoAdapter(io.reactivex.Single.class);
|
||||
testMonoAdapter(Maybe.class);
|
||||
testMonoAdapter(io.reactivex.Completable.class);
|
||||
|
||||
// Reactor
|
||||
assertNotNull(getAdapterTo(Mono.class));
|
||||
assertNotNull(getAdapterTo(Flux.class));
|
||||
|
||||
assertNotNull(getAdapterTo(Publisher.class));
|
||||
assertNotNull(getAdapterTo(CompletableFuture.class));
|
||||
|
||||
// RxJava 1
|
||||
assertNotNull(getAdapterTo(Observable.class));
|
||||
assertNotNull(getAdapterTo(Single.class));
|
||||
assertNotNull(getAdapterTo(Completable.class));
|
||||
|
||||
// RxJava 2
|
||||
assertNotNull(getAdapterTo(Flowable.class));
|
||||
assertNotNull(getAdapterTo(io.reactivex.Observable.class));
|
||||
assertNotNull(getAdapterTo(io.reactivex.Single.class));
|
||||
assertNotNull(getAdapterTo(Maybe.class));
|
||||
assertNotNull(getAdapterTo(io.reactivex.Completable.class));
|
||||
}
|
||||
|
||||
private void testFluxAdapter(Class<?> adapteeType) {
|
||||
ReactiveAdapter adapter = this.adapterRegistry.getAdapterFrom(adapteeType);
|
||||
assertNotNull(adapter);
|
||||
assertTrue(adapter.getDescriptor().isMultiValue());
|
||||
|
||||
adapter = this.adapterRegistry.getAdapterTo(adapteeType);
|
||||
assertNotNull(adapter);
|
||||
assertTrue(adapter.getDescriptor().isMultiValue());
|
||||
@Test
|
||||
public void publisherToFlux() throws Exception {
|
||||
List<Integer> sequence = Arrays.asList(1, 2, 3);
|
||||
Publisher<Integer> source = Flowable.fromIterable(sequence);
|
||||
Object target = getAdapterTo(Flux.class).fromPublisher(source);
|
||||
assertTrue(target instanceof Flux);
|
||||
assertEquals(sequence, ((Flux<Integer>) target).collectList().blockMillis(1000));
|
||||
}
|
||||
|
||||
private void testMonoAdapter(Class<?> adapteeType) {
|
||||
ReactiveAdapter adapter = this.adapterRegistry.getAdapterFrom(adapteeType);
|
||||
assertNotNull(adapter);
|
||||
assertFalse(adapter.getDescriptor().isMultiValue());
|
||||
// TODO: publisherToMono/CompletableFuture vs Single (ISE on multiple elements)?
|
||||
|
||||
adapter = this.adapterRegistry.getAdapterTo(adapteeType);
|
||||
assertNotNull(adapter);
|
||||
assertFalse(adapter.getDescriptor().isMultiValue());
|
||||
@Test
|
||||
public void publisherToMono() throws Exception {
|
||||
Publisher<Integer> source = Flowable.fromArray(1, 2, 3);
|
||||
Object target = getAdapterTo(Mono.class).fromPublisher(source);
|
||||
assertTrue(target instanceof Mono);
|
||||
assertEquals(new Integer(1), ((Mono<Integer>) target).blockMillis(1000));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void publisherToCompletableFuture() throws Exception {
|
||||
Publisher<Integer> source = Flowable.fromArray(1, 2, 3);
|
||||
Object target = getAdapterTo(CompletableFuture.class).fromPublisher(source);
|
||||
assertTrue(target instanceof CompletableFuture);
|
||||
assertEquals(new Integer(1), ((CompletableFuture<Integer>) target).get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void publisherToRxObservable() throws Exception {
|
||||
List<Integer> sequence = Arrays.asList(1, 2, 3);
|
||||
Publisher<Integer> source = Flowable.fromIterable(sequence);
|
||||
Object target = getAdapterTo(rx.Observable.class).fromPublisher(source);
|
||||
assertTrue(target instanceof rx.Observable);
|
||||
assertEquals(sequence, ((rx.Observable) target).toList().toBlocking().first());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void publisherToRxSingle() throws Exception {
|
||||
Publisher<Integer> source = Flowable.fromArray(1);
|
||||
Object target = getAdapterTo(rx.Single.class).fromPublisher(source);
|
||||
assertTrue(target instanceof rx.Single);
|
||||
assertEquals(new Integer(1), ((rx.Single<Integer>) target).toBlocking().value());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void publisherToRxCompletable() throws Exception {
|
||||
Publisher<Integer> source = Flowable.fromArray(1, 2, 3);
|
||||
Object target = getAdapterTo(rx.Completable.class).fromPublisher(source);
|
||||
assertTrue(target instanceof rx.Completable);
|
||||
assertNull(((rx.Completable) target).get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void publisherToReactivexFlowable() throws Exception {
|
||||
List<Integer> sequence = Arrays.asList(1, 2, 3);
|
||||
Publisher<Integer> source = Flux.fromIterable(sequence);
|
||||
Object target = getAdapterTo(io.reactivex.Flowable.class).fromPublisher(source);
|
||||
assertTrue(target instanceof io.reactivex.Flowable);
|
||||
assertEquals(sequence, ((io.reactivex.Flowable) target).toList().blockingGet());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void publisherToReactivexObservable() throws Exception {
|
||||
List<Integer> sequence = Arrays.asList(1, 2, 3);
|
||||
Publisher<Integer> source = Flowable.fromIterable(sequence);
|
||||
Object target = getAdapterTo(io.reactivex.Observable.class).fromPublisher(source);
|
||||
assertTrue(target instanceof io.reactivex.Observable);
|
||||
assertEquals(sequence, ((io.reactivex.Observable) target).toList().blockingGet());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void publisherToReactivexSingle() throws Exception {
|
||||
Publisher<Integer> source = Flowable.fromArray(1);
|
||||
Object target = getAdapterTo(io.reactivex.Single.class).fromPublisher(source);
|
||||
assertTrue(target instanceof io.reactivex.Single);
|
||||
assertEquals(new Integer(1), ((io.reactivex.Single<Integer>) target).blockingGet());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void publisherToReactivexCompletable() throws Exception {
|
||||
Publisher<Integer> source = Flowable.fromArray(1, 2, 3);
|
||||
Object target = getAdapterTo(io.reactivex.Completable.class).fromPublisher(source);
|
||||
assertTrue(target instanceof io.reactivex.Completable);
|
||||
assertNull(((io.reactivex.Completable) target).blockingGet());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void rxObservableToPublisher() throws Exception {
|
||||
List<Integer> sequence = Arrays.asList(1, 2, 3);
|
||||
Object source = rx.Observable.from(sequence);
|
||||
Object target = getAdapterFrom(rx.Observable.class).toPublisher(source);
|
||||
assertTrue("Expected Flux Publisher: " + target.getClass().getName(), target instanceof Flux);
|
||||
assertEquals(sequence, ((Flux<Integer>) target).collectList().blockMillis(1000));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void rxSingleToPublisher() throws Exception {
|
||||
Object source = rx.Single.just(1);
|
||||
Object target = getAdapterFrom(rx.Single.class).toPublisher(source);
|
||||
assertTrue("Expected Mono Publisher: " + target.getClass().getName(), target instanceof Mono);
|
||||
assertEquals(new Integer(1), ((Mono<Integer>) target).blockMillis(1000));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void rxCompletableToPublisher() throws Exception {
|
||||
Object source = rx.Completable.complete();
|
||||
Object target = getAdapterFrom(rx.Completable.class).toPublisher(source);
|
||||
assertTrue("Expected Mono Publisher: " + target.getClass().getName(), target instanceof Mono);
|
||||
((Mono<Void>) target).blockMillis(1000);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void reactivexFlowableToPublisher() throws Exception {
|
||||
List<Integer> sequence = Arrays.asList(1, 2, 3);
|
||||
Object source = io.reactivex.Flowable.fromIterable(sequence);
|
||||
Object target = getAdapterFrom(io.reactivex.Flowable.class).toPublisher(source);
|
||||
assertTrue("Expected Flux Publisher: " + target.getClass().getName(), target instanceof Flux);
|
||||
assertEquals(sequence, ((Flux<Integer>) target).collectList().blockMillis(1000));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void reactivexObservableToPublisher() throws Exception {
|
||||
List<Integer> sequence = Arrays.asList(1, 2, 3);
|
||||
Object source = io.reactivex.Observable.fromIterable(sequence);
|
||||
Object target = getAdapterFrom(io.reactivex.Observable.class).toPublisher(source);
|
||||
assertTrue("Expected Flux Publisher: " + target.getClass().getName(), target instanceof Flux);
|
||||
assertEquals(sequence, ((Flux<Integer>) target).collectList().blockMillis(1000));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void reactivexSingleToPublisher() throws Exception {
|
||||
Object source = io.reactivex.Single.just(1);
|
||||
Object target = getAdapterFrom(io.reactivex.Single.class).toPublisher(source);
|
||||
assertTrue("Expected Mono Publisher: " + target.getClass().getName(), target instanceof Mono);
|
||||
assertEquals(new Integer(1), ((Mono<Integer>) target).blockMillis(1000));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void reactivexCompletableToPublisher() throws Exception {
|
||||
Object source = io.reactivex.Completable.complete();
|
||||
Object target = getAdapterFrom(io.reactivex.Completable.class).toPublisher(source);
|
||||
assertTrue("Expected Mono Publisher: " + target.getClass().getName(), target instanceof Mono);
|
||||
((Mono<Void>) target).blockMillis(1000);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void CompletableFutureToPublisher() throws Exception {
|
||||
CompletableFuture<Integer> future = new CompletableFuture();
|
||||
future.complete(1);
|
||||
Object target = getAdapterFrom(CompletableFuture.class).toPublisher(future);
|
||||
assertTrue("Expected Mono Publisher: " + target.getClass().getName(), target instanceof Mono);
|
||||
assertEquals(new Integer(1), ((Mono<Integer>) target).blockMillis(1000));
|
||||
}
|
||||
|
||||
|
||||
private ReactiveAdapter getAdapterTo(Class<?> reactiveType) {
|
||||
return this.registry.getAdapterTo(reactiveType);
|
||||
}
|
||||
|
||||
private ReactiveAdapter getAdapterFrom(Class<?> reactiveType) {
|
||||
return this.registry.getAdapterFrom(reactiveType);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user