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
153 */
154 public class Throwable implements Serializable {
155 /** use serialVersionUID from JDK 1.0.2 for interoperability */
156 private static final long serialVersionUID = -3042686055658047285L;
157
158 /**
159 * Native code saves some indication of the stack backtrace in this slot.
160 */
161 private transient Object backtrace;
162
163 /**
164 * Specific details about the Throwable. For example, for
165 * {@code FileNotFoundException}, this contains the name of
166 * the file that could not be found.
167 *
168 * @serial
169 */
170 private String detailMessage;
171
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 }
701 * in the sequence.
702 *
703 * <p>Some virtual machines may, under some circumstances, omit one
704 * or more stack frames from the stack trace. In the extreme case,
705 * a virtual machine that has no stack trace information concerning
706 * this throwable is permitted to return a zero-length array from this
707 * method. Generally speaking, the array returned by this method will
708 * contain one element for every frame that would be printed by
709 * {@code printStackTrace}.
710 *
711 * @return an array of stack trace elements representing the stack trace
712 * pertaining to this throwable.
713 * @since 1.4
714 */
715 public StackTraceElement[] getStackTrace() {
716 return getOurStackTrace().clone();
717 }
718
719 private synchronized StackTraceElement[] getOurStackTrace() {
720 // Initialize stack trace if this is the first call to this method
721 if (stackTrace == null) {
722 int depth = getStackTraceDepth();
723 stackTrace = new StackTraceElement[depth];
724 for (int i=0; i < depth; i++)
725 stackTrace[i] = getStackTraceElement(i);
726 }
727 return stackTrace;
728 }
729
730 /**
731 * Sets the stack trace elements that will be returned by
732 * {@link #getStackTrace()} and printed by {@link #printStackTrace()}
733 * and related methods.
734 *
735 * This method, which is designed for use by RPC frameworks and other
736 * advanced systems, allows the client to override the default
737 * stack trace that is either generated by {@link #fillInStackTrace()}
738 * when a throwable is constructed or deserialized when a throwable is
739 * read from a serialization stream.
740 *
741 * @param stackTrace the stack trace elements to be associated with
742 * this {@code Throwable}. The specified array is copied by this
743 * call; changes in the specified array after the method invocation
744 * returns will have no affect on this {@code Throwable}'s stack
745 * trace.
746 *
747 * @throws NullPointerException if {@code stackTrace} is
748 * {@code null}, or if any of the elements of
749 * {@code stackTrace} are {@code null}
750 *
751 * @since 1.4
752 */
753 public void setStackTrace(StackTraceElement[] stackTrace) {
754 StackTraceElement[] defensiveCopy = stackTrace.clone();
755 for (int i = 0; i < defensiveCopy.length; i++)
756 if (defensiveCopy[i] == null)
757 throw new NullPointerException("stackTrace[" + i + "]");
758
759 synchronized (this) {
760 this.stackTrace = defensiveCopy;
761 }
762 }
763
764 /**
765 * Returns the number of elements in the stack trace (or 0 if the stack
766 * trace is unavailable).
767 *
768 * package-protection for use by SharedSecrets.
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
153 */
154 public class Throwable implements Serializable {
155 /** use serialVersionUID from JDK 1.0.2 for interoperability */
156 private static final long serialVersionUID = -3042686055658047285L;
157
158 /**
159 * Native code saves some indication of the stack backtrace in this slot.
160 */
161 private transient Object backtrace;
162
163 /**
164 * Specific details about the Throwable. For example, for
165 * {@code FileNotFoundException}, this contains the name of
166 * the file that could not be found.
167 *
168 * @serial
169 */
170 private String detailMessage;
171
172 /**
173 * {@linkplain #setStackTrace(StackTraceElement[]) Setting the
174 * stack trace} to a one-element array containing this sentinel
175 * value indicates future attempts to set the stack trace will be
176 * ignored. The sentinal is equal to the result of calling:<br>
177 * {@code new StackTraceElement("", "", null, Integer.MIN_VALUE)}
178 */
179 private static final StackTraceElement STACK_TRACE_ELEMENT_SENTINEL =
180 new StackTraceElement("", "", null, Integer.MIN_VALUE);
181
182 /**
183 * Sentinel value used in the serial form to indicate an immutable
184 * stack trace.
185 */
186 private static final StackTraceElement[] STACK_TRACE_SENTINEL = initStackTraceSentinel();
187
188 private static StackTraceElement[] initStackTraceSentinel() {
189 StackTraceElement[] ste = new StackTraceElement[1];
190 ste[0] = STACK_TRACE_ELEMENT_SENTINEL;
191 return ste;
192 }
193
194 /**
195 * A value indicating the stack trace field has not yet been initialized.
196 */
197 private static final StackTraceElement[] EMPTY_STACK = new StackTraceElement[0];
198
199 /*
200 * To allow Throwable objects to be made immutable and safely
201 * reused by the JVM, such as OutOfMemoryErrors, the three fields
202 * of Throwable that are writable in response to user actions,
203 * cause, stackTrace, and suppressedExceptions obey the following
204 * protocol:
205 *
206 * 1) The fields are initialized to a non-null sentinel value
207 * which indicates the value has logically not been set.
208 *
209 * 2) Writing a null to the field indicates further writes
210 * are forbidden
211 *
212 * 3) The sentinel value may be replaced with another non-null
213 * value.
214 *
215 * For example, implementations of the HotSpot JVM have
216 * preallocated OutOfMemoryError objects to provide for better
217 * diagnosability of that situation. These objects are created
218 * without calling the constructor for that class and the fields
219 * in question are initialized to null. To support this
220 * capability, any new fields added to Throwable that require
221 * being initialized to a non-null value require a coordinated JVM
222 * change.
223 */
224
225 /**
226 * The throwable that caused this throwable to get thrown, or null if this
227 * throwable was not caused by another throwable, or if the causative
228 * throwable is unknown. If this field is equal to this throwable itself,
229 * it indicates that the cause of this throwable has not yet been
230 * initialized.
231 *
232 * @serial
233 * @since 1.4
234 */
235 private Throwable cause = this;
236
237 /**
238 * The stack trace, as returned by {@link #getStackTrace()}.
239 *
240 * The field is initialized to a zero-length array. A {@code
241 * null} value of this field indicates subsequent calls to {@link
242 * #setStackTrace()} will be be no-ops.
243 *
244 * @serial
245 * @since 1.4
246 */
247 private StackTraceElement[] stackTrace = EMPTY_STACK;
248
249 // Setting this static field introduces an acceptable
250 // initialization dependency on a few java.util classes.
251 private static final List<Throwable> suppressedSentinel =
252 Collections.unmodifiableList(new ArrayList<Throwable>(0));
253
254 /**
255 * The list of suppressed exceptions, as returned by {@link
256 * #getSuppressed()}. The list is initialized to a zero-element
257 * unmodifiable sentinel list. When a serialized Throwable is
258 * read in, if the {@code suppressedExceptions} field points to a
259 * zero-element list, the field is reset to the sentinel value.
260 *
261 * @serial
262 * @since 1.7
263 */
264 private List<Throwable> suppressedExceptions = suppressedSentinel;
265
266 /** Message for trying to suppress a null exception. */
267 private static final String NULL_CAUSE_MESSAGE = "Cannot suppress a null exception.";
268
269 /** Message for trying to suppress oneself. */
270 private static final String SELF_SUPPRESSION_MESSAGE = "Self-suppression not permitted";
271
272 /** Caption for labeling causative exception stack traces */
273 private static final String CAUSE_CAPTION = "Caused by: ";
274
275 /** Caption for labeling suppressed exception stack traces */
276 private static final String SUPPRESSED_CAPTION = "Suppressed: ";
277
278 /**
279 * Constructs a new throwable with {@code null} as its detail message.
280 * The cause is not initialized, and may subsequently be initialized by a
281 * call to {@link #initCause}.
282 *
283 * <p>The {@link #fillInStackTrace()} method is called to initialize
284 * the stack trace data in the newly created throwable.
285 */
286 public Throwable() {
287 fillInStackTrace();
288 }
289
290 /**
291 * Constructs a new throwable with the specified detail message. The
610 */
611 public void printStackTrace(PrintStream s) {
612 printStackTrace(new WrappedPrintStream(s));
613 }
614
615 private void printStackTrace(PrintStreamOrWriter s) {
616 // Guard against malicious overrides of Throwable.equals by
617 // using a Set with identity equality semantics.
618 Set<Throwable> dejaVu =
619 Collections.newSetFromMap(new IdentityHashMap<Throwable, Boolean>());
620 dejaVu.add(this);
621
622 synchronized (s.lock()) {
623 // Print our stack trace
624 s.println(this);
625 StackTraceElement[] trace = getOurStackTrace();
626 for (StackTraceElement traceElement : trace)
627 s.println("\tat " + traceElement);
628
629 // Print suppressed exceptions, if any
630 for (Throwable se : getSuppressed())
631 se.printEnclosedStackTrace(s, trace, SUPPRESSED_CAPTION, "\t", dejaVu);
632
633 // Print cause, if any
634 Throwable ourCause = getCause();
635 if (ourCause != null)
636 ourCause.printEnclosedStackTrace(s, trace, CAUSE_CAPTION, "", dejaVu);
637 }
638 }
639
640 /**
641 * Print our stack trace as an enclosed exception for the specified
642 * stack trace.
643 */
644 private void printEnclosedStackTrace(PrintStreamOrWriter s,
645 StackTraceElement[] enclosingTrace,
646 String caption,
647 String prefix,
648 Set<Throwable> dejaVu) {
649 assert Thread.holdsLock(s.lock());
650 if (dejaVu.contains(this)) {
651 s.println("\t[CIRCULAR REFERENCE:" + this + "]");
652 } else {
653 dejaVu.add(this);
654 // Compute number of frames in common between this and enclosing trace
655 StackTraceElement[] trace = getOurStackTrace();
656 int m = trace.length - 1;
657 int n = enclosingTrace.length - 1;
658 while (m >= 0 && n >=0 && trace[m].equals(enclosingTrace[n])) {
659 m--; n--;
660 }
661 int framesInCommon = trace.length - 1 - m;
662
663 // Print our stack trace
664 s.println(prefix + caption + this);
665 for (int i = 0; i <= m; i++)
666 s.println(prefix + "\tat " + trace[i]);
667 if (framesInCommon != 0)
668 s.println(prefix + "\t... " + framesInCommon + " more");
669
670 // Print suppressed exceptions, if any
671 for (Throwable se : getSuppressed())
672 se.printEnclosedStackTrace(s, trace, SUPPRESSED_CAPTION,
673 prefix +"\t", dejaVu);
674
675 // Print cause, if any
676 Throwable ourCause = getCause();
677 if (ourCause != null)
678 ourCause.printEnclosedStackTrace(s, trace, CAUSE_CAPTION, prefix, dejaVu);
679 }
680 }
681
682 /**
683 * Prints this throwable and its backtrace to the specified
684 * print writer.
685 *
686 * @param s {@code PrintWriter} to use for output
687 * @since JDK1.1
688 */
689 public void printStackTrace(PrintWriter s) {
690 printStackTrace(new WrappedPrintWriter(s));
691 }
756 * in the sequence.
757 *
758 * <p>Some virtual machines may, under some circumstances, omit one
759 * or more stack frames from the stack trace. In the extreme case,
760 * a virtual machine that has no stack trace information concerning
761 * this throwable is permitted to return a zero-length array from this
762 * method. Generally speaking, the array returned by this method will
763 * contain one element for every frame that would be printed by
764 * {@code printStackTrace}.
765 *
766 * @return an array of stack trace elements representing the stack trace
767 * pertaining to this throwable.
768 * @since 1.4
769 */
770 public StackTraceElement[] getStackTrace() {
771 return getOurStackTrace().clone();
772 }
773
774 private synchronized StackTraceElement[] getOurStackTrace() {
775 // Initialize stack trace if this is the first call to this method
776 if (stackTrace == EMPTY_STACK) {
777 int depth = getStackTraceDepth();
778 stackTrace = new StackTraceElement[depth];
779 for (int i=0; i < depth; i++)
780 stackTrace[i] = getStackTraceElement(i);
781 } else if (stackTrace == null) {
782 return EMPTY_STACK;
783 }
784
785 return stackTrace;
786 }
787
788 /**
789 * Sets the stack trace elements that will be returned by
790 * {@link #getStackTrace()} and printed by {@link #printStackTrace()}
791 * and related methods.
792 *
793 * This method, which is designed for use by RPC frameworks and other
794 * advanced systems, allows the client to override the default
795 * stack trace that is either generated by {@link #fillInStackTrace()}
796 * when a throwable is constructed or deserialized when a throwable is
797 * read from a serialization stream.
798 *
799 * <p>If the stack trace is set to {@code null}, then future calls
800 * to this method have no effect on this {@code Throwable}.
801 *
802 * @param stackTrace the stack trace elements to be associated with
803 * this {@code Throwable}. The specified array is copied by this
804 * call; changes in the specified array after the method invocation
805 * returns will have no affect on this {@code Throwable}'s stack
806 * trace.
807 *
808 * @throws NullPointerException if any of the elements of
809 * {@code stackTrace} are {@code null}
810 *
811 * @since 1.4
812 */
813 public void setStackTrace(StackTraceElement[] stackTrace) {
814 if (this.stackTrace == null) // Immutable stack
815 return;
816
817 StackTraceElement[] defensiveCopy;
818
819 if (stackTrace == null) {
820 defensiveCopy = stackTrace;
821 } else {
822 defensiveCopy = stackTrace.clone();
823
824 for (int i = 0; i < defensiveCopy.length; i++) {
825 if (defensiveCopy[i] == null)
826 throw new NullPointerException("stackTrace[" + i + "]");
827 }
828 }
829
830 synchronized (this) {
831 this.stackTrace = defensiveCopy;
832 }
833 }
834
835 /**
836 * Returns the number of elements in the stack trace (or 0 if the stack
837 * trace is unavailable).
838 *
839 * package-protection for use by SharedSecrets.
840 */
841 native int getStackTraceDepth();
842
843 /**
844 * Returns the specified element of the stack trace.
845 *
846 * package-protection for use by SharedSecrets.
847 *
848 * @param index index of the element to return.
849 * @throws IndexOutOfBoundsException if {@code index < 0 ||
850 * index >= getStackTraceDepth() }
851 */
852 native StackTraceElement getStackTraceElement(int index);
853
854 /**
855 * Read a {@code Throwable} from a stream, enforcing
856 * well-formedness constraints on fields. Null entries and
857 * self-pointers are not allowed in the list of {@code
858 * suppressedExceptions}. Null entries are not allowed for stack
859 * trace elements. A single-element stack trace whose entry is
860 * equal to {@code new StackTraceElement("", "", null,
861 * Integer.MIN_VALUE)} results in a {@code null} {@code
862 * stackTrace} field.
863 *
864 * Note that there are no constraints on the value the {@code
865 * cause} field can hold; both {@code null} and this are valid
866 * values for the field.
867 */
868 private void readObject(ObjectInputStream s)
869 throws IOException, ClassNotFoundException {
870 s.defaultReadObject(); // read in all fields
871 List<Throwable> suppressed = null;
872 if (suppressedExceptions != null &&
873 !suppressedExceptions.isEmpty()) { // Copy Throwables to new list
874 suppressed = new ArrayList<Throwable>(1);
875 for (Throwable t : suppressedExceptions) {
876 // Enforce constraints on suppressed exceptions in
877 // case of corrupt or malicious stream.
878 if (t == null)
879 throw new NullPointerException(NULL_CAUSE_MESSAGE);
880 if (t == this)
881 throw new IllegalArgumentException(SELF_SUPPRESSION_MESSAGE);
882 suppressed.add(t);
883 }
884 }
885
886 // If suppressed is a zero-length list, use the sentinel
887 // value.
888 if (suppressed != null && suppressed.isEmpty())
889 suppressedExceptions = suppressedSentinel;
890 else
891 suppressedExceptions = suppressed;
892
893 // Check for the marker of an immutable stack trace
894 if (stackTrace != null) {
895 // Share zero-length stack traces
896 if (stackTrace.length == 0) {
897 stackTrace = EMPTY_STACK;
898 } else if (stackTrace.length == 1 &&
899 STACK_TRACE_ELEMENT_SENTINEL.equals(stackTrace[0])) {
900 stackTrace = null;
901 } else { // Verify stack trace elements are non-null.
902 for(StackTraceElement ste : stackTrace) {
903 if (ste == null)
904 throw new NullPointerException("null StackTraceElement in serial stream. ");
905 }
906 }
907 }
908
909 // A null stackTrace field in the serial form can result from
910 // an exception serialied without that field. Such exceptions
911 // are now treated as having immutable stack traces.
912 }
913
914 /**
915 * Write a {@code Throwable} object to a stream. A {@code null}
916 * stack trace field is represented in the serial form as a
917 * one-element array whose element is equal to {@code new
918 * StackTraceElement("", "", null, Integer.MIN_VALUE)}.
919 */
920 private synchronized void writeObject(ObjectOutputStream s)
921 throws IOException {
922 // Ensure that the stackTrace field is initialized to a
923 // non-null value, if appropriate. As of JDK 7, a null stack
924 // trace field is a valid value indicating the stack trace
925 // should not be set.
926 getOurStackTrace();
927 ObjectOutputStream.PutField fields = s.putFields();
928
929 fields.put("detailMessage", detailMessage);
930 fields.put("cause", cause);
931 // Serialize a null stacktrace using the stack trace sentinel.
932 if (stackTrace == null)
933 fields.put("stackTrace", STACK_TRACE_SENTINEL);
934 else
935 fields.put("stackTrace", stackTrace);
936 fields.put("suppressedExceptions", suppressedExceptions);
937
938 s.writeFields();
939 }
940
941 /**
942 * Adds the specified exception to the list of exceptions that
943 * were suppressed, typically by the {@code try}-with-resources
944 * statement, in order to deliver this exception.
945 *
946 * If the first exception to be suppressed is {@code null}, that
947 * indicates suppressed exception information will <em>not</em> be
948 * recorded for this exception. Subsequent calls to this method
949 * will not record any suppressed exceptions. Otherwise,
950 * attempting to suppress {@code null} after an exception has
951 * already been successfully suppressed results in a {@code
952 * NullPointerException}.
953 *
954 * <p>Note that when one exception {@linkplain
955 * #initCause(Throwable) causes} another exception, the first
956 * exception is usually caught and then the second exception is
957 * thrown in response. In contrast, when one exception suppresses
958 * another, two exceptions are thrown in sibling code blocks, such
959 * as in a {@code try} block and in its {@code finally} block, and
960 * control flow can only continue with one exception so the second
961 * is recorded as a suppressed exception of the first.
962 *
963 * @param exception the exception to be added to the list of
964 * suppressed exceptions
965 * @throws IllegalArgumentException if {@code exception} is this
966 * throwable; a throwable cannot suppress itself.
967 * @throws NullPointerException if {@code exception} is null and
968 * an exception has already been suppressed by this exception
969 * @since 1.7
970 */
971 public synchronized void addSuppressed(Throwable exception) {
972 if (exception == this)
973 throw new IllegalArgumentException(SELF_SUPPRESSION_MESSAGE);
974
975 if (exception == null) {
976 if (suppressedExceptions == suppressedSentinel) {
977 suppressedExceptions = null; // No suppression information recorded
978 return;
979 } else
980 throw new NullPointerException(NULL_CAUSE_MESSAGE);
981 } else {
982 assert exception != null && exception != this;
983
984 if (suppressedExceptions == null) // Suppressed exceptions not recorded
985 return;
986
987 if (suppressedExceptions == suppressedSentinel)
988 suppressedExceptions = new ArrayList<Throwable>(1);
989
990 assert suppressedExceptions != suppressedSentinel;
991
992 suppressedExceptions.add(exception);
993 }
994 }
995
996 private static final Throwable[] EMPTY_THROWABLE_ARRAY = new Throwable[0];
997
998 /**
999 * Returns an array containing all of the exceptions that were
1000 * suppressed, typically by the {@code try}-with-resources
1001 * statement, in order to deliver this exception.
1002 *
1003 * If no exceptions were suppressed, an empty array is returned.
1004 *
1005 * @return an array containing all of the exceptions that were
1006 * suppressed to deliver this exception.
1007 * @since 1.7
1008 */
1009 public synchronized Throwable[] getSuppressed() {
1010 if (suppressedExceptions == suppressedSentinel ||
1011 suppressedExceptions == null)
1012 return EMPTY_THROWABLE_ARRAY;
1013 else
1014 return suppressedExceptions.toArray(EMPTY_THROWABLE_ARRAY);
1015 }
1016 }
|