Single.blockingGet() -> BlockingMultiObserver/ExceptionCatcher should not wrap Exceptions?
See original GitHub issueVersion 2.1.9
Assuming this code:
return Single.error(new IllegalArgumentException("I'm the cause"));
I think thereās a issue in the design of ExceptionCatcher.wrapOrThrow. When calling blockingGet(), it wraps any instance of Exception but leaves Runtime and Error as-is. So basically you throw an exception somewhere but the Rx framework bubbles it up with a wrapper you have to unwrap to get your initial cause.
/**
* If the provided Throwable is an Error this method
* throws it, otherwise returns a RuntimeException wrapping the error
* if that error is a checked exception.
* @param error the error to wrap or throw
* @return the (wrapped) error
*/
public static RuntimeException wrapOrThrow(Throwable error) {
if (error instanceof Error) {
throw (Error)error;
}
if (error instanceof RuntimeException) {
return (RuntimeException)error;
}
return new RuntimeException(error);
}
Itās especially painful in unit tests, where you catch an Exception and have to sometime exception.getCause()
and sometime only exception
is good enough. So if your Single would be consumed by a Subscriber but you want to test it by blockingGet to ease your life, you end up with an extra coating of exception that wonāt be there in your real scenario, leading to glue code in tests that donāt behave like the original code.
Single<String> anySingle = Single.error(new IOException("I'm the cause"));
try {
anySingle.blockingGet();
}
// catch (RuntimeException e) {
// Should fail, but will pass
// Assert.assertTrue(e.getCause() instanceof IOException);
// }
catch (Exception e) {
// Should pass, but will fail
Assert.assertTrue(e instanceof IOException);
}
The caller code that invokes the ExceptionCatcher is BlockingMultiObserver.
public T blockingGet() {
if (getCount() != 0) {
try {
BlockingHelper.verifyNonBlocking();
await();
} catch (InterruptedException ex) {
dispose();
throw ExceptionHelper.wrapOrThrow(ex);
}
}
Throwable ex = error;
if (ex != null) {
throw ExceptionHelper.wrapOrThrow(ex);
}
return value;
}
I believe that the blockingGet() method should actually throws Exception
Is there any workaround for that?
Thank you very much
Issue Analytics
- State:
- Created 5 years ago
- Comments:9 (7 by maintainers)
Yep, Jesse sent it too, what a facepalm then š¤¦āāļø
It was even discussed before in RxJava
Well, that was a fun exercise I guessā¦
Soo, I personally thank everyone (sarcasm) in this issue because you got me to interested and itās 5:34 amā¦
Iāve built 0-deps java library that allows throwing checked exceptions without wrapping and without declaring it in method description
https://github.com/artem-zinnatullin/java-uncheck-exceptions
Itās not on maven central yet, but jar is available on releases page (or you can build it, see README)
TL;TR: yep, in Java source code you canāt throw checked exception without wrapping or declaring it. But in Java bytecode you can, so I do it from bytecode (you can read more in README and check implementation).
If you like it, we can integrate that class into RxJava and maybe Guava later.