Here is one simple way to make your API users unhappy. Tell them what went wrong, but hide the location of the root cause of exceptions. You can do this with most J2EE exception classes quite easily, and it is not uncommen to find code doing exactly this in J2EE frameworks and containers. Let me start with a simple example. Before you scroll down, see if you already know what is wrong with this.
try {
// Do something
}
catch(SomeException se) {
throw new ServletException(se);
}
Conventional wisdom says that the caller of this code should be able to catch the ServletException and see the stack trace to find out where things weng wrong, or print the stack trace to see the root cause (i.e. SomeException). If you think so, you are in a little surprise.
Try calling a printStackTrace() on the ServletException. Assuming that SomeException was created with a non-null message, the stack trace will look like this.
javax.servlet.ServletException: Something occured. at ...
You won’t find a Caused by... at the end of this trace, leaving no way to figure out where the root cause occured without calling the getRootCause() method on the ServletException. So, to print the stack trace with the root cause, the caller will have to do something like the following.
try {
}
catch(ServletException se) {
if(null != se.getRootCause()) {
se.getRootCause().printStackTrace();
}
else {
// Do whatever
}
}
This is true for most exception classes released prior to J2SE1.4, and includes such common J2EE exceptions as ServletException, JspException, EJBException, JAXRPCException etc. Each of these classes have methods like getRootCause(), getLinkedCause(), getCausedByException() etc to tell the source of the cause of the exception.
The trouble with all these exceptions is that, prior to J2SE 1.4, there was no common approach of exception chaining. So, each J2EE API came up with their own way of chaining. J2SE 1.4 introduced exception chaining, and standardized propagating the cause of exceptions when throwing exceptions.
From J2SE 1.4 onwards, exception classes can call super(Throwable cause) in their constructors to take advantage of chaining. Alternatively, the constructors can call super.initCause(Throwable t) in their constructors to initialize the root cause. But since exceptions like ServletException were designed prior to J2SE 1.4, they can not take advantage of this, and the developer must remember to initialize the root cause explicitly.
The right way to throw a ServletException is as follows:
try {
// Do something
}
catch(SomeException e) {
ServletException se = new ServletException(e.getMessage());
se.initCause(e);
throw se;
}
This will properly chain the root cause with the wrapped exception, and methods like printStackTrace() will be able to traverse the chain.
One more question. Why can’t later versions of J2EE exception classes (e.g in Servlet API 2.4) take advantage of exception chaining? This cannot be done without breaking backwards compatibility. In J2SE, the root cause for an exception can be initialized once and only once. Let’s say, the constructor of ServletException is modified to initialize the root cause as follows:
public ServletException(String message, Throwable rootCause) {
super(message, rootCause);
this.rootCause = rootCause;
}
Such a change in ServletException will break code that explicitly initializes the root cause via the initCause(Throwable) method. That is because the root cause can be initialized exactly once. Check the javadoc of the initCause(Throwable) method.
I was curious to see how prevalent the wrong style is. I did a grep in Apache Struts source. Struts has over forty occurrences of ServletExceptions and over seventy occurrences of JspExceptions thrown without initializing the root cause correctly. I am sure there will be lot more such cases with commercial/closed-source software.

{ 1 comment… read it below or add one }
Hi Subbu,
Thanks for this helpful posting.
Regarding your example of the “right” way to throw a ServletException, wouldn’t it be better to also include the root cause in the constructor, like so?
try { // Do something } catch(SomeException e) { ServletException se = new ServletException(e.getMessage(), e); se.initCause(e); throw se; }This way, “legacy” code calling ServletException.getRootCause() will still work too.
Also, regarding later versions of ServletException (and other similar such exception classes), they should simply override the getCause() method like so, to take advantage of exception chaining without breaking old code:
public Throwable getCause() { return (super.getCause() == null) ? this.rootCause : super.getCause(); }In fact, the comment for Throwable.getCause() includes the following wording:
‘While it is typically unnecessary to override this method, a subclass can override it to return a cause set by some other means. This is appropriate for a “legacy chained throwable” that predates the addition of chained exceptions to Throwable.’
Why don’t the later versions of these exception types actually do this?