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