Я часто видел исключения, генерируемые инфраструктурами или библиотеками, такими как Hibernate или Spring, ссылающиеся на себя как на причину (путая графический интерфейс отладчика в процессе).
Я всегда удивлялся, почему они это сделали, так как кажетсятакая плохая идея.И сегодня это на самом деле вызвало проблему, когда я пытался сериализовать один в JSON: bam, enless cycle.
Так что я исследовал это немного дальше:
В исходном коде Throwable
(весь приведенный здесь исходный код взят из JDK 1.7) у нас есть это:
/**
* 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;
Теперь я специально столкнулся с проблемой с классом исключений, который расширил RuntimeException
, поэтому я пошел оттуда.Один из конструкторов 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);
}
Конструктор Exception
, называемый выше:
/**
* 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);
}
Конструктор Throwable
, вызываемый выше:
/**
* 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
является нативным методом и, похоже, не изменяет поле причины.
Итак, как вы можете видеть, если только метод initCause
не вызывается впоследствии, cause
поле никогда не изменяется от исходного значения this
.
Вывод: если вы создаете новый Exception
(или один из множества подклассов, которые существуют в wild и не переопределяют это поведение)используя конструктор, который не принимает аргумент cause
, и вы не вызываете метод initCause
, причиной исключения будет сама!
Так что я думаю, это должно сделать его оченьобычное явление.