views:

246

answers:

4

I am writing some JUnit tests that verify that an exception of type MyCustomException is thrown. However, this exception is wrapped in other exceptions a number of times, e.g. in an InvocationTargetException, which in turn is wrapped in a RuntimeException.

What's the best way to determine whether MyCustomException somehow caused the exception that I actually catch? I would like to do something like this (see underlined):


try {
    doSomethingPotentiallyExceptional();
    fail("Expected an exception.");
} catch (RuntimeException e) {
     if (!e.wasCausedBy(MyCustomException.class)
        fail("Expected a different kind of exception.");
}

I would like to avoid calling getCause() a few "layers" deep, and similar ugly work-arounds. Is there a nicer way?

(Apparently, Spring has NestedRuntimeException.contains(Class), which does what I want - but I'm not using Spring.)

CLOSED: OK, I guess there's really no getting around a utility method :-) Thanks to everybody who replied!

+4  A: 

I don't think you have any choice but to call through the layers of getCause. If you look at the source code for the Spring NestedRuntimeException that you mention that is how it is implemented.

Mark
+6  A: 

Why would you want to avoid getCause. You can, of course, write yourself a method to perform the task, something like:

public static boolean isCause(
    Class<? extends Throwable> expected,
    Throwable exc
) {
   return expected.isInstance(exc) || (
       exc != null && isCause(expected, exc.getCause())
   );
}
Tom Hawtin - tackline
A: 

Well, I think there's no way to do this without calling getCause(). It you think it's ugly implement a utility class for doing this:

public class ExceptionUtils {
     public static boolean wasCausedBy(Throwable e, Class<? extends Throwable>) {
         // call getCause() until it returns null or finds the exception
     }
}
bruno conde
+1  A: 

Imitation is the sincerest form of flattery. Based on a quick inspection of the source, this is exactly what NestedRuntimeException does:

/**
 * Check whether this exception contains an exception of the given type:
 * either it is of the given class itself or it contains a nested cause
 * of the given type.
 * @param exType the exception type to look for
 * @return whether there is a nested exception of the specified type
 */
public boolean contains(Class exType) {
    if (exType == null) {
        return false;
    }
    if (exType.isInstance(this)) {
        return true;
    }
    Throwable cause = getCause();
    if (cause == this) {
        return false;
    }
    if (cause instanceof NestedRuntimeException) {
        return ((NestedRuntimeException) cause).contains(exType);
    }
    else {
        while (cause != null) {
            if (exType.isInstance(cause)) {
                return true;
            }
            if (cause.getCause() == cause) {
                break;
            }
            cause = cause.getCause();
        }
        return false;
    }
}

CAVEAT: The above is the code as of 4 March 2009 so, if you really want to know what Spring is doing right now, you should research the code as it exists today (whenever that is).

Bob Cross