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 * 39 * <p>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 */ 83 public Throwable() { 84 this.stackTrace = EmptyArray.STACK_TRACE_ELEMENT; 85 fillInStackTrace(); 86 } 87 88 /** 89 * Constructs a new {@code Throwable} with the current stack trace and the 90 * given detail message. 91 */ 92 public Throwable(String detailMessage) { 93 this.detailMessage = detailMessage; 94 this.stackTrace = EmptyArray.STACK_TRACE_ELEMENT; 95 fillInStackTrace(); 96 } 97 98 /** 99 * Constructs a new {@code Throwable} with the current stack trace, the 100 * given detail message and cause. 101 */ 102 public Throwable(String detailMessage, Throwable cause) { 103 this.detailMessage = detailMessage; 104 this.cause = cause; 105 this.stackTrace = EmptyArray.STACK_TRACE_ELEMENT; 106 fillInStackTrace(); 107 } 108 109 /** 110 * Constructs a new {@code Throwable} with the current stack trace and the 111 * given cause. 112 */ 113 public Throwable(Throwable cause) { 114 this.detailMessage = cause == null ? null : cause.toString(); 115 this.cause = cause; 116 this.stackTrace = EmptyArray.STACK_TRACE_ELEMENT; 117 fillInStackTrace(); 118 } 119 120 /** 121 * Constructs a new {@code Throwable} with the current stack trace, the 122 * specified detail message and the specified cause. 123 * 124 * @param enableSuppression if false, {@link #addSuppressed(Throwable)} will be a no-op. 125 * @param writableStackTrace if false, {@link #fillInStackTrace} will not be called, 126 * this object's {@code stackTrace} will be null, 127 * calls to {@link #fillInStackTrace} and {@link #setStackTrace} will be no-ops, 128 * and {@link #getStackTrace} will return a zero-length array. 129 * @since 1.7 130 */ 131 protected Throwable(String detailMessage, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { 132 this.detailMessage = detailMessage; 133 this.cause = cause; 134 if (!enableSuppression) { 135 this.suppressedExceptions = null; 136 } 137 if (writableStackTrace) { 138 this.stackTrace = EmptyArray.STACK_TRACE_ELEMENT; 139 fillInStackTrace(); 140 } else { 141 this.stackTrace = null; 142 } 143 } 144 145 /** 146 * Records the stack trace from the point where this method has been called 147 * to this {@code Throwable}. This method is invoked by the {@code Throwable} constructors. 148 * 149 * <p>This method is public so that code (such as an RPC system) which catches 150 * a {@code Throwable} and then re-throws it can replace the construction-time stack trace 151 * with a stack trace from the location where the exception was re-thrown, by <i>calling</i> 152 * {@code fillInStackTrace}. 153 * 154 * <p>This method is non-final so that non-Java language implementations can disable VM stack 155 * traces for their language. Filling in the stack trace is relatively expensive. 156 * <i>Overriding</i> this method in the root of a language's exception hierarchy allows the 157 * language to avoid paying for something it doesn't need. 158 * 159 * @return this {@code Throwable} instance. 160 */ 161 public Throwable fillInStackTrace() { 162 if (stackTrace == null) { 163 return this; // writableStackTrace was false. 164 } 165 // Fill in the intermediate representation. 166 stackState = nativeFillInStackTrace(); 167 // Mark the full representation as in need of update. 168 stackTrace = EmptyArray.STACK_TRACE_ELEMENT; 169 return this; 170 } 171 172 /** 173 * Returns the detail message which was provided when this 174 * {@code Throwable} was created. Returns {@code null} if no message was 175 * provided at creation time. 176 */ 177 public String getMessage() { 178 return detailMessage; 179 } 180 181 /** 182 * Returns the detail message which was provided when this 183 * {@code Throwable} was created. Returns {@code null} if no message was 184 * provided at creation time. Subclasses may override this method to return 185 * localized text for the message. Android returns the regular detail message. 186 */ 187 public String getLocalizedMessage() { 188 return getMessage(); 189 } 190 191 /** 192 * Returns a clone of the array of stack trace elements of this {@code Throwable}. Each 193 * {@code StackTraceElement} represents an entry in the call stack. The 194 * element at position 0 is the top of the stack, that is, the stack frame 195 * where this {@code Throwable} is thrown. 196 * 197 * @see #printStackTrace() 198 */ 199 public StackTraceElement[] getStackTrace() { 200 return getInternalStackTrace().clone(); 201 } 202 203 /** 204 * Sets the array of stack trace elements. Each {@code StackTraceElement} 205 * represents an entry in the call stack. A copy of the specified array is 206 * stored in this {@code Throwable}. will be returned by {@code 207 * getStackTrace()} and printed by {@code printStackTrace()}. 208 * 209 * @param trace 210 * the new array of {@code StackTraceElement}s. A copy of the 211 * array is stored in this {@code Throwable}, so subsequent 212 * changes to {@code trace} will not change the call stack stored 213 * in this {@code Throwable}. 214 * @throws NullPointerException 215 * if any element in {@code trace} is {@code null}. 216 * @see #printStackTrace() 217 */ 218 public void setStackTrace(StackTraceElement[] trace) { 219 if (stackTrace == null) { 220 return; // writableStackTrace was false. 221 } 222 StackTraceElement[] newTrace = trace.clone(); 223 for (int i = 0; i < newTrace.length; i++) { 224 if (newTrace[i] == null) { 225 throw new NullPointerException("trace[" + i + "] == null"); 226 } 227 } 228 stackTrace = newTrace; 229 } 230 231 /** 232 * Writes a printable representation of this {@code Throwable}'s stack trace 233 * to the {@code System.err} stream. 234 */ 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 private static int countDuplicates(StackTraceElement[] currentStack, 244 StackTraceElement[] parentStack) { 245 int duplicates = 0; 246 int parentIndex = parentStack.length; 247 for (int i = currentStack.length; --i >= 0 && --parentIndex >= 0;) { 248 StackTraceElement parentFrame = parentStack[parentIndex]; 249 if (parentFrame.equals(currentStack[i])) { 250 duplicates++; 251 } else { 252 break; 253 } 254 } 255 return duplicates; 256 } 257 258 /** 259 * Returns an array of StackTraceElement. Each StackTraceElement 260 * represents a entry on the stack. 261 */ 262 private StackTraceElement[] getInternalStackTrace() { 263 if (stackTrace == EmptyArray.STACK_TRACE_ELEMENT) { 264 stackTrace = nativeGetStackTrace(stackState); 265 stackState = null; // Let go of intermediate representation. 266 return stackTrace; 267 } else if (stackTrace == null) { 268 return EmptyArray.STACK_TRACE_ELEMENT; 269 } else { 270 return stackTrace; 271 } 272 } 273 274 /** 275 * Writes a printable representation of this {@code Throwable}'s stack trace 276 * to the given print stream. If the {@code Throwable} contains a 277 * {@link #getCause() cause}, the method will be invoked recursively for 278 * the nested {@code Throwable}. 279 */ 280 public void printStackTrace(PrintStream err) { 281 try { 282 printStackTrace(err, "", null); 283 } catch (IOException e) { 284 // Appendable.append throws IOException but PrintStream.append doesn't. 285 throw new AssertionError(); 286 } 287 } 288 289 /** 290 * Writes a printable representation of this {@code Throwable}'s stack trace 291 * to the specified print writer. If the {@code Throwable} contains a 292 * {@link #getCause() cause}, the method will be invoked recursively for the 293 * nested {@code Throwable}. 294 * 295 * @param err 296 * the writer to write the stack trace on. 297 */ 298 public void printStackTrace(PrintWriter err) { 299 try { 300 printStackTrace(err, "", null); 301 } catch (IOException e) { 302 // Appendable.append throws IOException, but PrintWriter.append doesn't. 303 throw new AssertionError(); 304 } 305 } 306 307 /** 308 * @param indent additional indentation on each line of the stack trace. 309 * This is the empty string for all but suppressed throwables. 310 * @param parentStack the parent stack trace to suppress duplicates from, or 311 * null if this stack trace has no parent. 312 */ 313 private void printStackTrace(Appendable err, String indent, StackTraceElement[] parentStack) 314 throws IOException { 315 err.append(toString()); 316 err.append("\n"); 317 318 StackTraceElement[] stack = getInternalStackTrace(); 319 if (stack != null) { 320 int duplicates = parentStack != null ? countDuplicates(stack, parentStack) : 0; 321 for (int i = 0; i < stack.length - duplicates; i++) { 322 err.append(indent); 323 err.append("\tat "); 324 err.append(stack[i].toString()); 325 err.append("\n"); 326 } 327 328 if (duplicates > 0) { 329 err.append(indent); 330 err.append("\t... "); 331 err.append(Integer.toString(duplicates)); 332 err.append(" more\n"); 333 } 334 } 335 336 // Print suppressed exceptions indented one level deeper. 337 if (suppressedExceptions != null) { 338 for (Throwable throwable : suppressedExceptions) { 339 err.append(indent); 340 err.append("\tSuppressed: "); 341 throwable.printStackTrace(err, indent + "\t", stack); 342 } 343 } 344 345 Throwable cause = getCause(); 346 if (cause != null) { 347 err.append(indent); 348 err.append("Caused by: "); 349 cause.printStackTrace(err, indent, stack); 350 } 351 } 352 353 @Override 354 public String toString() { 355 String msg = getLocalizedMessage(); 356 String name = getClass().getName(); 357 if (msg == null) { 358 return name; 359 } 360 return name + ": " + msg; 361 } 362 363 /** 364 * Initializes the cause of this {@code Throwable}. The cause can only be 365 * initialized once. 366 * 367 * @param throwable 368 * the cause of this {@code Throwable}. 369 * @return this {@code Throwable} instance. 370 * @throws IllegalArgumentException 371 * if {@code Throwable} is this object. 372 * @throws IllegalStateException 373 * if the cause has already been initialized. 374 */ 375 public Throwable initCause(Throwable throwable) { 376 if (cause != this) { 377 throw new IllegalStateException("Cause already initialized"); 378 } 379 if (throwable == this) { 380 throw new IllegalArgumentException("throwable == this"); 381 } 382 cause = throwable; 383 return this; 384 } 385 386 /** 387 * Returns the cause of this {@code Throwable}, or {@code null} if there is 388 * no cause. 389 */ 390 public Throwable getCause() { 391 if (cause == this) { 392 return null; 393 } 394 return cause; 395 } 396 397 /** 398 * Adds {@code throwable} to the list of throwables suppressed by this. The 399 * throwable will included when this exception's stack trace is printed. 400 * 401 * @throws IllegalArgumentException if {@code throwable == this}. 402 * @throws NullPointerException if {@code throwable == null}. 403 * @since 1.7 404 */ 405 public final void addSuppressed(Throwable throwable) { 406 if (throwable == this) { 407 throw new IllegalArgumentException("throwable == this"); 408 } 409 if (throwable == null) { 410 throw new NullPointerException("throwable == null"); 411 } 412 if (suppressedExceptions != null) { 413 // Suppressed exceptions are enabled. 414 if (suppressedExceptions.isEmpty()) { 415 // Ensure we have somewhere to place suppressed exceptions. 416 suppressedExceptions = new ArrayList<Throwable>(1); 417 } 418 suppressedExceptions.add(throwable); 419 } 420 } 421 422 /** 423 * Returns the throwables suppressed by this. 424 * 425 * @since 1.7 426 */ 427 public final Throwable[] getSuppressed() { 428 return (suppressedExceptions != null && !suppressedExceptions.isEmpty()) 429 ? suppressedExceptions.toArray(new Throwable[suppressedExceptions.size()]) 430 : EmptyArray.THROWABLE; 431 } 432 433 private void writeObject(ObjectOutputStream out) throws IOException { 434 // Ensure the stackTrace field is initialized. 435 getInternalStackTrace(); 436 out.defaultWriteObject(); 437 } 438 439 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { 440 in.defaultReadObject(); 441 442 if (suppressedExceptions != null) { 443 // The deserialized list may be unmodifiable, so just create a mutable copy. 444 suppressedExceptions = new ArrayList<Throwable>(suppressedExceptions); 445 } 446 } 447 448 /* 449 * Creates a compact, VM-specific collection of goodies, suitable for 450 * storing in the "stackState" field, based on the current thread's 451 * call stack. 452 */ 453 private static native Object nativeFillInStackTrace(); 454 455 /* 456 * Creates an array of StackTraceElement objects from the data held 457 * in "stackState". 458 */ 459 private static native StackTraceElement[] nativeGetStackTrace(Object stackState); 460 } 461