Guava contains the very useful class Throwables, which has the very useful method getRootCause. Given an exception, this method will return the original cause by following the cause hierarchy until it finds the first exception which has no underlying cause. For example:

try {
  throw new IOException(new IllegalArgumentException(new NumberFormatException("Foo")));
} catch (Exception e) {
  assertTrue(Throwables.getRootCause(e) instanceof NumberFormatException);
}

If the given exception has no cause, the exception itself is returned:

try {
  throw new NumberFormatException("Foo");
} catch (Exception e) {
  assertTrue(Throwables.getRootCause(e) instanceof NumberFormatException);
}

Another method that can sometimes be useful is getStackTraceAsString, which will return all the stack trace of the given Throwable as a string, suitable for storing it into a log.

Finally, similarly to getRootCause, there’s a getCausalChain method which will return the cause hierarchy as a List<Throwable>.