检查某个异常类型是否是嵌套异常中的原因(等等…)的最佳方法?
-
03-07-2019 - |
题
我正在编写一些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:强> 好吧,我想有一个实用方法真的没有绕过:-)感谢所有回复的人!
解决方案
为什么要避免 getCause
。当然,您可以自己编写一个执行任务的方法,例如:
public static boolean isCause(
Class<? extends Throwable> expected,
Throwable exc
) {
return expected.isInstance(exc) || (
exc != null && isCause(expected, exc.getCause())
);
}
其他提示
如果你正在使用 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
}
我认为除了通过getCause图层调用之外别无选择。如果你看一下Spring NestedRuntimeException的源代码,你提到它是如何实现的。
模仿是最真诚的奉承形式。 基于快速检查源,这正是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现在在做什么,你应该研究现有的代码(无论何时是)。
好吧,我认为如果不调用 getCause()
就没有办法做到这一点。你认为这样做很难实现实用程序类:
public class ExceptionUtils {
public static boolean wasCausedBy(Throwable e, Class<? extends Throwable>) {
// call getCause() until it returns null or finds the exception
}
}
您可以使用guava执行此操作:
FluentIterable.from(Throwables.getCausalChain(e))
.filter(Predicates.instanceOf(ConstraintViolationException.class))
.first()
.isPresent();
基于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);