检查某个异常类型是否是嵌套异常中的原因(原因等等)的最佳方法?

时间:2009-03-04 13:49:53

标签: java spring exception exception-handling nested-exceptions

我正在编写一些JUnit测试,用于验证类型MyCustomException的异常是否被抛出。但是,此异常多次包含在其他例外中,例如在InvocationTargetException中,它又包含在RuntimeException中。

确定MyCustomException是否会导致我实际捕获的异常的最佳方法是什么?我想做这样的事情(见下划线):


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

我想避免将getCause()称为“层次”深层,以及类似的丑陋处理方式。有更好的方式吗?

(显然,Spring有NestedRuntimeException.contains(Class),这就是我想做的 - 但我没有使用Spring。)

CLOSED: 好吧,我想有一个实用方法真的没有绕过:-)感谢所有回复的人!

8 个答案:

答案 0 :(得分:27)

如果您使用Apache Commons Lang,则可以使用以下内容:

(1)当原因应完全符合指定类型时

if (ExceptionUtils.indexOfThrowable(exception, ExpectedException.class) != -1) {
    // exception is or has a cause of type ExpectedException.class
}

(2)当原因应该是指定类型或其子类类型

if (ExceptionUtils.indexOfType(exception, ExpectedException.class) != -1) {
    // exception is or has a cause of type ExpectedException.class or its subclass
}

答案 1 :(得分:24)

为什么要避免getCause。当然,您可以自己编写一个执行任务的方法,例如:

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

答案 2 :(得分:5)

我认为除了通过getCause图层调用之外别无选择。如果你看一下Spring NestedRuntimeException的源代码,你提到它是如何实现的。

答案 3 :(得分:2)

模仿是最真诚的奉承形式。 Based on a quick inspection of the source,这正是NestedRuntimeException的作用:

/**
 * 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 :以上是截至2009年3月4日的代码,所以,如果你真的想知道Spring现在在做什么,你应该研究现在存在的代码(无论何时是)。

答案 4 :(得分:1)

嗯,我认为没有调用getCause()就没办法做到这一点。你认为这样做很难实现实用程序类:

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

答案 5 :(得分:1)

您可以使用guava执行此操作:

FluentIterable.from(Throwables.getCausalChain(e))
                        .filter(Predicates.instanceOf(ConstraintViolationException.class))
                        .first()
                        .isPresent();

答案 6 :(得分:1)

基于Patrick Boos回答: 如果您使用Apache Commons Lang 3,您可以查看:

indexOfThrowable :返回与异常链中指定类(完全)匹配的第一个Throwable的(从零开始)索引。 指定类的子类不匹配

if (ExceptionUtils.indexOfThrowable(e, clazz) != -1) {
    // your code
}

indexOfType :返回与例外链中指定的类或子类匹配的第一个Throwable的(从零开始)索引。 指定类的子类匹配

if (ExceptionUtils.indexOfType(e, clazz) != -1) {
    // your code
}

使用Java 8的多种类型的示例:

Class<? extends Throwable>[] classes = {...}
boolean match = Arrays.stream(classes)
            .anyMatch(clazz -> ExceptionUtils.indexOfType(e, clazz) != -1);

答案 7 :(得分:0)

您可以使用ExceptionUtils.hasCause(ex, type)