Suppose I am handling FooException
and BarException
occurs. Let's assume they are both unchecked exceptions.
What I want to see in the stacktrace is:
com.bar.BarException: Bar Message
at com.baz.BazCode(BazCode.java:123)
...
Caused by: com.foo.FooException: Foo Message
at com.baz.BazCode(BazCode.java:321)
....
Caused by: ...
However, by default, all record of FooException
will be erased from the stacktrace. For example:
// In a class written by me
/**
* ...
* @throws FooException if foo happens
* @throws BarException if bar happens
*/
public void upperFrame() {
try {
foo.doSomething();
} catch (FooException foo) {
bar.doSomethingElse();
}
}
// In class Bar (not written by me)
public void doSomethingElse() {
if (someConditionWhichHappensToBeTrueInThisScenario()) {
throw new BarException("Hello Bar World"); // At this point, FooException gets erased from the stack trace
}
}
If BarException
has a (message, cause)
constructor then I can follow a rather crude kind of "manual cloning" process to achieve my goal:
try {
foo.doSomething();
} catch (FooException foo) {
try {
bar.doSomethingElse();
} catch (BarException bar) {
BarException bar2 = new BarException(bar.getMessage(), foo);
bar2.setStackTrace(bar.getStackTrace());
throw bar2;
}
}
However, if BarException
does not have such a constructor (for example ClassCastException
) then I am reduced to doing things like this:
try {
foo.doSomething();
} catch (FooException foo) {
try {
bar.doSomethingElse();
} catch (BarException bar) {
RuntimeException e = new RuntimeException("com.bar.BarException: " + bar.getMessage(), foo);
e.setStackTrace(bar.getStackTrace());
throw e;
}
}
This is dangerous because e
has the wrong type and so may not be correctly handled by higher frames.
Is there a "best-practice" way to handle this situation?
One solution is to use the Throwable#initCause(Throwable)
method:
bar.initCause(foo);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With