1 /*
2 * Copyright (c) 1994, 2006, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
172 /**
173 * The throwable that caused this throwable to get thrown, or null if this
174 * throwable was not caused by another throwable, or if the causative
175 * throwable is unknown. If this field is equal to this throwable itself,
176 * it indicates that the cause of this throwable has not yet been
177 * initialized.
178 *
179 * @serial
180 * @since 1.4
181 */
182 private Throwable cause = this;
183
184 /**
185 * The stack trace, as returned by {@link #getStackTrace()}.
186 *
187 * @serial
188 * @since 1.4
189 */
190 private StackTraceElement[] stackTrace;
191 /*
192 * This field is lazily initialized on first use or serialization and
193 * nulled out when fillInStackTrace is called.
194 */
195
196 /**
197 * The list of suppressed exceptions, as returned by
198 * {@link #getSuppressedExceptions()}.
199 *
200 * @serial
201 * @since 1.7
202 */
203 private List<Throwable> suppressedExceptions = null;
204 /*
205 * This field is lazily initialized when the first suppressed
206 * exception is added.
207 *
208 * OutOfMemoryError is preallocated in the VM for better OOM
209 * diagnosability during VM initialization. Constructor can't
210 * be not invoked. If a new field to be added in the future must
211 * be initialized to non-null, it requires a synchronized VM change.
212 */
213
214 /** Message for trying to suppress a null exception. */
215 private static final String NULL_CAUSE_MESSAGE = "Cannot suppress a null exception.";
216
217 /** Caption for labeling causative exception stack traces */
218 private static final String CAUSE_CAPTION = "Caused by: ";
219
220 /** Caption for labeling suppressed exception stack traces */
221 private static final String SUPPRESSED_CAPTION = "Suppressed: ";
222
223 /**
224 * Constructs a new throwable with {@code null} as its detail message.
225 * The cause is not initialized, and may subsequently be initialized by a
226 * call to {@link #initCause}.
227 *
228 * <p>The {@link #fillInStackTrace()} method is called to initialize
229 * the stack trace data in the newly created throwable.
230 */
231 public Throwable() {
232 fillInStackTrace();
233 }
234
235 /**
236 * Constructs a new throwable with the specified detail message. The
555 */
556 public void printStackTrace(PrintStream s) {
557 printStackTrace(new WrappedPrintStream(s));
558 }
559
560 private void printStackTrace(PrintStreamOrWriter s) {
561 // Guard against malicious overrides of Throwable.equals by
562 // using a Set with identity equality semantics.
563 Set<Throwable> dejaVu =
564 Collections.newSetFromMap(new IdentityHashMap<Throwable, Boolean>());
565 dejaVu.add(this);
566
567 synchronized (s.lock()) {
568 // Print our stack trace
569 s.println(this);
570 StackTraceElement[] trace = getOurStackTrace();
571 for (StackTraceElement traceElement : trace)
572 s.println("\tat " + traceElement);
573
574 // Print suppressed exceptions, if any
575 for (Throwable se : getSuppressedExceptions())
576 se.printEnclosedStackTrace(s, trace, SUPPRESSED_CAPTION, "\t", dejaVu);
577
578 // Print cause, if any
579 Throwable ourCause = getCause();
580 if (ourCause != null)
581 ourCause.printEnclosedStackTrace(s, trace, CAUSE_CAPTION, "", dejaVu);
582 }
583 }
584
585 /**
586 * Print our stack trace as an enclosed exception for the specified
587 * stack trace.
588 */
589 private void printEnclosedStackTrace(PrintStreamOrWriter s,
590 StackTraceElement[] enclosingTrace,
591 String caption,
592 String prefix,
593 Set<Throwable> dejaVu) {
594 assert Thread.holdsLock(s.lock());
595 if (dejaVu.contains(this)) {
596 s.println("\t[CIRCULAR REFERENCE:" + this + "]");
597 } else {
598 dejaVu.add(this);
599 // Compute number of frames in common between this and enclosing trace
600 StackTraceElement[] trace = getOurStackTrace();
601 int m = trace.length - 1;
602 int n = enclosingTrace.length - 1;
603 while (m >= 0 && n >=0 && trace[m].equals(enclosingTrace[n])) {
604 m--; n--;
605 }
606 int framesInCommon = trace.length - 1 - m;
607
608 // Print our stack trace
609 s.println(prefix + caption + this);
610 for (int i = 0; i <= m; i++)
611 s.println(prefix + "\tat " + trace[i]);
612 if (framesInCommon != 0)
613 s.println(prefix + "\t... " + framesInCommon + " more");
614
615 // Print suppressed exceptions, if any
616 for (Throwable se : getSuppressedExceptions())
617 se.printEnclosedStackTrace(s, trace, SUPPRESSED_CAPTION,
618 prefix +"\t", dejaVu);
619
620 // Print cause, if any
621 Throwable ourCause = getCause();
622 if (ourCause != null)
623 ourCause.printEnclosedStackTrace(s, trace, CAUSE_CAPTION, prefix, dejaVu);
624 }
625 }
626
627 /**
628 * Prints this throwable and its backtrace to the specified
629 * print writer.
630 *
631 * @param s {@code PrintWriter} to use for output
632 * @since JDK1.1
633 */
634 public void printStackTrace(PrintWriter s) {
635 printStackTrace(new WrappedPrintWriter(s));
636 }
769 */
770 native int getStackTraceDepth();
771
772 /**
773 * Returns the specified element of the stack trace.
774 *
775 * package-protection for use by SharedSecrets.
776 *
777 * @param index index of the element to return.
778 * @throws IndexOutOfBoundsException if {@code index < 0 ||
779 * index >= getStackTraceDepth() }
780 */
781 native StackTraceElement getStackTraceElement(int index);
782
783 private void readObject(ObjectInputStream s)
784 throws IOException, ClassNotFoundException {
785 s.defaultReadObject(); // read in all fields
786 List<Throwable> suppressed = null;
787 if (suppressedExceptions != null &&
788 !suppressedExceptions.isEmpty()) { // Copy Throwables to new list
789 suppressed = new ArrayList<Throwable>();
790 for (Throwable t : suppressedExceptions) {
791 if (t == null)
792 throw new NullPointerException(NULL_CAUSE_MESSAGE);
793 suppressed.add(t);
794 }
795 }
796 suppressedExceptions = suppressed;
797 }
798
799 private synchronized void writeObject(ObjectOutputStream s)
800 throws IOException
801 {
802 getOurStackTrace(); // Ensure that stackTrace field is initialized.
803 s.defaultWriteObject();
804 }
805
806 /**
807 * Adds the specified exception to the list of exceptions that
808 * were suppressed, typically by the {@code try}-with-resources
809 * statement, in order to deliver this exception.
810 *
811 * <p>Note that when one exception {@linkplain
812 * #initCause(Throwable) causes} another exception, the first
813 * exception is usually caught and then the second exception is
814 * thrown in response. In contrast, when one exception suppresses
815 * another, two exceptions are thrown in sibling code blocks, such
816 * as in a {@code try} block and in its {@code finally} block, and
817 * control flow can only continue with one exception so the second
818 * is recorded as a suppressed exception of the first.
819 *
820 * @param exception the exception to be added to the list of
821 * suppressed exceptions
822 * @throws NullPointerException if {@code exception} is null
823 * @throws IllegalArgumentException if {@code exception} is this
824 * throwable; a throwable cannot suppress itself.
825 * @since 1.7
826 */
827 public synchronized void addSuppressedException(Throwable exception) {
828 if (exception == null)
829 throw new NullPointerException(NULL_CAUSE_MESSAGE);
830 if (exception == this)
831 throw new IllegalArgumentException("Self-suppression not permitted");
832
833 if (suppressedExceptions == null)
834 suppressedExceptions = new ArrayList<Throwable>();
835 suppressedExceptions.add(exception);
836 }
837
838 private static final Throwable[] EMPTY_THROWABLE_ARRAY = new Throwable[0];
839
840 /**
841 * Returns an array containing all of the exceptions that were
842 * suppressed, typically by the {@code try}-with-resources
843 * statement, in order to deliver this exception.
844 *
845 * @return an array containing all of the exceptions that were
846 * suppressed to deliver this exception.
847 * @since 1.7
848 */
849 public synchronized Throwable[] getSuppressedExceptions() {
850 if (suppressedExceptions == null)
851 return EMPTY_THROWABLE_ARRAY;
852 else
853 return suppressedExceptions.toArray(EMPTY_THROWABLE_ARRAY);
854 }
855 }
|
1 /*
2 * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
172 /**
173 * The throwable that caused this throwable to get thrown, or null if this
174 * throwable was not caused by another throwable, or if the causative
175 * throwable is unknown. If this field is equal to this throwable itself,
176 * it indicates that the cause of this throwable has not yet been
177 * initialized.
178 *
179 * @serial
180 * @since 1.4
181 */
182 private Throwable cause = this;
183
184 /**
185 * The stack trace, as returned by {@link #getStackTrace()}.
186 *
187 * @serial
188 * @since 1.4
189 */
190 private StackTraceElement[] stackTrace;
191 /*
192 * This field above is lazily initialized on first use or
193 * serialization and nulled out when fillInStackTrace is called.
194 */
195
196 private static final List<Throwable> suppressedSentinal =
197 Collections.unmodifiableList(new ArrayList<Throwable>(0));
198
199 /**
200 * The list of suppressed exceptions, as returned by
201 * {@link #getSuppressed()}.
202 *
203 * @serial
204 * @since 1.7
205 */
206 private List<Throwable> suppressedExceptions = suppressedSentinal;
207 /*
208 * This field is lazily initialized when the first suppressed
209 * exception is added.
210 *
211 * OutOfMemoryError is preallocated in the VM for better OOM
212 * diagnosability during VM initialization. Constructor can't
213 * be not invoked. If a new field to be added in the future must
214 * be initialized to non-null, it requires a synchronized VM change.
215 */
216
217 /** Message for trying to suppress a null exception. */
218 private static final String NULL_CAUSE_MESSAGE = "Cannot suppress a null exception.";
219
220 /** Message for trying to suppress oneself. */
221 private static final String SELF_SUPPRESSION_MESSAGE = "Self-suppression not permitted";
222
223 /** Caption for labeling causative exception stack traces */
224 private static final String CAUSE_CAPTION = "Caused by: ";
225
226 /** Caption for labeling suppressed exception stack traces */
227 private static final String SUPPRESSED_CAPTION = "Suppressed: ";
228
229 /**
230 * Constructs a new throwable with {@code null} as its detail message.
231 * The cause is not initialized, and may subsequently be initialized by a
232 * call to {@link #initCause}.
233 *
234 * <p>The {@link #fillInStackTrace()} method is called to initialize
235 * the stack trace data in the newly created throwable.
236 */
237 public Throwable() {
238 fillInStackTrace();
239 }
240
241 /**
242 * Constructs a new throwable with the specified detail message. The
561 */
562 public void printStackTrace(PrintStream s) {
563 printStackTrace(new WrappedPrintStream(s));
564 }
565
566 private void printStackTrace(PrintStreamOrWriter s) {
567 // Guard against malicious overrides of Throwable.equals by
568 // using a Set with identity equality semantics.
569 Set<Throwable> dejaVu =
570 Collections.newSetFromMap(new IdentityHashMap<Throwable, Boolean>());
571 dejaVu.add(this);
572
573 synchronized (s.lock()) {
574 // Print our stack trace
575 s.println(this);
576 StackTraceElement[] trace = getOurStackTrace();
577 for (StackTraceElement traceElement : trace)
578 s.println("\tat " + traceElement);
579
580 // Print suppressed exceptions, if any
581 for (Throwable se : getSuppressed())
582 se.printEnclosedStackTrace(s, trace, SUPPRESSED_CAPTION, "\t", dejaVu);
583
584 // Print cause, if any
585 Throwable ourCause = getCause();
586 if (ourCause != null)
587 ourCause.printEnclosedStackTrace(s, trace, CAUSE_CAPTION, "", dejaVu);
588 }
589 }
590
591 /**
592 * Print our stack trace as an enclosed exception for the specified
593 * stack trace.
594 */
595 private void printEnclosedStackTrace(PrintStreamOrWriter s,
596 StackTraceElement[] enclosingTrace,
597 String caption,
598 String prefix,
599 Set<Throwable> dejaVu) {
600 assert Thread.holdsLock(s.lock());
601 if (dejaVu.contains(this)) {
602 s.println("\t[CIRCULAR REFERENCE:" + this + "]");
603 } else {
604 dejaVu.add(this);
605 // Compute number of frames in common between this and enclosing trace
606 StackTraceElement[] trace = getOurStackTrace();
607 int m = trace.length - 1;
608 int n = enclosingTrace.length - 1;
609 while (m >= 0 && n >=0 && trace[m].equals(enclosingTrace[n])) {
610 m--; n--;
611 }
612 int framesInCommon = trace.length - 1 - m;
613
614 // Print our stack trace
615 s.println(prefix + caption + this);
616 for (int i = 0; i <= m; i++)
617 s.println(prefix + "\tat " + trace[i]);
618 if (framesInCommon != 0)
619 s.println(prefix + "\t... " + framesInCommon + " more");
620
621 // Print suppressed exceptions, if any
622 for (Throwable se : getSuppressed())
623 se.printEnclosedStackTrace(s, trace, SUPPRESSED_CAPTION,
624 prefix +"\t", dejaVu);
625
626 // Print cause, if any
627 Throwable ourCause = getCause();
628 if (ourCause != null)
629 ourCause.printEnclosedStackTrace(s, trace, CAUSE_CAPTION, prefix, dejaVu);
630 }
631 }
632
633 /**
634 * Prints this throwable and its backtrace to the specified
635 * print writer.
636 *
637 * @param s {@code PrintWriter} to use for output
638 * @since JDK1.1
639 */
640 public void printStackTrace(PrintWriter s) {
641 printStackTrace(new WrappedPrintWriter(s));
642 }
775 */
776 native int getStackTraceDepth();
777
778 /**
779 * Returns the specified element of the stack trace.
780 *
781 * package-protection for use by SharedSecrets.
782 *
783 * @param index index of the element to return.
784 * @throws IndexOutOfBoundsException if {@code index < 0 ||
785 * index >= getStackTraceDepth() }
786 */
787 native StackTraceElement getStackTraceElement(int index);
788
789 private void readObject(ObjectInputStream s)
790 throws IOException, ClassNotFoundException {
791 s.defaultReadObject(); // read in all fields
792 List<Throwable> suppressed = null;
793 if (suppressedExceptions != null &&
794 !suppressedExceptions.isEmpty()) { // Copy Throwables to new list
795 suppressed = new ArrayList<Throwable>(1);
796 for (Throwable t : suppressedExceptions) {
797 if (t == null)
798 throw new NullPointerException(NULL_CAUSE_MESSAGE);
799 if (t == this)
800 throw new IllegalArgumentException(SELF_SUPPRESSION_MESSAGE);
801 suppressed.add(t);
802 }
803 }
804
805 if (suppressed != null && suppressed.isEmpty())
806 suppressedExceptions = suppressedSentinal;
807 else
808 suppressedExceptions = suppressed;
809 }
810
811 private synchronized void writeObject(ObjectOutputStream s)
812 throws IOException
813 {
814 getOurStackTrace(); // Ensure that stackTrace field is initialized.
815 s.defaultWriteObject();
816 }
817
818 /**
819 * Adds the specified exception to the list of exceptions that
820 * were suppressed, typically by the {@code try}-with-resources
821 * statement, in order to deliver this exception.
822 *
823 * If the first exception to be suppressed is {@code null}, that
824 * indicates suppressed exception information will <em>not</em> be
825 * recorded for this exception. Subsequent calls to this method
826 * will not record any suppressed exceptions. Otherwise,
827 * attempting to suppress {@code null} after an exception has
828 * already been successfully suppressed results in a {@code
829 * NullPointerException}.
830 *
831 * <p>Note that when one exception {@linkplain
832 * #initCause(Throwable) causes} another exception, the first
833 * exception is usually caught and then the second exception is
834 * thrown in response. In contrast, when one exception suppresses
835 * another, two exceptions are thrown in sibling code blocks, such
836 * as in a {@code try} block and in its {@code finally} block, and
837 * control flow can only continue with one exception so the second
838 * is recorded as a suppressed exception of the first.
839 *
840 * @param exception the exception to be added to the list of
841 * suppressed exceptions
842 * @throws NullPointerException if {@code exception} is null
843 * @throws IllegalArgumentException if {@code exception} is this
844 * throwable; a throwable cannot suppress itself.
845 * @since 1.7
846 */
847 public synchronized void addSuppressed(Throwable exception) {
848 if (exception == this)
849 throw new IllegalArgumentException(SELF_SUPPRESSION_MESSAGE);
850
851 if (exception == null) {
852 if (suppressedExceptions == suppressedSentinal) {
853 suppressedExceptions = null; // No suppression information recorded
854 return;
855 } else
856 throw new NullPointerException(NULL_CAUSE_MESSAGE);
857 } else {
858 assert exception != null && exception != this;
859
860 if (suppressedExceptions == null) // Suppressed exceptions not recorded
861 return;
862
863 if (suppressedExceptions == suppressedSentinal)
864 suppressedExceptions = new ArrayList<Throwable>(1);
865
866 assert suppressedExceptions != suppressedSentinal;
867
868 suppressedExceptions.add(exception);
869 return;
870 }
871 }
872
873 private static final Throwable[] EMPTY_THROWABLE_ARRAY = new Throwable[0];
874
875 /**
876 * Returns an array containing all of the exceptions that were
877 * suppressed, typically by the {@code try}-with-resources
878 * statement, in order to deliver this exception.
879 *
880 * If no exceptions were suppressed, an empty array is returned.
881 *
882 * @return an array containing all of the exceptions that were
883 * suppressed to deliver this exception.
884 * @since 1.7
885 */
886 public synchronized Throwable[] getSuppressed() {
887 if (suppressedExceptions == suppressedSentinal ||
888 suppressedExceptions == null)
889 return EMPTY_THROWABLE_ARRAY;
890 else
891 return suppressedExceptions.toArray(EMPTY_THROWABLE_ARRAY);
892 }
893 }
|