From f4d2f25ce2f217d0926ec1626eb40939cb4406b9 Mon Sep 17 00:00:00 2001 From: Pierre-Yves Ricau Date: Thu, 20 Oct 2016 18:38:03 -0700 Subject: [PATCH] #4737 Error when tracking exception with unknown cause --- .../AssemblyStackTraceException.java | 10 ++++- src/test/java/rx/plugins/RxJavaHooksTest.java | 42 +++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/src/main/java/rx/exceptions/AssemblyStackTraceException.java b/src/main/java/rx/exceptions/AssemblyStackTraceException.java index 5fee891344..8342adc637 100644 --- a/src/main/java/rx/exceptions/AssemblyStackTraceException.java +++ b/src/main/java/rx/exceptions/AssemblyStackTraceException.java @@ -52,7 +52,15 @@ public void attachTo(Throwable exception) { for (;;) { if (exception.getCause() == null) { - exception.initCause(this); + try { + exception.initCause(this); + } catch (IllegalStateException e) { + RxJavaHooks.onError(new RuntimeException( + "Received an exception with a cause set to null, instead of being unset." + + " To fix this, look down the chain of causes. The last exception had" + + " a cause explicitly set to null. It should be unset instead.", + exception)); + } return; } diff --git a/src/test/java/rx/plugins/RxJavaHooksTest.java b/src/test/java/rx/plugins/RxJavaHooksTest.java index 3d9bdb7872..89a118482d 100644 --- a/src/test/java/rx/plugins/RxJavaHooksTest.java +++ b/src/test/java/rx/plugins/RxJavaHooksTest.java @@ -23,8 +23,10 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; import org.junit.Test; +import org.mockito.Mockito; import rx.*; import rx.Observable; import rx.Scheduler.Worker; @@ -39,6 +41,12 @@ public class RxJavaHooksTest { + public static class TestExceptionWithUnknownCause extends RuntimeException { + TestExceptionWithUnknownCause() { + super((Throwable) null); + } + } + static Observable createObservable() { return Observable.range(1, 5).map(new Func1() { @Override @@ -48,6 +56,15 @@ public Integer call(Integer t) { }); } + static Observable createObservableThrowingUnknownCause() { + return Observable.range(1, 5).map(new Func1() { + @Override + public Integer call(Integer t) { + throw new TestExceptionWithUnknownCause(); + } + }); + } + @Test public void constructorShouldBePrivate() { TestUtil.checkUtilityClass(RxJavaHooks.class); @@ -89,6 +106,31 @@ public void assemblyTrackingObservable() { } } + @Test + public void assemblyTrackingObservableUnknownCause() { + RxJavaHooks.enableAssemblyTracking(); + try { + final AtomicReference onErrorThrowableRef = new AtomicReference(); + RxJavaHooks.setOnError(new Action1() { + @Override + public void call(Throwable throwable) { + onErrorThrowableRef.set(throwable); + } + }); + TestSubscriber ts = TestSubscriber.create(); + + createObservableThrowingUnknownCause().subscribe(ts); + + ts.assertError(TestExceptionWithUnknownCause.class); + + Throwable receivedError = onErrorThrowableRef.get(); + assertNotNull(receivedError); + assertTrue(receivedError.getMessage().contains("cause set to null")); + } finally { + RxJavaHooks.reset(); + } + } + static Single createSingle() { return Single.just(1).map(new Func1() { @Override