• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 package java.lang;
19 
20 import java.io.IOException;
21 import java.io.ObjectInputStream;
22 import java.io.ObjectOutputStream;
23 import java.io.PrintStream;
24 import java.io.PrintWriter;
25 import java.util.ArrayList;
26 import java.util.List;
27 import libcore.util.EmptyArray;
28 
29 /**
30  * The superclass of all classes which can be thrown by the VM. The
31  * two direct subclasses are recoverable exceptions ({@code Exception}) and
32  * unrecoverable errors ({@code Error}). This class provides common methods for
33  * accessing a string message which provides extra information about the
34  * circumstances in which the {@code Throwable} was created (basically an error
35  * message in most cases), and for saving a stack trace (that is, a record of
36  * the call stack at a particular point in time) which can be printed later.
37  * <p>
38  * A {@code Throwable} can also include a cause, which is a nested {@code
39  * Throwable} that represents the original problem that led to this {@code
40  * Throwable}. It is often used for wrapping various types of errors into a
41  * common {@code Throwable} without losing the detailed original error
42  * information. When printing the stack trace, the trace of the cause is
43  * included.
44  *
45  * @see Error
46  * @see Exception
47  * @see RuntimeException
48  */
49 public class Throwable implements java.io.Serializable {
50     private static final long serialVersionUID = -3042686055658047285L;
51 
52     /**
53      * The message provided when the exception was created.
54      */
55     private String detailMessage;
56 
57     /**
58      * The cause of this Throwable. Null when there is no cause.
59      */
60     private Throwable cause = this;
61 
62     /**
63      * Throwables suppressed by this throwable. Null when suppressed exceptions
64      * are disabled.
65      */
66     private List<Throwable> suppressedExceptions = new ArrayList<Throwable>();
67 
68     /**
69      * An intermediate representation of the stack trace.  This field may
70      * be accessed by the VM; do not rename.
71      */
72     private volatile Object stackState;
73 
74     /**
75      * A fully-expanded representation of the stack trace.
76      */
77     private StackTraceElement[] stackTrace;
78 
79     /**
80      * Constructs a new {@code Throwable} that includes the current stack trace.
81      */
Throwable()82     public Throwable() {
83         fillInStackTrace();
84     }
85 
86     /**
87      * Constructs a new {@code Throwable} with the current stack trace and the
88      * specified detail message.
89      *
90      * @param detailMessage
91      *            the detail message for this {@code Throwable}.
92      */
Throwable(String detailMessage)93     public Throwable(String detailMessage) {
94         this();
95         this.detailMessage = detailMessage;
96     }
97 
98     /**
99      * Constructs a new {@code Throwable} with the current stack trace, the
100      * specified detail message and the specified cause.
101      *
102      * @param detailMessage
103      *            the detail message for this {@code Throwable}.
104      * @param throwable
105      *            the cause of this {@code Throwable}.
106      */
Throwable(String detailMessage, Throwable throwable)107     public Throwable(String detailMessage, Throwable throwable) {
108         this();
109         this.detailMessage = detailMessage;
110         cause = throwable;
111     }
112 
113     /**
114      * Constructs a new {@code Throwable} with the current stack trace and the
115      * specified cause.
116      *
117      * @param throwable
118      *            the cause of this {@code Throwable}.
119      */
Throwable(Throwable throwable)120     public Throwable(Throwable throwable) {
121         this();
122         this.detailMessage = throwable == null ? null : throwable.toString();
123         cause = throwable;
124     }
125 
126     /**
127      * Constructs a new {@code Throwable} with the current stack trace, the
128      * specified detail message and the specified cause.
129      *
130      * @param enableSuppression if false, throwables passed to {@link
131      *     #addSuppressed(Throwable)} will be silently discarded.
132      * @since 1.7
133      * @hide 1.7
134      */
Throwable(String detailMessage, Throwable throwable, boolean enableSuppression)135     protected Throwable(String detailMessage, Throwable throwable, boolean enableSuppression) {
136         this(detailMessage, throwable);
137         if (!enableSuppression) {
138             this.suppressedExceptions = null;
139         }
140     }
141 
142     /**
143      * Records the stack trace from the point where this method has been called
144      * to this {@code Throwable}. This method is invoked by the {@code Throwable} constructors.
145      *
146      * <p>This method is public so that code (such as an RPC system) which catches
147      * a {@code Throwable} and then re-throws it can replace the construction-time stack trace
148      * with a stack trace from the location where the exception was re-thrown, by <i>calling</i>
149      * {@code fillInStackTrace}.
150      *
151      * <p>This method is non-final so that non-Java language implementations can disable VM stack
152      * traces for their language. Filling in the stack trace is relatively expensive.
153      * <i>Overriding</i> this method in the root of a language's exception hierarchy allows the
154      * language to avoid paying for something it doesn't need.
155      *
156      * @return this {@code Throwable} instance.
157      */
fillInStackTrace()158     public Throwable fillInStackTrace() {
159         // Fill in the intermediate representation
160         stackState = nativeFillInStackTrace();
161         // Mark the full representation as empty
162         stackTrace = null;
163         return this;
164     }
165 
166     /**
167      * Returns the extra information message which was provided when this
168      * {@code Throwable} was created. Returns {@code null} if no message was
169      * provided at creation time.
170      *
171      * @return this {@code Throwable}'s detail message.
172      */
getMessage()173     public String getMessage() {
174         return detailMessage;
175     }
176 
177     /**
178      * Returns the extra information message which was provided when this
179      * {@code Throwable} was created. Returns {@code null} if no message was
180      * provided at creation time. Subclasses may override this method to return
181      * localized text for the message. Android returns the regular detail message.
182      *
183      * @return this {@code Throwable}'s localized detail message.
184      */
getLocalizedMessage()185     public String getLocalizedMessage() {
186         return getMessage();
187     }
188 
189     /**
190      * Returns the array of stack trace elements of this {@code Throwable}. Each
191      * {@code StackTraceElement} represents an entry in the call stack. The
192      * element at position 0 is the top of the stack, that is, the stack frame
193      * where this {@code Throwable} is thrown.
194      *
195      * @return a copy of the array of {@code StackTraceElement}s representing
196      *         the call stack. Changes in the array obtained from this call will
197      *         not change the call stack stored in this {@code Throwable}.
198      * @see #printStackTrace()
199      */
getStackTrace()200     public StackTraceElement[] getStackTrace() {
201         return getInternalStackTrace().clone();
202     }
203 
204     /**
205      * Sets the array of stack trace elements. Each {@code StackTraceElement}
206      * represents an entry in the call stack. A copy of the specified array is
207      * stored in this {@code Throwable}. will be returned by {@code
208      * getStackTrace()} and printed by {@code printStackTrace()}.
209      *
210      * @param trace
211      *            the new array of {@code StackTraceElement}s. A copy of the
212      *            array is stored in this {@code Throwable}, so subsequent
213      *            changes to {@code trace} will not change the call stack stored
214      *            in this {@code Throwable}.
215      * @throws NullPointerException
216      *             if any element in {@code trace} is {@code null}.
217      * @see #printStackTrace()
218      */
setStackTrace(StackTraceElement[] trace)219     public void setStackTrace(StackTraceElement[] trace) {
220         StackTraceElement[] newTrace = trace.clone();
221         for (StackTraceElement element : newTrace) {
222             if (element == null) {
223                 throw new NullPointerException();
224             }
225         }
226         stackTrace = newTrace;
227     }
228 
229     /**
230      * Writes a printable representation of this {@code Throwable}'s stack trace
231      * to the {@code System.err} stream.
232      *
233      */
printStackTrace()234     public void printStackTrace() {
235         printStackTrace(System.err);
236     }
237 
238     /**
239      * Counts the number of duplicate stack frames, starting from the
240      * end of the stack.
241      *
242      * @param currentStack a stack to compare
243      * @param parentStack a stack to compare
244      *
245      * @return the number of duplicate stack frames.
246      */
countDuplicates(StackTraceElement[] currentStack, StackTraceElement[] parentStack)247     private static int countDuplicates(StackTraceElement[] currentStack,
248             StackTraceElement[] parentStack) {
249         int duplicates = 0;
250         int parentIndex = parentStack.length;
251         for (int i = currentStack.length; --i >= 0 && --parentIndex >= 0;) {
252             StackTraceElement parentFrame = parentStack[parentIndex];
253             if (parentFrame.equals(currentStack[i])) {
254                 duplicates++;
255             } else {
256                 break;
257             }
258         }
259         return duplicates;
260     }
261 
262     /**
263      * Returns an array of StackTraceElement. Each StackTraceElement
264      * represents a entry on the stack.
265      *
266      * @return an array of StackTraceElement representing the stack
267      */
getInternalStackTrace()268     private StackTraceElement[] getInternalStackTrace() {
269         if (stackTrace == null) {
270             stackTrace = nativeGetStackTrace(stackState);
271             stackState = null; // Clean up intermediate representation
272         }
273         return stackTrace;
274     }
275 
276     /**
277      * Writes a printable representation of this {@code Throwable}'s stack trace
278      * to the specified print stream. If the {@code Throwable} contains a
279      * {@link #getCause() cause}, the method will be invoked recursively for
280      * the nested {@code Throwable}.
281      *
282      * @param err
283      *            the stream to write the stack trace on.
284      */
printStackTrace(PrintStream err)285     public void printStackTrace(PrintStream err) {
286         try {
287             printStackTrace(err, "", null);
288         } catch (IOException e) {
289             // Appendable.append throws IOException but PrintStream.append doesn't.
290             throw new AssertionError();
291         }
292     }
293 
294     /**
295      * Writes a printable representation of this {@code Throwable}'s stack trace
296      * to the specified print writer. If the {@code Throwable} contains a
297      * {@link #getCause() cause}, the method will be invoked recursively for the
298      * nested {@code Throwable}.
299      *
300      * @param err
301      *            the writer to write the stack trace on.
302      */
printStackTrace(PrintWriter err)303     public void printStackTrace(PrintWriter err) {
304         try {
305             printStackTrace(err, "", null);
306         } catch (IOException e) {
307             // Appendable.append throws IOException, but PrintWriter.append doesn't.
308             throw new AssertionError();
309         }
310     }
311 
312     /**
313      * @param indent additional indentation on each line of the stack trace.
314      *     This is the empty string for all but suppressed throwables.
315      * @param parentStack the parent stack trace to suppress duplicates from, or
316      *     null if this stack trace has no parent.
317      */
printStackTrace(Appendable err, String indent, StackTraceElement[] parentStack)318     private void printStackTrace(Appendable err, String indent, StackTraceElement[] parentStack)
319             throws IOException {
320         err.append(toString());
321         err.append("\n");
322 
323         StackTraceElement[] stack = getInternalStackTrace();
324         if (stack != null) {
325             int duplicates = parentStack != null ? countDuplicates(stack, parentStack) : 0;
326             for (int i = 0; i < stack.length - duplicates; i++) {
327                 err.append(indent);
328                 err.append("\tat ");
329                 err.append(stack[i].toString());
330                 err.append("\n");
331             }
332 
333             if (duplicates > 0) {
334                 err.append(indent);
335                 err.append("\t... ");
336                 err.append(Integer.toString(duplicates));
337                 err.append(" more\n");
338             }
339         }
340 
341         // Print suppressed exceptions indented one level deeper.
342         if (suppressedExceptions != null) {
343             for (Throwable throwable : suppressedExceptions) {
344                 err.append(indent);
345                 err.append("\tSuppressed: ");
346                 throwable.printStackTrace(err, indent + "\t", stack);
347             }
348         }
349 
350         Throwable cause = getCause();
351         if (cause != null) {
352             err.append(indent);
353             err.append("Caused by: ");
354             cause.printStackTrace(err, indent, stack);
355         }
356     }
357 
358     @Override
toString()359     public String toString() {
360         String msg = getLocalizedMessage();
361         String name = getClass().getName();
362         if (msg == null) {
363             return name;
364         }
365         return name + ": " + msg;
366     }
367 
368     /**
369      * Initializes the cause of this {@code Throwable}. The cause can only be
370      * initialized once.
371      *
372      * @param throwable
373      *            the cause of this {@code Throwable}.
374      * @return this {@code Throwable} instance.
375      * @throws IllegalArgumentException
376      *             if {@code Throwable} is this object.
377      * @throws IllegalStateException
378      *             if the cause has already been initialized.
379      */
initCause(Throwable throwable)380     public Throwable initCause(Throwable throwable) {
381         if (cause != this) {
382             throw new IllegalStateException("Cause already initialized");
383         }
384         if (throwable == this) {
385             throw new IllegalArgumentException("throwable == this");
386         }
387         cause = throwable;
388         return this;
389     }
390 
391     /**
392      * Returns the cause of this {@code Throwable}, or {@code null} if there is
393      * no cause.
394      *
395      * @return Throwable this {@code Throwable}'s cause.
396      */
getCause()397     public Throwable getCause() {
398         if (cause == this) {
399             return null;
400         }
401         return cause;
402     }
403 
404     /**
405      * Adds {@code throwable} to the list of throwables suppressed by this. The
406      * throwable will included when this exception's stack trace is printed.
407      *
408      * @throws IllegalArgumentException if {@code throwable == this}.
409      * @throws NullPointerException if {@code throwable == null}.
410      * @since 1.7
411      * @hide 1.7
412      */
addSuppressed(Throwable throwable)413     public final void addSuppressed(Throwable throwable) {
414         if (throwable == this) {
415             throw new IllegalArgumentException("suppressed == this");
416         }
417         if (throwable == null) {
418             throw new NullPointerException("suppressed == null");
419         }
420         if (suppressedExceptions != null) {
421             suppressedExceptions.add(throwable);
422         }
423     }
424 
425     /**
426      * Returns the throwables suppressed by this.
427      *
428      * @since 1.7
429      * @hide 1.7
430      */
getSuppressed()431     public final Throwable[] getSuppressed() {
432         return (suppressedExceptions != null)
433                 ? suppressedExceptions.toArray(new Throwable[suppressedExceptions.size()])
434                 : EmptyArray.THROWABLE;
435     }
436 
writeObject(ObjectOutputStream out)437     private void writeObject(ObjectOutputStream out) throws IOException {
438         // ensure the stackTrace field is initialized
439         getInternalStackTrace();
440         out.defaultWriteObject();
441     }
442 
readObject(ObjectInputStream in)443     private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
444         in.defaultReadObject();
445 
446         if (suppressedExceptions != null) {
447             // the deserialized list may be unmodifiable, so just create a mutable copy
448             suppressedExceptions = new ArrayList<Throwable>(suppressedExceptions);
449         }
450     }
451 
452     /*
453      * Creates a compact, VM-specific collection of goodies, suitable for
454      * storing in the "stackState" field, based on the current thread's
455      * call stack.
456      */
nativeFillInStackTrace()457     private static native Object nativeFillInStackTrace();
458 
459     /*
460      * Creates an array of StackTraceElement objects from the data held
461      * in "stackState".
462      */
nativeGetStackTrace(Object stackState)463     private static native StackTraceElement[] nativeGetStackTrace(Object stackState);
464 }
465