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 18package java.lang; 19 20import java.io.IOException; 21import java.io.ObjectInputStream; 22import java.io.ObjectOutputStream; 23import java.io.PrintStream; 24import java.io.PrintWriter; 25import java.util.ArrayList; 26import java.util.Collections; 27import java.util.List; 28import 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 */ 50public 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 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 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 */ 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 */ 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 */ 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 */ 437 public final Throwable[] getSuppressed() { 438 return (suppressedExceptions != null && !suppressedExceptions.isEmpty()) 439 ? suppressedExceptions.toArray(new Throwable[suppressedExceptions.size()]) 440 : EmptyArray.THROWABLE; 441 } 442 443 private void writeObject(ObjectOutputStream out) throws IOException { 444 // ensure the stackTrace field is initialized 445 getInternalStackTrace(); 446 out.defaultWriteObject(); 447 } 448 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 */ 463 private static native Object nativeFillInStackTrace(); 464 465 /* 466 * Creates an array of StackTraceElement objects from the data held 467 * in "stackState". 468 */ 469 private static native StackTraceElement[] nativeGetStackTrace(Object stackState); 470} 471