중첩 된 예외에서 특정 예외 유형이 원인 (원인 등)인지 확인하는 가장 좋은 방법?
-
03-07-2019 - |
문제
나는 유형의 예외를 확인하는 Junit 테스트를 작성하고 있습니다. MyCustomException
던져졌다. 그러나이 예외는 다른 예외에 여러 번, 예를 들어 invocationtargetexception에서 랩핑됩니다.
mycustomexception이 어떻게 든 내가 실제로 잡는 예외를 유발했는지 여부를 결정하는 가장 좋은 방법은 무엇입니까? 나는 이런 일을하고 싶습니다 (밑줄 참조) :
try { doSomethingPotentiallyExceptional(); fail("Expected an exception."); } catch (RuntimeException e) { if (!e.
wasCausedBy(MyCustomException.class) fail("Expected a different kind of exception."); }
전화를 피하고 싶습니다 getCause()
몇 개의 "레이어"깊이와 비슷한 못생긴 작업 계약. 더 좋은 방법이 있습니까?
(분명히, 봄은 있습니다 NestEdRuntImeexception.contains (클래스), 내가 원하는 것을하는 일 - 그러나 나는 봄을 사용하지 않습니다.)
닫은:좋아, 유틸리티 방법을 돌아 다니는 것이 실제로 없을 것 같아요 :-) 대답 한 모든 분들께 감사드립니다!
해결책
왜 피하고 싶습니까? 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
}
나는 당신이 선택의 여지가 없다고 생각합니다. 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;
}
}
경고: 위는 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: 지정된 클래스와 일치하는 첫 번째 던지기 가능의 (제로 기반) 색인을 반환합니다 (바로 그거죠) 예외 체인에서. 지정된 클래스의 서브 클래스가 일치하지 않습니다
if (ExceptionUtils.indexOfThrowable(e, clazz) != -1) {
// your code
}
또는
indexoftype: 지정된 것과 일치하는 첫 번째 던지기 가능의 (제로 기반) 색인을 반환합니다. 클래스 또는 하위 클래스 예외 체인에서. 지정된 클래스의 서브 클래스가 일치합니다
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);