Frecuentemente he visto excepciones lanzadas por frameworks o bibliotecas como Hibernate o Spring como la causa (confundiendo la GUI del depurador en el proceso).
Siempre me pregunté por qué lo hicieron, ya que parece una mala idea. Y hoy en realidad causó un problema cuando estaba tratando de serializar uno para JSON: bam, enless cycle.
Así que investigué un poco más allá:
En el código fuente de Throwable
(todo el código fuente que aparece aquí es de JDK 1.7) tenemos:
/**
* The throwable that caused this throwable to get thrown, or null if this
* throwable was not caused by another throwable, or if the causative
* throwable is unknown. If this field is equal to this throwable itself,
* it indicates that the cause of this throwable has not yet been
* initialized.
*
* @serial
* @since 1.4
*/
private Throwable cause = this;
Ahora se reunió específicamente el problema con una clase de excepción que extendió RuntimeException
, así que fui desde allí. Uno de los constructores de RuntimeException
:
/** Constructs a new runtime exception with the specified detail message.
* The cause is not initialized, and may subsequently be initialized by a
* call to {@link #initCause}.
*
* @param message the detail message. The detail message is saved for
* later retrieval by the {@link #getMessage()} method.
*/
public RuntimeException(String message) {
super(message);
}
Constructor de Exception
llamado por el anterior:
/**
* Constructs a new exception with the specified detail message. The
* cause is not initialized, and may subsequently be initialized by
* a call to {@link #initCause}.
*
* @param message the detail message. The detail message is saved for
* later retrieval by the {@link #getMessage()} method.
*/
public Exception(String message) {
super(message);
}
Constructor de Throwable
llamados por lo anterior:
/**
* Constructs a new throwable with the specified detail message. The
* cause is not initialized, and may subsequently be initialized by
* a call to {@link #initCause}.
*
* <p>The {@link #fillInStackTrace()} method is called to initialize
* the stack trace data in the newly created throwable.
*
* @param message the detail message. The detail message is saved for
* later retrieval by the {@link #getMessage()} method.
*/
public Throwable(String message) {
fillInStackTrace();
detailMessage = message;
}
fillInStackTrace
es un método nativo y no parece modificar el campo de causa.
Como puede ver, a menos que se llame posteriormente al método initCause
, el campo cause
nunca cambia del valor original de .
Conclusión: si no un nuevo Exception
(o una de las muchas muchas subclases que existen en la naturaleza y no invalidar este comportamiento) usando un constructor que no toma un argumento cause
, y lo hace crear llama al método initCause
, la causa de la excepción será ella misma.
Supongo que debería ser una ocurrencia muy común.
Mala práctica de codificación, si la excepción ya es la causa, no tiene que definir una causa principal. –
Claro ... si * desea * crear una dependencia circular de la que no haya escapatoria. De alguna manera estoy pensando que el código no está haciendo lo que crees que está haciendo. –
También es una mala práctica, pero puede suceder que un código atrape la Excepción X y arroje una nueva Excepción X, con la anterior como causa. Entonces pueden parecer similares, pero en realidad son excepciones diferentes. – Luciano