diff --git a/reactive/src/main/java/feign/reactive/ReactorFeign.java b/reactive/src/main/java/feign/reactive/ReactorFeign.java index 33278dfc21..9fb33f408b 100644 --- a/reactive/src/main/java/feign/reactive/ReactorFeign.java +++ b/reactive/src/main/java/feign/reactive/ReactorFeign.java @@ -14,7 +14,8 @@ package feign.reactive; import feign.Feign; -import feign.reactive.ReactiveFeign.Builder; +import reactor.core.scheduler.Scheduler; +import reactor.core.scheduler.Schedulers; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.util.Map; @@ -29,24 +30,36 @@ public static Builder builder() { public static class Builder extends ReactiveFeign.Builder { + private Scheduler scheduler = Schedulers.elastic(); + @Override public Feign build() { - super.invocationHandlerFactory(new ReactorInvocationHandlerFactory()); + super.invocationHandlerFactory(new ReactorInvocationHandlerFactory(scheduler)); return super.build(); } @Override - public Feign.Builder invocationHandlerFactory( - InvocationHandlerFactory invocationHandlerFactory) { + public Builder invocationHandlerFactory(InvocationHandlerFactory invocationHandlerFactory) { throw new UnsupportedOperationException( "Invocation Handler Factory overrides are not supported."); } + + public Builder scheduleOn(Scheduler scheduler) { + this.scheduler = scheduler; + return this; + } } private static class ReactorInvocationHandlerFactory implements InvocationHandlerFactory { + private final Scheduler scheduler; + + private ReactorInvocationHandlerFactory(Scheduler scheduler) { + this.scheduler = scheduler; + } + @Override public InvocationHandler create(Target target, Map dispatch) { - return new ReactorInvocationHandler(target, dispatch); + return new ReactorInvocationHandler(target, dispatch, scheduler); } } } diff --git a/reactive/src/main/java/feign/reactive/ReactorInvocationHandler.java b/reactive/src/main/java/feign/reactive/ReactorInvocationHandler.java index cdd6569b2e..ff5e827d98 100644 --- a/reactive/src/main/java/feign/reactive/ReactorInvocationHandler.java +++ b/reactive/src/main/java/feign/reactive/ReactorInvocationHandler.java @@ -20,22 +20,25 @@ import org.reactivestreams.Publisher; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; -import reactor.core.scheduler.Schedulers; +import reactor.core.scheduler.Scheduler; public class ReactorInvocationHandler extends ReactiveInvocationHandler { + private final Scheduler scheduler; ReactorInvocationHandler(Target target, - Map dispatch) { + Map dispatch, + Scheduler scheduler) { super(target, dispatch); + this.scheduler = scheduler; } @Override protected Publisher invoke(Method method, MethodHandler methodHandler, Object[] arguments) { Publisher invocation = this.invokeMethod(methodHandler, arguments); if (Flux.class.isAssignableFrom(method.getReturnType())) { - return Flux.from(invocation).subscribeOn(Schedulers.elastic()); + return Flux.from(invocation).subscribeOn(scheduler); } else if (Mono.class.isAssignableFrom(method.getReturnType())) { - return Mono.from(invocation).subscribeOn(Schedulers.elastic()); + return Mono.from(invocation).subscribeOn(scheduler); } throw new IllegalArgumentException( "Return type " + method.getReturnType().getName() + " is not supported"); diff --git a/reactive/src/main/java/feign/reactive/RxJavaFeign.java b/reactive/src/main/java/feign/reactive/RxJavaFeign.java index 89ea356400..8554a3e552 100644 --- a/reactive/src/main/java/feign/reactive/RxJavaFeign.java +++ b/reactive/src/main/java/feign/reactive/RxJavaFeign.java @@ -19,6 +19,8 @@ import feign.Feign; import feign.InvocationHandlerFactory; import feign.Target; +import io.reactivex.Scheduler; +import io.reactivex.schedulers.Schedulers; public class RxJavaFeign extends ReactiveFeign { @@ -28,25 +30,36 @@ public static Builder builder() { public static class Builder extends ReactiveFeign.Builder { + private Scheduler scheduler = Schedulers.trampoline(); + @Override public Feign build() { - super.invocationHandlerFactory(new RxJavaInvocationHandlerFactory()); + super.invocationHandlerFactory(new RxJavaInvocationHandlerFactory(scheduler)); return super.build(); } @Override - public Feign.Builder invocationHandlerFactory( - InvocationHandlerFactory invocationHandlerFactory) { + public Builder invocationHandlerFactory(InvocationHandlerFactory invocationHandlerFactory) { throw new UnsupportedOperationException( "Invocation Handler Factory overrides are not supported."); } + public Builder scheduleOn(Scheduler scheduler) { + this.scheduler = scheduler; + return this; + } } private static class RxJavaInvocationHandlerFactory implements InvocationHandlerFactory { + private final Scheduler scheduler; + + private RxJavaInvocationHandlerFactory(Scheduler scheduler) { + this.scheduler = scheduler; + } + @Override public InvocationHandler create(Target target, Map dispatch) { - return new RxJavaInvocationHandler(target, dispatch); + return new RxJavaInvocationHandler(target, dispatch, scheduler); } } diff --git a/reactive/src/main/java/feign/reactive/RxJavaInvocationHandler.java b/reactive/src/main/java/feign/reactive/RxJavaInvocationHandler.java index fe9076d30b..c1defe1150 100644 --- a/reactive/src/main/java/feign/reactive/RxJavaInvocationHandler.java +++ b/reactive/src/main/java/feign/reactive/RxJavaInvocationHandler.java @@ -16,21 +16,24 @@ import feign.InvocationHandlerFactory.MethodHandler; import feign.Target; import io.reactivex.Flowable; -import io.reactivex.schedulers.Schedulers; +import io.reactivex.Scheduler; import java.lang.reflect.Method; import java.util.Map; import org.reactivestreams.Publisher; public class RxJavaInvocationHandler extends ReactiveInvocationHandler { + private final Scheduler scheduler; RxJavaInvocationHandler(Target target, - Map dispatch) { + Map dispatch, + Scheduler scheduler) { super(target, dispatch); + this.scheduler = scheduler; } @Override protected Publisher invoke(Method method, MethodHandler methodHandler, Object[] arguments) { return Flowable.fromPublisher(this.invokeMethod(methodHandler, arguments)) - .observeOn(Schedulers.trampoline()); + .observeOn(scheduler); } } diff --git a/reactive/src/test/java/feign/reactive/ReactiveInvocationHandlerTest.java b/reactive/src/test/java/feign/reactive/ReactiveInvocationHandlerTest.java index 4368a8a8c5..50ac0a9c87 100644 --- a/reactive/src/test/java/feign/reactive/ReactiveInvocationHandlerTest.java +++ b/reactive/src/test/java/feign/reactive/ReactiveInvocationHandlerTest.java @@ -23,17 +23,16 @@ import feign.RequestLine; import feign.Target; import io.reactivex.Flowable; - import java.io.IOException; import java.lang.reflect.Method; import java.util.Collections; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; import reactor.core.publisher.Mono; +import reactor.core.scheduler.Schedulers; import reactor.test.StepVerifier; @RunWith(MockitoJUnitRunner.class) @@ -57,7 +56,7 @@ public void setUp() throws NoSuchMethodException { public void invokeOnSubscribeReactor() throws Throwable { given(this.methodHandler.invoke(any())).willReturn("Result"); ReactorInvocationHandler handler = new ReactorInvocationHandler(this.target, - Collections.singletonMap(method, this.methodHandler)); + Collections.singletonMap(method, this.methodHandler), Schedulers.elastic()); Object result = handler.invoke(method, this.methodHandler, new Object[] {}); assertThat(result).isInstanceOf(Mono.class); @@ -75,7 +74,7 @@ public void invokeOnSubscribeReactor() throws Throwable { public void invokeOnSubscribeEmptyReactor() throws Throwable { given(this.methodHandler.invoke(any())).willReturn(null); ReactorInvocationHandler handler = new ReactorInvocationHandler(this.target, - Collections.singletonMap(method, this.methodHandler)); + Collections.singletonMap(method, this.methodHandler), Schedulers.elastic()); Object result = handler.invoke(method, this.methodHandler, new Object[] {}); assertThat(result).isInstanceOf(Mono.class); @@ -92,7 +91,7 @@ public void invokeOnSubscribeEmptyReactor() throws Throwable { public void invokeFailureReactor() throws Throwable { given(this.methodHandler.invoke(any())).willThrow(new IOException("Could Not Decode")); ReactorInvocationHandler handler = new ReactorInvocationHandler(this.target, - Collections.singletonMap(this.method, this.methodHandler)); + Collections.singletonMap(this.method, this.methodHandler), Schedulers.elastic()); Object result = handler.invoke(this.method, this.methodHandler, new Object[] {}); assertThat(result).isInstanceOf(Mono.class); @@ -111,7 +110,8 @@ public void invokeOnSubscribeRxJava() throws Throwable { given(this.methodHandler.invoke(any())).willReturn("Result"); RxJavaInvocationHandler handler = new RxJavaInvocationHandler(this.target, - Collections.singletonMap(this.method, this.methodHandler)); + Collections.singletonMap(this.method, this.methodHandler), + io.reactivex.schedulers.Schedulers.trampoline()); Object result = handler.invoke(this.method, this.methodHandler, new Object[] {}); assertThat(result).isInstanceOf(Flowable.class); @@ -129,8 +129,9 @@ public void invokeOnSubscribeRxJava() throws Throwable { public void invokeOnSubscribeEmptyRxJava() throws Throwable { given(this.methodHandler.invoke(any())).willReturn(null); RxJavaInvocationHandler handler = - new RxJavaInvocationHandler(this.target, - Collections.singletonMap(this.method, this.methodHandler)); + new RxJavaInvocationHandler(this.target, + Collections.singletonMap(this.method, this.methodHandler), + io.reactivex.schedulers.Schedulers.trampoline()); Object result = handler.invoke(this.method, this.methodHandler, new Object[] {}); assertThat(result).isInstanceOf(Flowable.class); @@ -148,7 +149,8 @@ public void invokeFailureRxJava() throws Throwable { given(this.methodHandler.invoke(any())).willThrow(new IOException("Could Not Decode")); RxJavaInvocationHandler handler = new RxJavaInvocationHandler(this.target, - Collections.singletonMap(this.method, this.methodHandler)); + Collections.singletonMap(this.method, this.methodHandler), + io.reactivex.schedulers.Schedulers.trampoline()); Object result = handler.invoke(this.method, this.methodHandler, new Object[] {}); assertThat(result).isInstanceOf(Flowable.class);