practice handling exceptions example error custom controlleradvice best java spring exception exception-handling nested-exceptions

java - handling - spring boot custom error response



¿La mejor forma de verificar si un determinado tipo de excepción fue la causa(de una causa, etc.) en una excepción anidada? (7)

¿Por qué querrías evitar getCause ? Por supuesto, puedes escribirte un método para realizar la tarea, algo como:

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

Estoy escribiendo algunas pruebas de JUnit que verifican que se MyCustomException una excepción de tipo MyCustomException . Sin embargo, esta excepción está envuelta en otras excepciones varias veces, por ejemplo, en una InvocationTargetException, que a su vez está envuelta en una RuntimeException.

¿Cuál es la mejor manera de determinar si MyCustomException causó de alguna manera la excepción que detecté? Me gustaría hacer algo como esto (ver subrayado):

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

Me gustaría evitar llamar a getCause() a algunas "capas" de profundidad, y otras alternativas similares feas. ¿Hay alguna manera mejor?

(Al parecer, Spring tiene NestedRuntimeException.contains(Class) , que hace lo que quiero, pero no estoy usando Spring).

CERRADO: De acuerdo, creo que realmente no hay manera de evitar un método de utilidad :-) ¡Gracias a todos los que respondieron!


Bueno, creo que no hay manera de hacer esto sin llamar a getCause() . Crees que es feo implementar una clase de utilidad para hacer esto:

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


En base a la respuesta de Patrick Boos: Si está utilizando Apache Commons Lang 3, puede verificar:

indexOfThrowable : devuelve el índice (basado en cero) del primer Throwable que coincide con la clase especificada ( exactamente ) en la cadena de excepciones. Las subclases de la clase especificada no coinciden

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

o

indexOfType : devuelve el índice (basado en cero) del primer Throwable que coincide con la clase o subclase especificada en la cadena de excepciones. Las subclases de la clase especificada coinciden

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

Ejemplo para múltiples tipos con Java 8:

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


La imitación es la forma más sincera de adulación. Basado en una inspección rápida de la fuente , esto es exactamente lo que hace la excepción 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 : El código anterior es el 4 de marzo de 2009, por lo tanto, si realmente quiere saber qué está haciendo Spring en este momento, debe investigar el código tal como existe en la actualidad (siempre que sea).


No creo que tengas otra opción que llamar a través de las capas de getCause. Si observa el código fuente de la excepción NestedRuntimeException de Spring que menciona, así es como se implementa.


Puedes hacerlo usando guayaba:

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


Si está utilizando Apache Commons Lang , puede usar lo siguiente:

(1) Cuando la causa debe ser exactamente del tipo especificado

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

(2) Cuando la causa debe ser del tipo especificado o su tipo de subclase

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