ReactiveAdapterRegistry detects Reactor

The ReactiveAdapterRegistry now detects the presence of Reactor. In
practice Reactor is required for the Spring Framework reactive support
and it is expected to be present.

The registry however is now capable of being neutral if Reactor is not
present on the classpath for example where other Spring projects may
not have the same assumptions about Reactor's presence.

Issue: SPR-14902
This commit is contained in:
Rossen Stoyanchev 2016-11-27 21:36:14 -05:00
parent 52096ab8b9
commit ac86acde53
2 changed files with 54 additions and 38 deletions

View File

@ -36,12 +36,12 @@ import rx.RxReactiveStreams;
import org.springframework.util.ClassUtils; import org.springframework.util.ClassUtils;
/** /**
* A registry of adapters to adapt to {@link Flux} and {@link Mono}. * A registry of adapters to adapt a Reactive Streams {@link Publisher} to/from
* various async/reactive types such as {@code CompletableFuture}, RxJava
* {@code Observable}, and others.
* *
* <p>By default, depending on classpath availability, adapters are registered * <p>By default, depending on classpath availability, adapters are registered
* for RxJava 1, RxJava 2 types, and {@link CompletableFuture}. In addition the * for Reactor, RxJava 1, RxJava 2 types, and {@link CompletableFuture}.
* registry contains adapters for Reactor's own Flux and Mono types (no-op)
* along with adaption for any other Reactive Streams {@link Publisher}.
* *
* @author Rossen Stoyanchev * @author Rossen Stoyanchev
* @author Sebastien Deleuze * @author Sebastien Deleuze
@ -49,6 +49,9 @@ import org.springframework.util.ClassUtils;
*/ */
public class ReactiveAdapterRegistry { public class ReactiveAdapterRegistry {
private static final boolean reactorPresent =
ClassUtils.isPresent("reactor.core.publisher.Flux", ReactiveAdapterRegistry.class.getClassLoader());
private static final boolean rxJava1Present = private static final boolean rxJava1Present =
ClassUtils.isPresent("rx.Observable", ReactiveAdapterRegistry.class.getClassLoader()); ClassUtils.isPresent("rx.Observable", ReactiveAdapterRegistry.class.getClassLoader());
@ -67,35 +70,14 @@ public class ReactiveAdapterRegistry {
*/ */
public ReactiveAdapterRegistry() { public ReactiveAdapterRegistry() {
// Flux and Mono ahead of Publisher... if (reactorPresent) {
new ReactorRegistrar().registerAdapters(this);
registerReactiveType( }
ReactiveTypeDescriptor.singleOptionalValue(Mono.class, Mono::empty),
source -> (Mono<?>) source,
Mono::from
);
registerReactiveType(ReactiveTypeDescriptor.multiValue(Flux.class, Flux::empty),
source -> (Flux<?>) source,
Flux::from);
registerReactiveType(ReactiveTypeDescriptor.multiValue(Publisher.class, Flux::empty),
source -> (Publisher<?>) source,
source -> source);
registerReactiveType(
ReactiveTypeDescriptor.singleOptionalValue(CompletableFuture.class, () -> {
CompletableFuture<?> empty = new CompletableFuture<>();
empty.complete(null);
return empty;
}),
source -> Mono.fromFuture((CompletableFuture<?>) source),
source -> Mono.from(source).toFuture()
);
if (rxJava1Present && rxJava1Adapter) { if (rxJava1Present && rxJava1Adapter) {
new RxJava1Registrar().registerAdapters(this); new RxJava1Registrar().registerAdapters(this);
} }
if (rxJava2Present) { if (rxJava2Present) {
new RxJava2Registrar().registerAdapters(this); new RxJava2Registrar().registerAdapters(this);
} }
@ -110,7 +92,12 @@ public class ReactiveAdapterRegistry {
public void registerReactiveType(ReactiveTypeDescriptor descriptor, public void registerReactiveType(ReactiveTypeDescriptor descriptor,
Function<Object, Publisher<?>> toAdapter, Function<Publisher<?>, Object> fromAdapter) { Function<Object, Publisher<?>> toAdapter, Function<Publisher<?>, Object> fromAdapter) {
this.adapters.add(new ReactorAdapter(descriptor, toAdapter, fromAdapter)); if (reactorPresent) {
this.adapters.add(new ReactorAdapter(descriptor, toAdapter, fromAdapter));
}
else {
this.adapters.add(new ReactiveAdapter(descriptor, toAdapter, fromAdapter));
}
} }
/** /**
@ -145,9 +132,41 @@ public class ReactiveAdapterRegistry {
} }
private static class ReactorRegistrar {
void registerAdapters(ReactiveAdapterRegistry registry) {
// Flux and Mono ahead of Publisher...
registry.registerReactiveType(
ReactiveTypeDescriptor.singleOptionalValue(Mono.class, Mono::empty),
source -> (Mono<?>) source,
Mono::from
);
registry.registerReactiveType(ReactiveTypeDescriptor.multiValue(Flux.class, Flux::empty),
source -> (Flux<?>) source,
Flux::from);
registry.registerReactiveType(ReactiveTypeDescriptor.multiValue(Publisher.class, Flux::empty),
source -> (Publisher<?>) source,
source -> source);
registry.registerReactiveType(
ReactiveTypeDescriptor.singleOptionalValue(CompletableFuture.class, () -> {
CompletableFuture<?> empty = new CompletableFuture<>();
empty.complete(null);
return empty;
}),
source -> Mono.fromFuture((CompletableFuture<?>) source),
source -> Mono.from(source).toFuture()
);
}
}
private static class RxJava1Registrar { private static class RxJava1Registrar {
public void registerAdapters(ReactiveAdapterRegistry registry) { void registerAdapters(ReactiveAdapterRegistry registry) {
registry.registerReactiveType( registry.registerReactiveType(
ReactiveTypeDescriptor.multiValue(rx.Observable.class, rx.Observable::empty), ReactiveTypeDescriptor.multiValue(rx.Observable.class, rx.Observable::empty),
source -> RxReactiveStreams.toPublisher((rx.Observable<?>) source), source -> RxReactiveStreams.toPublisher((rx.Observable<?>) source),
@ -168,7 +187,7 @@ public class ReactiveAdapterRegistry {
private static class RxJava2Registrar { private static class RxJava2Registrar {
public void registerAdapters(ReactiveAdapterRegistry registry) { void registerAdapters(ReactiveAdapterRegistry registry) {
registry.registerReactiveType( registry.registerReactiveType(
ReactiveTypeDescriptor.multiValue(Flowable.class, Flowable::empty), ReactiveTypeDescriptor.multiValue(Flowable.class, Flowable::empty),
source -> (Flowable<?>) source, source -> (Flowable<?>) source,
@ -204,7 +223,7 @@ public class ReactiveAdapterRegistry {
*/ */
private static class ReactorAdapter extends ReactiveAdapter { private static class ReactorAdapter extends ReactiveAdapter {
public ReactorAdapter(ReactiveTypeDescriptor descriptor, ReactorAdapter(ReactiveTypeDescriptor descriptor,
Function<Object, Publisher<?>> toPublisherFunction, Function<Object, Publisher<?>> toPublisherFunction,
Function<Publisher<?>, Object> fromPublisherFunction) { Function<Publisher<?>, Object> fromPublisherFunction) {

View File

@ -17,9 +17,6 @@ package org.springframework.core;
import java.util.function.Supplier; import java.util.function.Supplier;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import org.springframework.util.Assert; import org.springframework.util.Assert;
/** /**
@ -76,9 +73,9 @@ public class ReactiveTypeDescriptor {
/** /**
* Return {@code true} if the reactive type can produce more than 1 value * Return {@code true} if the reactive type can produce more than 1 value
* can be produced and is therefore a good fit to adapt to {@link Flux}. * can be produced and is therefore a good fit to adapt to {@code Flux}.
* A {@code false} return value implies the reactive type can produce 1 * A {@code false} return value implies the reactive type can produce 1
* value at most and is therefore a good fit to adapt to {@link Mono}. * value at most and is therefore a good fit to adapt to {@code Mono}.
*/ */
public boolean isMultiValue() { public boolean isMultiValue() {
return this.multiValue; return this.multiValue;