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 } 465