ServletException rootCause vs cause

27 11 2007

A recent failed test-case when testing some code against different Servlet API libraries has made me look more closely at how ServletException deals with exception chaining.

I’d pretty much taken this for granted before, but it turns out to be not entirely trivial. So it seems worth spelling out exactly how it works, and what steps you need to take to use it safely.

The underlying problem is that the ServletException class pre-dates the introduction of standardised support for a “cause” within Throwable. As with many such classes from before the introduction of “cause”, ServletException provides its own mechanism for exception chaining – in its own case, a “rootCause” property.

Since the introduction of standard “cause” support in Throwable, ServletException thus has both its own “rootCause” property and the inherited “cause” property. However, the relationship between these two mechanisms is left entirely unspecified, with the Javadoc for ServletException’s constructor and “getRootCause” methods making no mention of whether or how they interact with the inherited “cause” mechanism.

The result is that the interaction between “rootCause” and “cause” may differ between Servlet API implementations, and care may be necessary when populating these properties.

Specifically:

  • ServletException provides constructors that take a “rootCause”, together with a “getRootCause” method that returns it, as well as other constructors that do not take a “rootCause” and for which “getRootCause” returns null.
  • ServletException’s underlying Throwable base class provides constructors that take a “cause” and other constructors that do not, plus an “initCause” method that can be used to populate the cause after construction if and only if it is not already set, together with a “getCause” method that returns the “cause” (if any).
  • ServletException does not specify whether supplying a “rootCause” also populates its “cause” or leaves it unpopulated. Different Servlet API implementations are potentially free to handle this differently.
  • ServletException does not specify whether setting a “cause” via its “initCause” method also sets its “rootCause” (and if so, whether this is only permitted if no “rootCause” was supplied on construction, or whether it can be called even if a “rootCause” is already present). Different Servlet API implementations are potentially free to handle this differently.

So when you’re creating a ServletException with an underlying cause, this leaves you not knowing:

  • Whether to just supply the cause to the ServletException’s constructor as its “rootCause” (on the basis that this should “obviously” take the given value as being both the “rootCause” and the “cause”).
  • Or whether to also call the resulting instance’s “initCause” method so as to ensure that the “cause” is populated properly (on the basis that ServletException doesn’t explicitly say that it populates the “cause”, so there is no reason to think that supplying a “rootCause” has any effect on its “cause”).
  • Or whether to ignore the ServletException “rootCause” constructor and instead just call the inherited “initCause” method (on the basis that in the absence of an existing “rootCause” this can safely be called to set the “cause” and should “obviously” also set the “rootCause”).

If you get this wrong, you can potentially end up with a ServletException that has a “rootCause” but no “cause” (and thus, for example, doesn’t show the underlying cause in its stack trace); or with a call to “initCause” that fails with an IllegalStateException due to the “cause” having already being populated during construction; or with a ServletException that has a “cause” but no “rootCause”.

This isn’t entirely academic, because Servlet API implementations do actually differ in how they handle this. For example:

  • The Servlet API 2.5 reference implementation in Glassfish does automatically populate the “cause” when you supply a “rootCause” (by passing the “rootCause” to the appropriate superclass constructor during the ServletException’s construction).
  • The reference implementations provided by Apache Tomcat for earlier Servlet API versions do not popluate the “cause” when you supply a “rootCause”, and the “cause” remains empty unless and until you populate it yourself. (Theoretically, nothing prevents the use of two entirely different exceptions as the “rootCause” and “cause”, which could get rather confusing, especially if done accidentally).
  • Other implementations and subsequent releases remain free to take either approach.
  • Although I’ve not seen, and can’t really imagine, a ServletException implementation whose “initCause” takes the “rootCause” into account (e.g fails if it is already set but otherwise populates it in addition to the “cause”), this is potentially possible and stranger things have happened.

So as far as I can see, the safest way to ensure that both the “rootCause” and “cause” are populated (without being dependent on the particular implementation of a particular Servlet API library) is to supply the underlying exception to the ServletException constructor but then also call the “initCause” method to populate the “cause” if and only if it has not already been populated by the constructor.

That is, you need code along the lines of:

ServletException e = new ServletException(message, cause);
if (e.getCause() == null) {
    e.initCause(cause);
};

Obviously, if you need to do this in multiple places it makes sense to encapsulate it in a method or to provide your own subclass of ServletException that does this in its constructor.

Advertisements

Actions

Information

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s




%d bloggers like this: