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:
Rossen Stoyanchev
2016-11-24 18:30:05 -05:00
parent e563326357
commit 52096ab8b9
8 changed files with 340 additions and 214 deletions

View File

@@ -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);
}
}