Search This Blog

Sunday 30 June 2013

ExceptionUtils

One of the most commonly used features in Java is Exceptions. I have always used it- throwing, catching and sometimes crashing code with them. I recently had a requirement where I needed to convert a stack trace to a String.
As a part of my investigation I opened the source code to have a look at the classes in the exception hierarchy.
I first opened the Exception class:
public class Exception extends Throwable {
The class (as of Java 6) is purely composed of constructors. It does not override a single method. Same is the case with error subclass. So all the behavior is defined in the Throwable class:
public class Throwable implements Serializable {

   /**
    * Native code saves some indication of the stack backtrace in this slot.
    */
   private transient Object backtrace;
   private String detailMessage;

   /**
    * 
    * If this field is equal to this throwable itself, 
    * it indicates that the cause of this throwable has not yet been
    * initialized.
    */

   private Throwable cause = this;
   private StackTraceElement[] stackTrace;
   // ....
}
From the code docs:
  • The stackTrace member contains a snapshot of the execution stack of the throwable's thread at the time it was created. 
  • The detailMessage is simply a string that gives more information about the error. 
  • The interesting member is the cause variable. It is also of type Throwable. So the Throwable object can internally refer to another Throwable object.
From the code comments:
A throwable can contain a cause: another throwable that 
caused this throwable to get thrown. The cause facility 
is new in release 1.4. It is also known as the chained
exception facility, as the cause can, itself, have a cause, 
and so on, leading to a "chain" of exceptions, each caused 
by another.
This is the reason why we can do this:
public static void main(final String[] args) {
      throw new RuntimeException("Runtime Exception!!", 
            new Exception("Exception!!", 
                  new Throwable("Throwable !!")));
   }
The output would be:
Exception in thread "main" java.lang.RuntimeException: Runtime Exception!!
at test.exception.TestClient.main(TestClient.java:6)
Caused by: java.lang.Exception: Exception!!
... 1 more
Caused by: java.lang.Throwable: Throwable !!
... 1 more
Coming back to my requirement, I needed to get the stack trace as a string. Before I could start on it,I found a ready made solution:
public class TestException {
   public static void main(final String[] args) {

      try {
         throw new RuntimeException("Runtime Exception!!",
               new Exception("Exception!!", 
                     new Throwable("Throwable !!")));
      } catch (final Exception e) {
         System.out.println(ExceptionUtils.getStackTrace(e));
      }

   }
}
I used the ExceptionUtils class from commons lang library. The class includes a method that reads the stack trace and returns it as a string. The output is as below:
java.lang.RuntimeException: Runtime Exception!!
 at TestException.main(TestException.java:7)
Caused by: java.lang.Exception: Exception!!
 ... 1 more
Caused by: java.lang.Throwable: Throwable !!
 ... 1 more
As seen a matching stack trace was obtained for our use as a String. The ExceptionUtils class provides utility methods for working with Throwable instances. I decided to try some more methods:
public static void main(final String[] args) {
      try {
         throw new RuntimeException("Runtime Exception!!",
               new Exception("Exception!!",
                     new Throwable("Throwable !!")));

      } catch (final Exception e) {
         System.out.println(" getMessage : " + ExceptionUtils.getMessage(e));
         System.out.println(" getRootCauseMessage : " + ExceptionUtils.getRootCauseMessage(e));
         System.out.println(" getThrowableCount : " + ExceptionUtils.getThrowableCount(e));
         System.out.println(" getThrowables : ");

         for (final Throwable element : ExceptionUtils.getThrowables(e)) {
            System.out.println(element.getMessage());
         }

         System.out.println(" indexOfThrowable(e,RuntimeException.class) : "
               + ExceptionUtils.indexOfThrowable(e, RuntimeException.class));
         System.out.println(" indexOfThrowable(e,Throwable.class) : "
               + ExceptionUtils.indexOfThrowable(e, Throwable.class));
         System.out.println(" indexOfType(e,RuntimeException.class) : "
               + ExceptionUtils.indexOfType(e, RuntimeException.class));
         System.out.println(" indexOfType(e,Throwable.class) : " + ExceptionUtils.indexOfType(e, Throwable.class));
         System.out.println(" getCause : " + ExceptionUtils.getCause(e));
         System.out.println(" getRootCause : " + ExceptionUtils.getRootCause(e));
         System.out.println(" getRootCauseStackTrace : ");

         for (final String element : ExceptionUtils.getRootCauseStackTrace(e)) {
            System.out.println(element);
         }
      }
   }
The getMessage method will return us the message of the exception. getRootCauseMessage method on the other hand will traverse the exception chain and return us the message associated with the innermost cause variable. Interestingly when we do not set the cause property of an exception class, the cause reference points to the object itself. It is not set to null.
private Throwable cause = this;//if not set, then by default refer to this object
The getThrowableCount will give us the total number of throwables present in the Exception(1 indexed). If we need to access these throwable objects than we have the getThrowables method.
If I were to run the above code:
getMessage : RuntimeException: Runtime Exception!!
 getRootCauseMessage : Throwable: Throwable !!
 getThrowableCount : 3
 getThrowables : 
Runtime Exception!!
Exception!!
Throwable !!
 indexOfThrowable(e,RuntimeException.class) : 0
 indexOfThrowable(e,Throwable.class) : 2
 indexOfType(e,RuntimeException.class) : 0
 indexOfType(e,Throwable.class) : 0
 getCause : java.lang.Exception: Exception!!
 getRootCause : java.lang.Throwable: Throwable !!
 getRootCauseStackTrace : 
java.lang.Throwable: Throwable !!
 [wrapped] java.lang.Exception: Exception!!
 [wrapped] java.lang.RuntimeException: Runtime Exception!!
 at TestException.main(TestException.java:9)
The indexOfThrowable method indicates the first occurrence of the specified class in the exception chain if any. As seen the method returned 0 for RuntimeException as it is the outermost in the thrown set. Similarly it returned 2 for Throwable. The method does not match on subclass.
If we want to return any exception that satisfies the instanceof rule than we have the indexOfType method. The getCause method will return the value referred to by the cause field of the outermost exception.
If we want the cause of the innermost exception we use the getRootCause method.
The last method was the getRootCauseStackTrace. As per the method doc:
Creates a compact stack trace for the root cause of the supplied Throwable. 
The output of this method is consistent across JDK versions. It consists 
of the root exception followed by each of its wrapping exceptions separated 
by '[wrapped]'. Note that this is the opposite order to the JDK1.4 display

No comments:

Post a Comment