-
Notifications
You must be signed in to change notification settings - Fork 7.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
2.x: Evaluate Schedule initialization via Callable #4585
Changes from 2 commits
0ab5956
5112117
85e14a9
1303f47
e521926
9ccf4ed
38bb3c0
174ce7a
aeafcc7
786090d
c191e31
fff28b2
a273507
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,6 +13,7 @@ | |
package io.reactivex.plugins; | ||
|
||
import java.lang.Thread.UncaughtExceptionHandler; | ||
import java.util.concurrent.Callable; | ||
|
||
import org.reactivestreams.Subscriber; | ||
|
||
|
@@ -183,52 +184,52 @@ public static Function<Scheduler, Scheduler> getSingleSchedulerHandler() { | |
|
||
/** | ||
* Calls the associated hook function. | ||
* @param defaultScheduler the hook's input value | ||
* @param defaultScheduler a {@link Callable} which returns the hook's input value | ||
* @return the value returned by the hook | ||
*/ | ||
public static Scheduler initComputationScheduler(Scheduler defaultScheduler) { | ||
public static Scheduler initComputationScheduler(Callable<Scheduler> defaultScheduler) { | ||
Function<Scheduler, Scheduler> f = onInitComputationHandler; | ||
if (f == null) { | ||
return defaultScheduler; | ||
return callOrNull(defaultScheduler); | ||
} | ||
return apply(f, defaultScheduler); // JIT will skip this | ||
} | ||
|
||
/** | ||
* Calls the associated hook function. | ||
* @param defaultScheduler the hook's input value | ||
* @param defaultScheduler a {@link Callable} which returns the hook's input value | ||
* @return the value returned by the hook | ||
*/ | ||
public static Scheduler initIoScheduler(Scheduler defaultScheduler) { | ||
public static Scheduler initIoScheduler(Callable<Scheduler> defaultScheduler) { | ||
Function<Scheduler, Scheduler> f = onInitIoHandler; | ||
if (f == null) { | ||
return defaultScheduler; | ||
return callOrNull(defaultScheduler); | ||
} | ||
return apply(f, defaultScheduler); | ||
} | ||
|
||
/** | ||
* Calls the associated hook function. | ||
* @param defaultScheduler the hook's input value | ||
* @param defaultScheduler a {@link Callable} which returns the hook's input value | ||
* @return the value returned by the hook | ||
*/ | ||
public static Scheduler initNewThreadScheduler(Scheduler defaultScheduler) { | ||
public static Scheduler initNewThreadScheduler(Callable<Scheduler> defaultScheduler) { | ||
Function<Scheduler, Scheduler> f = onInitNewThreadHandler; | ||
if (f == null) { | ||
return defaultScheduler; | ||
return callOrNull(defaultScheduler); | ||
} | ||
return apply(f, defaultScheduler); | ||
} | ||
|
||
/** | ||
* Calls the associated hook function. | ||
* @param defaultScheduler the hook's input value | ||
* @param defaultScheduler a {@link Callable} which returns the hook's input value | ||
* @return the value returned by the hook | ||
*/ | ||
public static Scheduler initSingleScheduler(Scheduler defaultScheduler) { | ||
public static Scheduler initSingleScheduler(Callable<Scheduler> defaultScheduler) { | ||
Function<Scheduler, Scheduler> f = onInitSingleHandler; | ||
if (f == null) { | ||
return defaultScheduler; | ||
return callOrNull(defaultScheduler); | ||
} | ||
return apply(f, defaultScheduler); | ||
} | ||
|
@@ -934,6 +935,23 @@ static <T, R> R apply(Function<T, R> f, T t) { | |
} | ||
} | ||
|
||
/** | ||
* Wraps the call to the function in try-catch and propagates thrown | ||
* checked exceptions as RuntimeException. | ||
* @param <T> the input type | ||
* @param <R> the output type | ||
* @param f the function to call, not null (not verified) | ||
* @param t the {@link Callable} parameter value to the function | ||
* @return the result of the function call | ||
*/ | ||
static <T, R> R apply(Function<T, R> f, Callable<T> t) { | ||
try { | ||
return f.apply(t.call()); | ||
} catch (Throwable ex) { | ||
throw ExceptionHelper.wrapOrThrow(ex); | ||
} | ||
} | ||
|
||
/** | ||
* Wraps the call to the function in try-catch and propagates thrown | ||
* checked exceptions as RuntimeException. | ||
|
@@ -953,6 +971,33 @@ static <T, U, R> R apply(BiFunction<T, U, R> f, T t, U u) { | |
} | ||
} | ||
|
||
/** | ||
* Wraps the call to the callable in try-catch and propagates thrown | ||
* checked exceptions as RuntimeException. | ||
* @param <T> the input type | ||
* @param <T> the output type | ||
* @param t the callable, not null (not verified) | ||
* @return the result of the callable call | ||
*/ | ||
static <T> T call(Callable<T> t) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. inline this method? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure what you mean. I've tried to be consistent with the abstraction of the similar |
||
try { | ||
return t.call(); | ||
} catch (Throwable ex) { | ||
throw ExceptionHelper.wrapOrThrow(ex); | ||
} | ||
} | ||
|
||
/** | ||
* Wraps the call to the callable in try-catch and propagates thrown | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. copy paste error There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed. |
||
* checked exceptions as RuntimeException. | ||
* @param <T> the input and output type | ||
* @param t the callable, nullable | ||
* @return the callable result if the callable is nonnull, null otherwise. | ||
*/ | ||
static <T> T callOrNull(Callable<T> t) { | ||
return t == null ? null : call(t); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. null should never be allowed |
||
} | ||
|
||
/** Helper class, no instances. */ | ||
private RxJavaPlugins() { | ||
throw new IllegalStateException("No instances!"); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,6 +13,7 @@ | |
|
||
package io.reactivex.schedulers; | ||
|
||
import java.util.concurrent.Callable; | ||
import java.util.concurrent.Executor; | ||
|
||
import io.reactivex.Scheduler; | ||
|
@@ -45,15 +46,35 @@ public final class Schedulers { | |
static final Scheduler NEW_THREAD; | ||
|
||
static { | ||
SINGLE = RxJavaPlugins.initSingleScheduler(new SingleScheduler()); | ||
|
||
COMPUTATION = RxJavaPlugins.initComputationScheduler(new ComputationScheduler()); | ||
|
||
IO = RxJavaPlugins.initIoScheduler(new IoScheduler()); | ||
SINGLE = RxJavaPlugins.initSingleScheduler(new Callable<Scheduler>() { | ||
@Override | ||
public Scheduler call() throws Exception { | ||
return new SingleScheduler(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just in case call() is called multiple times by the hook, these could actually return an field of an inner class (singleton holder pattern or what's the name): static final class SingleHolder {
static final Scheduler DEFAULT = new SingleScheduler();
}
SINGLE = RxJavaPlugins.initiSingleScheduler(new Callable<Scheduler>() {
@Override
public Scheduler call() {
return SingleHolder.DEFAULT;
}
}); |
||
} | ||
}); | ||
|
||
COMPUTATION = RxJavaPlugins.initComputationScheduler(new Callable<Scheduler>() { | ||
@Override | ||
public Scheduler call() throws Exception { | ||
return new ComputationScheduler(); | ||
} | ||
}); | ||
|
||
IO = RxJavaPlugins.initIoScheduler(new Callable<Scheduler>() { | ||
@Override | ||
public Scheduler call() throws Exception { | ||
return new IoScheduler(); | ||
} | ||
}); | ||
|
||
TRAMPOLINE = TrampolineScheduler.instance(); | ||
|
||
NEW_THREAD = RxJavaPlugins.initNewThreadScheduler(NewThreadScheduler.instance()); | ||
NEW_THREAD = RxJavaPlugins.initNewThreadScheduler(new Callable<Scheduler>() { | ||
@Override | ||
public Scheduler call() throws Exception { | ||
return NewThreadScheduler.instance(); | ||
} | ||
}); | ||
} | ||
|
||
/** Utility class. */ | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should not it throw on a null callable? What's the point of calling with null?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was done for consistency with the existing expectations in
RxJavaPluginsTest.clearIsPassthrough()
, specifically:Should this be changed to only return null if the
Callable
returns null (and throw if theCallable
itself is null)?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Null should not be allowed as a return value from the
Callable
nor from the initFunction
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This would be a change, because previously the
Scheduler
value forRxJavaPlugins.init*
was allowed to be null, as per -assertNull(RxJavaPlugins.initSingleScheduler(null));
.I will add an additional set of tests for the new behavior (something along the lines of
assemblyHookCrashes
).There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.