![]()
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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
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 */
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 */
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 */
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 */
431 public final Throwable[] getSuppressed() {
432 return (suppressedExceptions != null)
433 ? suppressedExceptions.toArray(new Throwable[suppressedExceptions.size()])
434 : EmptyArray.THROWABLE;
435 }
436
437 private void writeObject(ObjectOutputStream out) throws IOException {
438 // ensure the stackTrace field is initialized
439 getInternalStackTrace();
440 out.defaultWriteObject();
441 }
442
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 */
457 private static native Object nativeFillInStackTrace();
458
459 /*
460 * Creates an array of StackTraceElement objects from the data held
461 * in "stackState".
462 */
463 private static native StackTraceElement[] nativeGetStackTrace(Object stackState);
464 }