Tuesday 15 February 2011

Beware of unknown root causes

All exceptions are based on the Throwable class. By default, all Throwables can have an underlying root cause. The root cause may be set in the Throwable's constructor, or after construction by calling initCause.

Having the root cause is very useful for troubleshooting. However, there is a case in which root causes can cause a problem. When a Throwable is passed over the network, it must first be serialized, and then reconstructed (deserialized) on the other end. If the root cause inside a Throwable object is not known to the receiver on the other end, then what happens? The receiver will throw a NoClassDefFoundError. Of course, this replaces the original exception with something unrelated.

One option is to define a "locked down" exception, which can hold only null as the root cause.

Example

This class is a checked exception which cannot take a root cause.

/**
  A checked exception that cannot be given a root cause.
  
  All calls to {@link #getCause()} will return <tt>null</tt>.
  This class cannot be subclassed. 
*/
public final class LockedDownException extends Exception {
  
  /**
   The sole constructor.
   No root cause can be passed to this constructor.  
  */
  public LockedDownException(String aMessage){
    super(aMessage);
  }
  
  /**
    Always coerces the root cause to <tt>null</tt>.
    
    <P>Even though the caller is allowed to call this method, it will never have any 
    effect. The caller is not allowed to set the root cause, neither during construction, 
    nor after construction.
   */
  @Override public synchronized Throwable initCause(Throwable aRootCause) {
    return super.initCause(null);
  }
  
  /** Simple test harness. */
  public static void main(String... aArgs){
    LockedDownException ex = new LockedDownException("Hello");
    ex.initCause(new IllegalArgumentException("Test"));
    System.out.println(ex.getCause()); //prints 'null'
  }
} 

See Also :

Data exception wrapping

No comments:

Post a Comment