From dcbaecea2a73c10580e184b927c3747a6c6fd900 Mon Sep 17 00:00:00 2001 From: Sebastien Deleuze Date: Tue, 3 Jul 2018 13:23:51 +0200 Subject: [PATCH] Perform explicit class checks in ReactiveAdapterRegistry In order to allow Spring Framework applications running as GraalVM native images, ReactiveAdapterRegistry should perform explicit class checks instead of catching Throwable in order to avoid UnsupportedFeatureError errors. Issue: SPR-17000 --- .../core/ReactiveAdapterRegistry.java | 56 +++++++++---------- 1 file changed, 26 insertions(+), 30 deletions(-) diff --git a/spring-core/src/main/java/org/springframework/core/ReactiveAdapterRegistry.java b/spring-core/src/main/java/org/springframework/core/ReactiveAdapterRegistry.java index bdb0d4b5c2..6e077a96fe 100644 --- a/spring-core/src/main/java/org/springframework/core/ReactiveAdapterRegistry.java +++ b/spring-core/src/main/java/org/springframework/core/ReactiveAdapterRegistry.java @@ -63,41 +63,32 @@ public class ReactiveAdapterRegistry { */ public ReactiveAdapterRegistry() { + ClassLoader classLoader = ReactiveAdapterRegistry.class.getClassLoader(); + // Reactor boolean reactorRegistered = false; - try { + if (ClassUtils.isPresent("reactor.core.publisher.Flux", classLoader)) { new ReactorRegistrar().registerAdapters(this); reactorRegistered = true; } - catch (Throwable ex) { - // Ignore - } this.reactorPresent = reactorRegistered; // RxJava1 - try { + if (ClassUtils.isPresent("rx.Observable", classLoader)) { new RxJava1Registrar().registerAdapters(this); } - catch (Throwable ex) { - // Ignore - } // RxJava2 - try { + if (ClassUtils.isPresent("io.reactivex.Flowable", classLoader)) { new RxJava2Registrar().registerAdapters(this); } - catch (Throwable ex) { - // Ignore - } // Java 9+ Flow.Publisher - try { + if (ClassUtils.isPresent("java.util.concurrent.Flow.Publisher", classLoader)) { new ReactorJdkFlowAdapterRegistrar().registerAdapter(this); } - catch (Throwable ex) { - // Ignore for the time being... - // We can fall back on "reactive-streams-flow-bridge" (once released) - } + // If not present, do nothing for the time being... + // We can fall back on "reactive-streams-flow-bridge" (once released) } @@ -276,24 +267,29 @@ public class ReactiveAdapterRegistry { private static class ReactorJdkFlowAdapterRegistrar { - void registerAdapter(ReactiveAdapterRegistry registry) throws Exception { + void registerAdapter(ReactiveAdapterRegistry registry) { // TODO: remove reflection when build requires JDK 9+ - String publisherName = "java.util.concurrent.Flow.Publisher"; - Class publisherClass = ClassUtils.forName(publisherName, getClass().getClassLoader()); + try { + String publisherName = "java.util.concurrent.Flow.Publisher"; + Class publisherClass = ClassUtils.forName(publisherName, getClass().getClassLoader()); - String adapterName = "reactor.adapter.JdkFlowAdapter"; - Class flowAdapterClass = ClassUtils.forName(adapterName, getClass().getClassLoader()); + String adapterName = "reactor.adapter.JdkFlowAdapter"; + Class flowAdapterClass = ClassUtils.forName(adapterName, getClass().getClassLoader()); - Method toFluxMethod = flowAdapterClass.getMethod("flowPublisherToFlux", publisherClass); - Method toFlowMethod = flowAdapterClass.getMethod("publisherToFlowPublisher", Publisher.class); - Object emptyFlow = ReflectionUtils.invokeMethod(toFlowMethod, null, Flux.empty()); + Method toFluxMethod = flowAdapterClass.getMethod("flowPublisherToFlux", publisherClass); + Method toFlowMethod = flowAdapterClass.getMethod("publisherToFlowPublisher", Publisher.class); + Object emptyFlow = ReflectionUtils.invokeMethod(toFlowMethod, null, Flux.empty()); - registry.registerReactiveType( - ReactiveTypeDescriptor.multiValue(publisherClass, () -> emptyFlow), - source -> (Publisher) ReflectionUtils.invokeMethod(toFluxMethod, null, source), - publisher -> ReflectionUtils.invokeMethod(toFlowMethod, null, publisher) - ); + registry.registerReactiveType( + ReactiveTypeDescriptor.multiValue(publisherClass, () -> emptyFlow), + source -> (Publisher) ReflectionUtils.invokeMethod(toFluxMethod, null, source), + publisher -> ReflectionUtils.invokeMethod(toFlowMethod, null, publisher) + ); + } + catch (Throwable ex) { + // Ignore + } } }