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

发布于 2024-07-15 01:45:35 字数 797 浏览 13 评论 0原文

我正在编写一些 JUnit 测试来验证是否引发了 MyCustomException 类型的异常。 然而,该异常多次包装在其他异常中,例如,在 InvocableTargetException 中,而后者又被包装在 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。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

望喜 2024-07-22 01:45:35

如果您使用 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
}

If you are using Apache Commons Lang, then you can use the following:

(1) When the cause should be exactly of the specified type

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

(2) When the cause should be either of the specified type or its subclass type

if (ExceptionUtils.indexOfType(exception, ExpectedException.class) != -1) {
    // exception is or has a cause of type ExpectedException.class or its subclass
}
淡写薰衣草的香 2024-07-22 01:45:35

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

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

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())
   );
}
国际总奸 2024-07-22 01:45:35

我认为你别无选择,只能通过 getCause 的层层调用。 如果您查看您提到的 Spring NestedRuntimeException 的源代码,这就是它的实现方式。

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.

美人如玉 2024-07-22 01:45:35

模仿是最真诚的奉承形式。 基于快速检查来源,这正是 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;
    }
}

警告:上面是截至 2009 年 3 月 4 日的代码,因此,如果您确实想知道 Spring 现在在做什么,您应该研究当前存在的代码(无论何时)。

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).

叫思念不要吵 2024-07-22 01:45:35

您可以使用番石榴来做到这一点:

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

You can do this using guava:

FluentIterable.from(Throwables.getCausalChain(e))
                        .filter(Predicates.instanceOf(ConstraintViolationException.class))
                        .first()
                        .isPresent();
雄赳赳气昂昂 2024-07-22 01:45:35

根据 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);

Based on Patrick Boos answer:
If you using Apache Commons Lang 3 you can check:

indexOfThrowable: Returns the (zero based) index of the first Throwable that matches the specified class (exactly) in the exception chain. Subclasses of the specified class do not match

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

or

indexOfType: Returns the (zero based) index of the first Throwable that matches the specified class or subclass in the exception chain. Subclasses of the specified class do match

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

Example for multiple types with Java 8:

Class<? extends Throwable>[] classes = {...}
boolean match = Arrays.stream(classes)
            .anyMatch(clazz -> ExceptionUtils.indexOfType(e, clazz) != -1);
转角预定愛 2024-07-22 01:45:35

您可以使用 Apache Commons Lang 库中的 ExceptionUtils.hasCause(ex, type) 。

You can use ExceptionUtils.hasCause(ex, type) from the Apache Commons Lang library.

待"谢繁草 2024-07-22 01:45:35

好吧,我认为如果不调用 getCause() 就没有办法做到这一点。 如果您认为它很丑陋,请实现一个实用程序类来执行此操作:

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

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
     }
}
爱的故事 2024-07-22 01:45:35

如果感兴趣的异常肯定是“根本”原因,则 assertj 是查找 getRootCause 检查的另一个位置,尽管从今天的源代码来看,它似乎有可能其他答案中讨论了无限循环问题。

If the exception of interest is definitely the "root" cause, assertj is an additional place to find a getRootCause check, although from the source today, it appears to have the possible infinite loop problem discussed in other answers.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文