< prev index next >

src/java.base/share/classes/java/lang/NullPointerException.java

Print this page
rev 59936 : 8248476: No helpful NullPointerException message after calling fillInStackTrace
Summary: reported by christoph.dreis@freenet.de
Reviewed-by:

@@ -68,10 +68,33 @@
      */
     public NullPointerException(String s) {
         super(s);
     }
 
+    private static final String MUST_COMPUTE_EXTENDED_MESSAGE =
+        "MUST_COMPUTE_EXTENDED_MESSAGE";
+    private static final String NO_EXTENDED_MESSAGE =
+        "NO_EXTENDED_MESSAGE";
+    private transient String extendedMessage;
+
+    /**
+     * {@inheritDoc}
+     */
+    public synchronized Throwable fillInStackTrace() {
+        // After the stack trace is changed the extended NPE algorithm
+        // will compute a wrong message. So compute it beforehand.
+        if (extendedMessage == null) {
+            // The first call. Don't compute the message, we'll
+            // do it lazily.
+            extendedMessage = MUST_COMPUTE_EXTENDED_MESSAGE;
+        } else if (extendedMessage == MUST_COMPUTE_EXTENDED_MESSAGE) {
+            // The second call.
+            extendedMessage = getExtendedNPEMessage();
+        }
+        return super.fillInStackTrace();
+    }
+
     /**
      * Returns the detail message string of this throwable.
      *
      * <p> If a non-null message was supplied in a constructor it is
      * returned. Otherwise, an implementation specific message or

@@ -87,17 +110,32 @@
      * @return the detail message string, which may be {@code null}.
      */
     public String getMessage() {
         String message = super.getMessage();
         if (message == null) {
-            return getExtendedNPEMessage();
+            synchronized(this) {
+                if (extendedMessage == MUST_COMPUTE_EXTENDED_MESSAGE) {
+                    // Only the original stack trace was filled in. Message will
+                    // compute correctly.
+                    extendedMessage = getExtendedNPEMessage();
+                }
+                if (extendedMessage != NO_EXTENDED_MESSAGE) {
+                    return extendedMessage;
+                }
+            }
         }
         return message;
     }
 
     /**
      * Get an extended exception message. This returns a string describing
-     * the location and cause of the exception. It returns null for
+     * the location and cause of the exception. It returns NO_EXTENDED_MESSAGE for
      * exceptions where this is not applicable.
      */
-    private native String getExtendedNPEMessage();
+    private String getExtendedNPEMessage() {
+        String msg = getExtendedNPEMessage0();
+        if (msg == null) return NO_EXTENDED_MESSAGE;
+        return msg;
+    }
+
+    private native String getExtendedNPEMessage0();
 }
< prev index next >