If fillInStackTrace is called on the exception, the original stack
trace is lost. The helpful NPE algorithm can no more compute
the proper message. Also, the check for messages created in
user code fails. Thus, we must check for fillInStackTrace and
suppress the message if it was called.
This problem was reported and analyzed by Christoph Dreis:
http://mail.openjdk.java.net/pipermail/hotspot-runtime-dev/2020-June/040450.html
His example of the wrong message:
public class Main {
public static void main(String[] args) {
NullPointerException ex = new NullPointerException();
Throwable throwable = ex.fillInStackTrace();
System.out.println(throwable);
}
}
He sees the following output:
java.lang.NullPointerException: Cannot invoke "java.lang.NullPointerException.fillInStackTrace()" because "ex" is null
which is wrong. As the exception is created explicitly via new, it should not
and can not get a proper message by this algorithm.
*Fix*
Various approaches were discussed.
Finally we decided to fix this in NullPointerException.java.
NullPointerException now overwrites Throwable::fillInStackTrace() and
precomputes the message before the original backtrace is overwritten.
The message is stored in a private field, and returned by getMessage().
This allowed a little enhancement: If getMessage is called repeatedly,
the message is no more recomputed on each call. This also guarantees
that each getMessage call returns the very same String object.