• 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.ObjectOutputStream;
22 import java.io.PrintStream;
23 import java.io.PrintWriter;
24 
25 /**
26  * The superclass of all classes which can be thrown by the virtual machine. The
27  * two direct subclasses are recoverable exceptions ({@code Exception}) and
28  * unrecoverable errors ({@code Error}). This class provides common methods for
29  * accessing a string message which provides extra information about the
30  * circumstances in which the {@code Throwable} was created (basically an error
31  * message in most cases), and for saving a stack trace (that is, a record of
32  * the call stack at a particular point in time) which can be printed later.
33  * <p>
34  * A {@code Throwable} can also include a cause, which is a nested {@code
35  * Throwable} that represents the original problem that led to this {@code
36  * Throwable}. It is often used for wrapping various types of errors into a
37  * common {@code Throwable} without losing the detailed original error
38  * information. When printing the stack trace, the trace of the cause is
39  * included.
40  *
41  * @see Error
42  * @see Exception
43  * @see RuntimeException
44  *
45  * @since Android 1.0
46  */
47 public class Throwable implements java.io.Serializable {
48     private static final long serialVersionUID = -3042686055658047285L;
49 
50     /**
51      * The message provided when the exception was created.
52      */
53     private String detailMessage;
54 
55     /**
56      * The cause of this Throwable. Null when there is no cause.
57      */
58     private Throwable cause = this;
59 
60     // BEGIN android-added
61     /**
62      * An intermediate representation of the stack trace.  This field may
63      * be accessed by the VM; do not rename.
64      */
65     private volatile Object stackState;
66     // END android-added
67 
68     /**
69      * A fully-expanded representation of the stack trace.
70      */
71     private StackTraceElement[] stackTrace;
72 
73     /**
74      * Constructs a new {@code Throwable} that includes the current stack trace.
75      *
76      * @since Android 1.0
77      */
Throwable()78     public Throwable() {
79         super();
80         fillInStackTrace();
81     }
82 
83     /**
84      * Constructs a new {@code Throwable} with the current stack trace and the
85      * specified detail message.
86      *
87      * @param detailMessage
88      *            the detail message for this {@code Throwable}.
89      * @since Android 1.0
90      */
Throwable(String detailMessage)91     public Throwable(String detailMessage) {
92         this();
93         this.detailMessage = detailMessage;
94     }
95 
96     /**
97      * Constructs a new {@code Throwable} with the current stack trace, the
98      * specified detail message and the specified cause.
99      *
100      * @param detailMessage
101      *            the detail message for this {@code Throwable}.
102      * @param throwable
103      *            the cause of this {@code Throwable}.
104      * @since Android 1.0
105      */
Throwable(String detailMessage, Throwable throwable)106     public Throwable(String detailMessage, Throwable throwable) {
107         this();
108         this.detailMessage = detailMessage;
109         cause = throwable;
110     }
111 
112     /**
113      * Constructs a new {@code Throwable} with the current stack trace and the
114      * specified cause.
115      *
116      * @param throwable
117      *            the cause of this {@code Throwable}.
118      * @since Android 1.0
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     // BEGIN android-changed
127     /**
128      * Records the stack trace from the point where this method has been called
129      * to this {@code Throwable}. The method is public so that code which
130      * catches a {@code Throwable} and then re-throws it can adjust the stack
131      * trace to represent the location where the exception was re-thrown.
132      *
133      * @return this {@code Throwable} instance.
134      * @since Android 1.0
135      */
fillInStackTrace()136     public Throwable fillInStackTrace() {
137         // Fill in the intermediate representation
138         stackState = nativeFillInStackTrace();
139         // Mark the full representation as empty
140         stackTrace = null;
141         return this;
142     }
143     // END android-changed
144 
145     /**
146      * Returns the extra information message which was provided when this
147      * {@code Throwable} was created. Returns {@code null} if no message was
148      * provided at creation time.
149      *
150      * @return this {@code Throwable}'s detail message.
151      * @since Android 1.0
152      */
getMessage()153     public String getMessage() {
154         return detailMessage;
155     }
156 
157     /**
158      * Returns the extra information message which was provided when this
159      * {@code Throwable} was created. Returns {@code null} if no message was
160      * provided at creation time. Subclasses may override this method to return
161      * localized text for the message. The Android reference implementation
162      * returns the unlocalized detail message.
163      *
164      * @return this {@code Throwable}'s localized detail message.
165      * @since Android 1.0
166      */
getLocalizedMessage()167     public String getLocalizedMessage() {
168         return getMessage();
169     }
170 
171     /**
172      * Returns the array of stack trace elements of this {@code Throwable}. Each
173      * {@code StackTraceElement} represents an entry in the call stack. The
174      * element at position 0 is the top of the stack, that is, the stack frame
175      * where this {@code Throwable} is thrown.
176      *
177      * @return a copy of the array of {@code StackTraceElement}s representing
178      *         the call stack. Changes in the array obtained from this call will
179      *         not change the call stack stored in this {@code Throwable}.
180      * @see #printStackTrace()
181      * @since Android 1.0
182      */
getStackTrace()183     public StackTraceElement[] getStackTrace() {
184         return getInternalStackTrace().clone();
185     }
186 
187     /**
188      * Sets the array of stack trace elements. Each {@code StackTraceElement}
189      * represents an entry in the call stack. A copy of the specified array is
190      * stored in this {@code Throwable}. will be returned by {@code
191      * getStackTrace()} and printed by {@code printStackTrace()}.
192      *
193      * @param trace
194      *            the new array of {@code StackTraceElement}s. A copy of the
195      *            array is stored in this {@code Throwable}, so subsequent
196      *            changes to {@code trace} will not change the call stack stored
197      *            in this {@code Throwable}.
198      * @throws NullPointerException
199      *             if any element in {@code trace} is {@code null}.
200      * @see #printStackTrace()
201      * @since Android 1.0
202      */
setStackTrace(StackTraceElement[] trace)203     public void setStackTrace(StackTraceElement[] trace) {
204         StackTraceElement[] newTrace = trace.clone();
205         for (java.lang.StackTraceElement element : newTrace) {
206             if (element == null) {
207                 throw new NullPointerException();
208             }
209         }
210         stackTrace = newTrace;
211     }
212 
213     /**
214      * Writes a printable representation of this {@code Throwable}'s stack trace
215      * to the {@code System.err} stream.
216      *
217      * @since Android 1.0
218      */
printStackTrace()219     public void printStackTrace() {
220         printStackTrace(System.err);
221     }
222 
223     /**
224      * Counts the number of duplicate stack frames, starting from the
225      * end of the stack.
226      *
227      * @param currentStack a stack to compare
228      * @param parentStack a stack to compare
229      *
230      * @return the number of duplicate stack frames.
231      */
countDuplicates(StackTraceElement[] currentStack, StackTraceElement[] parentStack)232     private static int countDuplicates(StackTraceElement[] currentStack,
233             StackTraceElement[] parentStack) {
234         int duplicates = 0;
235         int parentIndex = parentStack.length;
236         for (int i = currentStack.length; --i >= 0 && --parentIndex >= 0;) {
237             StackTraceElement parentFrame = parentStack[parentIndex];
238             if (parentFrame.equals(currentStack[i])) {
239                 duplicates++;
240             } else {
241                 break;
242             }
243         }
244         return duplicates;
245     }
246 
247     /**
248      * Returns an array of StackTraceElement. Each StackTraceElement
249      * represents a entry on the stack.
250      *
251      * @return an array of StackTraceElement representing the stack
252      */
getInternalStackTrace()253     private StackTraceElement[] getInternalStackTrace() {
254         if (stackTrace == null) {
255             // BEGIN android-changed
256             stackTrace = nativeGetStackTrace(stackState);
257             stackState = null; // Clean up intermediate representation
258             // END android-changed
259         }
260         return stackTrace;
261     }
262 
263     /**
264      * Writes a printable representation of this {@code Throwable}'s stack trace
265      * to the specified print stream. If the {@code Throwable} contains a
266      * {@link #getCause() cause}, the method will be invoked recursively for
267      * the nested {@code Throwable}.
268      *
269      * @param err
270      *            the stream to write the stack trace on.
271      * @since Android 1.0
272      */
printStackTrace(PrintStream err)273     public void printStackTrace(PrintStream err) {
274         err.println(toString());
275         // Don't use getStackTrace() as it calls clone()
276         // Get stackTrace, in case stackTrace is reassigned
277         StackTraceElement[] stack = getInternalStackTrace();
278         for (java.lang.StackTraceElement element : stack) {
279             err.println("\tat " + element);
280         }
281 
282         StackTraceElement[] parentStack = stack;
283         Throwable throwable = getCause();
284         while (throwable != null) {
285             err.print("Caused by: ");
286             err.println(throwable);
287             StackTraceElement[] currentStack = throwable.getInternalStackTrace();
288             int duplicates = countDuplicates(currentStack, parentStack);
289             for (int i = 0; i < currentStack.length - duplicates; i++) {
290                 err.println("\tat " + currentStack[i]);
291             }
292             if (duplicates > 0) {
293                 err.println("\t... " + duplicates + " more");
294             }
295             parentStack = currentStack;
296             throwable = throwable.getCause();
297         }
298     }
299 
300     /**
301      * Writes a printable representation of this {@code Throwable}'s stack trace
302      * to the specified print writer. If the {@code Throwable} contains a
303      * {@link #getCause() cause}, the method will be invoked recursively for the
304      * nested {@code Throwable}.
305      *
306      * @param err
307      *            the writer to write the stack trace on.
308      * @since Android 1.0
309      */
printStackTrace(PrintWriter err)310     public void printStackTrace(PrintWriter err) {
311         err.println(toString());
312         // Don't use getStackTrace() as it calls clone()
313         // Get stackTrace, in case stackTrace is reassigned
314         StackTraceElement[] stack = getInternalStackTrace();
315         for (java.lang.StackTraceElement element : stack) {
316             err.println("\tat " + element);
317         }
318 
319         StackTraceElement[] parentStack = stack;
320         Throwable throwable = getCause();
321         while (throwable != null) {
322             err.print("Caused by: ");
323             err.println(throwable);
324             StackTraceElement[] currentStack = throwable.getInternalStackTrace();
325             int duplicates = countDuplicates(currentStack, parentStack);
326             for (int i = 0; i < currentStack.length - duplicates; i++) {
327                 err.println("\tat " + currentStack[i]);
328             }
329             if (duplicates > 0) {
330                 err.println("\t... " + duplicates + " more");
331             }
332             parentStack = currentStack;
333             throwable = throwable.getCause();
334         }
335     }
336 
337     @Override
toString()338     public String toString() {
339         String msg = getLocalizedMessage();
340         String name = getClass().getName();
341         if (msg == null) {
342             return name;
343         }
344         return new StringBuffer(name.length() + 2 + msg.length()).append(name).append(": ")
345                 .append(msg).toString();
346     }
347 
348     /**
349      * Initializes the cause of this {@code Throwable}. The cause can only be
350      * initialized once.
351      *
352      * @param throwable
353      *            the cause of this {@code Throwable}.
354      * @return this {@code Throwable} instance.
355      * @throws IllegalArgumentException
356      *             if {@code Throwable} is this object.
357      * @throws IllegalStateException
358      *             if the cause has already been initialized.
359      * @since Android 1.0
360      */
initCause(Throwable throwable)361     public Throwable initCause(Throwable throwable) {
362         // BEGIN android-note
363         // removed synchronized modifier
364         // END android-note
365         if (cause == this) {
366             if (throwable != this) {
367                 cause = throwable;
368                 return this;
369             }
370             throw new IllegalArgumentException("Cause cannot be the receiver");
371         }
372         throw new IllegalStateException("Cause already initialized");
373     }
374 
375     /**
376      * Returns the cause of this {@code Throwable}, or {@code null} if there is
377      * no cause.
378      *
379      * @return Throwable this {@code Throwable}'s cause.
380      * @since Android 1.0
381      */
getCause()382     public Throwable getCause() {
383         if (cause == this) {
384             return null;
385         }
386         return cause;
387     }
388 
writeObject(ObjectOutputStream s)389     private void writeObject(ObjectOutputStream s) throws IOException {
390         // ensure the stackTrace field is initialized
391         getInternalStackTrace();
392         s.defaultWriteObject();
393     }
394 
395     // BEGIN android-added
396     /*
397      * Creates a compact, VM-specific collection of goodies, suitable for
398      * storing in the "stackState" field, based on the current thread's
399      * call stack.
400      */
nativeFillInStackTrace()401     native private static Object nativeFillInStackTrace();
402 
403     /*
404      * Creates an array of StackTraceElement objects from the data held
405      * in "stackState".
406      */
nativeGetStackTrace(Object stackState)407     native private static StackTraceElement[] nativeGetStackTrace(Object stackState);
408     // END android-added
409 }
410 
411