Die beste Weg, um zu überprüfen, ob eine bestimmte Ausnahmetyp war die Ursache (eine Ursache, etc ...) in einer verschachtelten Ausnahme?

StackOverflow https://stackoverflow.com/questions/610628

Frage

ich einige JUnit-Tests schreibe, die eine Ausnahme vom Typ MyCustomException überprüfen, ob geworfen wird. Allerdings ist diese Ausnahme in anderen Ausnahmen mehr Male gewickelt, z.B. in einem InvocationTargetException, der wiederum in einem Runtime gewickelt.

Was ist der beste Weg, um zu bestimmen, ob MyCustomException irgendwie die Ausnahme verursacht, dass ich tatsächlich fangen? Ich möchte so etwas tun (siehe unterstrichene):


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

Ich möchte ein paar „Schichten“ tief und ähnliche hässliche Umgehungen Aufruf getCause() zu vermeiden. Gibt es eine schönere Art und Weise?

(Offenbar hat Frühling NestedRuntimeException.contains (Klasse) , das tut, was ich will -. aber ich bin mit Spring nicht)

GESCHLOSSEN: OK, ich denke, es ist wirklich nicht ist um eine Hilfsmethode :-) Danke an alle bekommen, die! Antwortete

War es hilfreich?

Lösung

Warum wollen Sie getCause vermeiden. Sie können natürlich, schreiben Sie sich ein Verfahren um die Aufgabe auszuführen, so etwas wie:

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

Andere Tipps

Wenn Sie mit Apache Commons Lang , dann können Sie die folgenden Befehle verwenden:

(1) Wenn die Ursache sollte genau der angegebenen Art sein

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

(2) Wenn die Ursache sollte entweder den angegebenen Typs oder seine Unterklasse Typ

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

Ich glaube nicht, dass Sie keine Wahl, sondern durch die Schichten des getCause zu nennen. Wenn Sie sich den Quellcode für den Frühling NestedRuntimeException aussehen, dass Sie erwähnen, das ist, wie es umgesetzt wird.

Nachahmung ist die aufrichtigste Form der Schmeichelei. Basierend auf einer schnellen Prüfung von die Quelle , das ist genau das, was NestedRuntimeException tut:

/**
 * 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 : Die oben ist der Code als vom 4. März 2009 so, wenn Sie wirklich wissen wollen, was Frühling gerade jetzt tun, sollten Sie den Code erforschen, wie es heute existiert (wann auch immer das ist ).

Nun, ich glaube, es gibt keinen Weg, diese getCause() ohne Aufruf zu tun. Es Sie denken, es ist hässlich ein Dienstprogramm Klasse implementieren, dies zu tun:

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

Sie können dieses mit Guave tun:

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

Auf der Grundlage von Patrick Boos Antwort: Wenn Sie Apache Commons Lang 3 verwenden, können Sie überprüfen:

indexOfThrowable : Gibt den (Null basierend) Index des ersten Throwable, die die angegebene Klasse entspricht ( genau ) in der Ausnahmekette. Subklassen der angegebenen Klasse nicht übereinstimmen

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

oder

indexOfType : Gibt den (Null basierend) Index des ersten Throwable, die die angegebene Klasse oder Unterklasse übereinstimmt in der Ausnahmekette. Subklassen der angegebenen Klasse passen

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

Beispiel für mehrere Typen mit Java 8:

Class<? extends Throwable>[] classes = {...}
boolean match = Arrays.stream(classes)
            .anyMatch(clazz -> ExceptionUtils.indexOfType(e, clazz) != -1);
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top