diff --git a/src/main/java/io/reactivex/plugins/RxJavaPlugins.java b/src/main/java/io/reactivex/plugins/RxJavaPlugins.java index 5ab0192342..d698f182b7 100644 --- a/src/main/java/io/reactivex/plugins/RxJavaPlugins.java +++ b/src/main/java/io/reactivex/plugins/RxJavaPlugins.java @@ -30,8 +30,27 @@ import io.reactivex.schedulers.Schedulers; /** * Utility class to inject handlers to certain standard RxJava operations. + *

+ * Supported system properties ({@code System.getProperty()}): + *

*/ public final class RxJavaPlugins { + + /** + * System property value for uncaught exceptions that passes the exception directly to the current thread's + * {@link UncaughtExceptionHandler}. This is the default behavior. + */ + @Experimental + public static final String UNCAUGHT_HANDLER = "handler"; + + /** + * System property value for uncaught exceptions that just immediately throws the uncaught exception. + */ + @Experimental + public static final String UNCAUGHT_THROW = "throw"; + @Nullable static volatile Consumer errorHandler; @@ -123,6 +142,9 @@ public final class RxJavaPlugins { */ static volatile boolean failNonBlockingScheduler; + /** The name of the system property for setting the uncaught exception behavior. */ + private static final String KEY_UNCAUGHT_BEHAVIOR = "rx2.uncaught-behavior"; + /** * Prevents changing the plugins from then on. *

This allows container-like environments to prevent clients @@ -406,9 +428,15 @@ static boolean isBug(Throwable error) { } static void uncaught(@NonNull Throwable error) { - Thread currentThread = Thread.currentThread(); - UncaughtExceptionHandler handler = currentThread.getUncaughtExceptionHandler(); - handler.uncaughtException(currentThread, error); + String uncaughtBehavior = System.getProperty(KEY_UNCAUGHT_BEHAVIOR, UNCAUGHT_HANDLER); + if (UNCAUGHT_THROW.equals(uncaughtBehavior)) { + throw new UncaughtRxJavaException(error); + } else { + Thread currentThread = Thread.currentThread(); + UncaughtExceptionHandler handler = currentThread.getUncaughtExceptionHandler(); + handler.uncaughtException(currentThread, error); + } + // TODO Error on invalid inputs somehow? } /** diff --git a/src/main/java/io/reactivex/plugins/UncaughtRxJavaException.java b/src/main/java/io/reactivex/plugins/UncaughtRxJavaException.java new file mode 100644 index 0000000000..0346f047dc --- /dev/null +++ b/src/main/java/io/reactivex/plugins/UncaughtRxJavaException.java @@ -0,0 +1,16 @@ +package io.reactivex.plugins; + +import io.reactivex.annotations.Experimental; + +/** + * An exception thrown when an uncaught throwable was received and the {@link RxJavaPlugins#UNCAUGHT_THROW} property was + * set. This guarantees the existence of an underlying cause retrievable via {@link #getCause()}. + */ +@Experimental +public final class UncaughtRxJavaException extends RuntimeException { + + public UncaughtRxJavaException(Throwable cause) { + super(cause); + } + +}