jdk/src/share/classes/java/lang/Throwable.java

Print this page

        

*** 23,32 **** --- 23,33 ---- * questions. */ package java.lang; import java.io.*; + import java.util.*; /** * The <code>Throwable</code> class is the superclass of all errors and * exceptions in the Java language. Only objects that are instances of this * class (or one of its subclasses) are thrown by the Java Virtual Machine or
*** 100,110 **** * <pre> * try { * lowLevelOp(); * } catch (LowLevelException le) { * throw (HighLevelException) ! new HighLevelException().initCause(le); // Legacy constructor * } * </pre> * * <p>Prior to release 1.4, there were many throwables that had their own * non-standard exception chaining mechanisms ( --- 101,111 ---- * <pre> * try { * lowLevelOp(); * } catch (LowLevelException le) { * throw (HighLevelException) ! * new HighLevelException().initCause(le); // Legacy constructor * } * </pre> * * <p>Prior to release 1.4, there were many throwables that had their own * non-standard exception chaining mechanisms (
*** 191,200 **** --- 192,216 ---- * This field is lazily initialized on first use or serialization and * nulled out when fillInStackTrace is called. */ /** + * The list of suppressed exceptions, as returned by + * {@link #getSuppressedExceptions()}. + * + * @serial + * @since 1.7 + */ + private List<Throwable> suppressedExceptions = Collections.emptyList(); + + /** Caption for labeling causative exception stack traces */ + private static final String CAUSE_CAPTION = "Caused by: "; + + /** Caption for labeling suppressed exception stack traces */ + private static final String SUPPRESSED_CAPTION = "Suppressed: "; + + /** * Constructs a new throwable with <code>null</code> as its 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
*** 467,476 **** --- 483,538 ---- * } * * class LowLevelException extends Exception { * } * </pre> + * As of release 7, the platform supports the notion of + * <i>suppressed exceptions</i> (in conjunction with automatic + * resource management blocks). Any exceptions that were + * suppressed in order to deliver an exception are printed out + * beneath the stack trace. The format of this information + * depends on the implementation, but the following example may be + * regarded as typical: + * + * <pre> + * Exception in thread "main" java.lang.Exception: Something happened + * at Foo.bar(Foo.java:10) + * at Foo.main(Foo.java:5) + * Suppressed: Resource$CloseFailException: Resource ID = 0 + * at Resource.close(Resource.java:26) + * at Foo.bar(Foo.java:9) + * ... 1 more + * </pre> + * Note that the "... n more" notation is used on suppressed exceptions + * just at it is used on causes. Unlike causes, suppressed exceptions are + * indented beyond their "containing exceptions." + * + * <p>An exception can have both a cause and one or more suppressed + * exceptions: + * <pre> + * Exception in thread "main" java.lang.Exception: Main block + * at Foo3.main(Foo3.java:7) + * Suppressed: Resource$CloseFailException: Resource ID = 2 + * at Resource.close(Resource.java:26) + * at Foo3.main(Foo3.java:5) + * Suppressed: Resource$CloseFailException: Resource ID = 1 + * at Resource.close(Resource.java:26) + * at Foo3.main(Foo3.java:5) + * Caused by: java.lang.Exception: I did it + * at Foo3.main(Foo3.java:8) + * </pre> + * Likewise, a suppressed exception can have a cause: + * <pre> + * Exception in thread "main" java.lang.Exception: Main block + * at Foo4.main(Foo4.java:6) + * Suppressed: Resource2$CloseFailException: Resource ID = 1 + * at Resource2.close(Resource2.java:20) + * at Foo4.main(Foo4.java:5) + * Caused by: java.lang.Exception: Rats, you caught me + * at Resource2$CloseFailException.<init>(Resource2.java:45) + * ... 2 more + * </pre> */ public void printStackTrace() { printStackTrace(System.err); }
*** 478,573 **** * Prints this throwable and its backtrace to the specified print stream. * * @param s <code>PrintStream</code> to use for output */ public void printStackTrace(PrintStream s) { ! synchronized (s) { s.println(this); StackTraceElement[] trace = getOurStackTrace(); ! for (int i=0; i < trace.length; i++) ! s.println("\tat " + trace[i]); Throwable ourCause = getCause(); if (ourCause != null) ! ourCause.printStackTraceAsCause(s, trace); } } /** ! * Print our stack trace as a cause for the specified stack trace. */ ! private void printStackTraceAsCause(PrintStream s, ! StackTraceElement[] causedTrace) ! { ! // assert Thread.holdsLock(s); ! // Compute number of frames in common between this and caused StackTraceElement[] trace = getOurStackTrace(); ! int m = trace.length-1, n = causedTrace.length-1; ! while (m >= 0 && n >=0 && trace[m].equals(causedTrace[n])) { m--; n--; } int framesInCommon = trace.length - 1 - m; ! s.println("Caused by: " + this); ! for (int i=0; i <= m; i++) ! s.println("\tat " + trace[i]); if (framesInCommon != 0) ! s.println("\t... " + framesInCommon + " more"); ! // Recurse if we have a cause Throwable ourCause = getCause(); if (ourCause != null) ! ourCause.printStackTraceAsCause(s, trace); } /** * Prints this throwable and its backtrace to the specified * print writer. * * @param s <code>PrintWriter</code> to use for output * @since JDK1.1 */ public void printStackTrace(PrintWriter s) { ! synchronized (s) { ! s.println(this); ! StackTraceElement[] trace = getOurStackTrace(); ! for (int i=0; i < trace.length; i++) ! s.println("\tat " + trace[i]); ! ! Throwable ourCause = getCause(); ! if (ourCause != null) ! ourCause.printStackTraceAsCause(s, trace); ! } } /** ! * Print our stack trace as a cause for the specified stack trace. */ ! private void printStackTraceAsCause(PrintWriter s, ! StackTraceElement[] causedTrace) ! { ! // assert Thread.holdsLock(s); ! // Compute number of frames in common between this and caused ! StackTraceElement[] trace = getOurStackTrace(); ! int m = trace.length-1, n = causedTrace.length-1; ! while (m >= 0 && n >=0 && trace[m].equals(causedTrace[n])) { ! m--; n--; } - int framesInCommon = trace.length - 1 - m; ! s.println("Caused by: " + this); ! for (int i=0; i <= m; i++) ! s.println("\tat " + trace[i]); ! if (framesInCommon != 0) ! s.println("\t... " + framesInCommon + " more"); ! // Recurse if we have a cause ! Throwable ourCause = getCause(); ! if (ourCause != null) ! ourCause.printStackTraceAsCause(s, trace); } /** * Fills in the execution stack trace. This method records within this * <code>Throwable</code> object information about the current state of --- 540,658 ---- * Prints this throwable and its backtrace to the specified print stream. * * @param s <code>PrintStream</code> to use for output */ public void printStackTrace(PrintStream s) { ! printStackTrace(new WrappedPrintStream(s)); ! } ! ! private void printStackTrace(PrintStreamOrWriter s) { ! synchronized (s.lock()) { ! // Print our stack trace s.println(this); StackTraceElement[] trace = getOurStackTrace(); ! for (StackTraceElement traceElement : trace) ! s.println("\tat " + traceElement); + // Print suppressed exceptions, if any + for (Throwable se : suppressedExceptions) + se.printEnclosedStackTrace(s, trace, SUPPRESSED_CAPTION, "\t"); + + // Print cause, if any Throwable ourCause = getCause(); if (ourCause != null) ! ourCause.printEnclosedStackTrace(s, trace, CAUSE_CAPTION, ""); } } /** ! * Print our stack trace as an enclosed exception for the specified ! * stack trace. */ ! private void printEnclosedStackTrace(PrintStreamOrWriter s, ! StackTraceElement[] enclosingTrace, String caption, String prefix) { ! assert Thread.holdsLock(s.lock()); ! // Compute number of frames in common between this and enclosing trace StackTraceElement[] trace = getOurStackTrace(); ! int m = trace.length-1, n = enclosingTrace.length-1; ! while (m >= 0 && n >=0 && trace[m].equals(enclosingTrace[n])) { m--; n--; } int framesInCommon = trace.length - 1 - m; ! // Print our stack trace ! s.println(prefix + caption + this); ! for (int i = 0; i <= m; i++) ! s.println(prefix + "\tat " + trace[i]); if (framesInCommon != 0) ! s.println(prefix + "\t... " + framesInCommon + " more"); ! // Print suppressed exceptions, if any ! for (Throwable se : suppressedExceptions) ! se.printEnclosedStackTrace(s, trace, SUPPRESSED_CAPTION, ! prefix +"\t"); ! ! // Print cause, if any Throwable ourCause = getCause(); if (ourCause != null) ! ourCause.printEnclosedStackTrace(s, trace, CAUSE_CAPTION, prefix); } /** * Prints this throwable and its backtrace to the specified * print writer. * * @param s <code>PrintWriter</code> to use for output * @since JDK1.1 */ public void printStackTrace(PrintWriter s) { ! printStackTrace(new WrappedPrintWriter(s)); } /** ! * Wrapper class for PrintStream and PrintWirter to enable a single ! * implementation of printStackTrace. */ ! private abstract static class PrintStreamOrWriter { ! /** Returns the object to be locked when using this StreamOrWriter */ ! abstract Object lock(); ! /** Prints the specified string as a line on this StreamOrWriter */ ! abstract void println(Object o); } ! private static class WrappedPrintStream extends PrintStreamOrWriter { ! private final PrintStream printStream; ! WrappedPrintStream(PrintStream printStream) { ! this.printStream = printStream; ! } ! ! Object lock() { ! return printStream; ! } ! ! void println(Object o) { ! printStream.println(o); ! } ! } ! ! private static class WrappedPrintWriter extends PrintStreamOrWriter { ! private final PrintWriter printWriter; ! ! WrappedPrintWriter(PrintWriter printWriter) { ! this.printWriter = printWriter; ! } ! ! Object lock() { ! return printWriter; ! } ! ! void println(Object o) { ! printWriter.println(o); ! } } /** * Fills in the execution stack trace. This method records within this * <code>Throwable</code> object information about the current state of
*** 665,676 **** --- 750,809 ---- * @throws IndexOutOfBoundsException if <tt>index &lt; 0 || * index &gt;= getStackTraceDepth() </tt> */ native StackTraceElement getStackTraceElement(int index); + private void readObject(java.io.ObjectInputStream s) + throws java.io.IOException, ClassNotFoundException { + s.defaultReadObject(); // read in all fields + List<Throwable> impressedExceptions = Collections.emptyList(); + if (suppressedExceptions != null && + !suppressedExceptions.isEmpty()) { // Copy Throwables to new list + impressedExceptions = new ArrayList<Throwable>(); + for(Throwable t : suppressedExceptions) { + impressedExceptions.add(t); + } + } + suppressedExceptions = impressedExceptions; + } + private synchronized void writeObject(java.io.ObjectOutputStream s) throws IOException { getOurStackTrace(); // Ensure that stackTrace field is initialized. s.defaultWriteObject(); } + + /** + * Adds the specified exception to the list of exceptions that + * were suppressed, typically by the automatic resource management + * statement, in order to deliver this exception. + * + * @param exception the exception to be added to the list of + * suppressed exceptions + * @throws NullPointerException if {@code exception} is null + * @since 1.7 + */ + public synchronized void addSuppressedException(Throwable exception) { + if (exception == null) + throw new NullPointerException(); + + if (suppressedExceptions.size() == 0) + suppressedExceptions = new ArrayList<Throwable>(); + suppressedExceptions.add(exception); + } + + private static final Throwable[] EMPTY_THROWABLE_ARRAY = new Throwable[0]; + + /** + * Returns an array containing all of the exceptions that were + * suppressed, typically by the automatic resource management + * statement, in order to deliver this exception. + * + * @return an array containing all of the exceptions that were + * suppressed to deliver this exception. + * @since 1.7 + */ + public Throwable[] getSuppressedExceptions() { + return suppressedExceptions.toArray(EMPTY_THROWABLE_ARRAY); + } }