1 /* java.lang.Throwable -- Root class for all Exceptions and Errors 2 Copyright (C) 1998, 1999, 2002 Free Software Foundation, Inc. 3 4 This file is part of GNU Classpath. 5 6 GNU Classpath is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2, or (at your option) 9 any later version. 10 11 GNU Classpath is distributed in the hope that it will be useful, but 12 WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with GNU Classpath; see the file COPYING. If not, write to the 18 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 19 02111-1307 USA. 20 21 Linking this library statically or dynamically with other modules is 22 making a combined work based on this library. Thus, the terms and 23 conditions of the GNU General Public License cover the whole 24 combination. 25 26 As a special exception, the copyright holders of this library give you 27 permission to link this library with independent modules to produce an 28 executable, regardless of the license terms of these independent 29 modules, and to copy and distribute the resulting executable under 30 terms of your choice, provided that you also meet, for each linked 31 independent module, the terms and conditions of the license of that 32 module. An independent module is a module which is not derived from 33 or based on this library. If you modify this library, you may extend 34 this exception to your version of the library, but you are not 35 obligated to do so. If you do not wish to do so, delete this 36 exception statement from your version. */ 37 38 package java.lang; 39 40 import java.io.Serializable; 41 import java.io.PrintWriter; 42 import java.io.PrintStream; 43 import java.io.ObjectOutputStream; 44 import java.io.ObjectInputStream; 45 import java.io.IOException; 46 import java.io.OutputStream; 47 48 /** 49 * Throwable is the superclass of all exceptions that can be raised. 50 * 51 * <p>There are two special cases: {@link Error} and {@link RuntimeException}: 52 * these two classes (and their subclasses) are considered unchecked 53 * exceptions, and are either frequent enough or catastrophic enough that you 54 * do not need to declare them in <code>throws</code> clauses. Everything 55 * else is a checked exception, and is ususally a subclass of 56 * {@link Exception}; these exceptions have to be handled or declared. 57 * 58 * <p>Instances of this class are usually created with knowledge of the 59 * execution context, so that you can get a stack trace of the problem spot 60 * in the code. Also, since JDK 1.4, Throwables participate in "exception 61 * chaining." This means that one exception can be caused by another, and 62 * preserve the information of the original. 63 * 64 * <p>One reason this is useful is to wrap exceptions to conform to an 65 * interface. For example, it would be bad design to require all levels 66 * of a program interface to be aware of the low-level exceptions thrown 67 * at one level of abstraction. Another example is wrapping a checked 68 * exception in an unchecked one, to communicate that failure occured 69 * while still obeying the method throws clause of a superclass. 70 * 71 * <p>A cause is assigned in one of two ways; but can only be assigned once 72 * in the lifetime of the Throwable. There are new constructors added to 73 * several classes in the exception hierarchy that directly initialize the 74 * cause, or you can use the <code>initCause</code> method. This second 75 * method is especially useful if the superclass has not been retrofitted 76 * with new constructors:<br> 77 * <pre> 78 * try 79 * { 80 * lowLevelOp(); 81 * } 82 * catch (LowLevelException lle) 83 * { 84 * throw (HighLevelException) new HighLevelException().initCause(lle); 85 * } 86 * </pre> 87 * Notice the cast in the above example; without it, your method would need 88 * a throws clase that declared Throwable, defeating the purpose of chainig 89 * your exceptions. 90 * 91 * <p>By convention, exception classes have two constructors: one with no 92 * arguments, and one that takes a String for a detail message. Further, 93 * classes which are likely to be used in an exception chain also provide 94 * a constructor that takes a Throwable, with or without a detail message 95 * string. 96 * 97 * <p>Another 1.4 feature is the StackTrace, a means of reflection that 98 * allows the program to inspect the context of the exception, and which is 99 * serialized, so that remote procedure calls can correctly pass exceptions. 100 * 101 * @author Brian Jones 102 * @author John Keiser 103 * @author Mark Wielaard 104 * @author Tom Tromey 105 * @author Eric Blake <ebb9@email.byu.edu> 106 * @since 1.0 107 * @status updated to 1.4 108 */ 109 public class Throwable implements Serializable 110 { 111 /** 112 * Compatible with JDK 1.0+. 113 */ 114 private static final long serialVersionUID = -3042686055658047285L; 115 116 /** 117 * The detail message. 118 * 119 * @serial specific details about the exception, may be null 120 */ 121 private final String detailMessage; 122 123 /** 124 * The cause of the throwable, including null for an unknown or non-chained 125 * cause. This may only be set once; so the field is set to 126 * <code>this</code> until initialized. 127 * 128 * @serial the cause, or null if unknown, or this if not yet set 129 * @since 1.4 130 */ 131 private Throwable cause = this; 132 133 /** 134 * The stack trace, in a serialized form. 135 * 136 * @serial the elements of the stack trace; this is non-null, and has 137 * no null entries 138 * @since 1.4 139 */ 140 private StackTraceElement[] stackTrace; 141 142 /** 143 * Instantiate this Throwable with an empty message. The cause remains 144 * uninitialized. {@link #fillInStackTrace()} will be called to set 145 * up the stack trace. 146 */ Throwable()147 public Throwable() 148 { 149 this((String) null); 150 } 151 152 /** 153 * Instantiate this Throwable with the given message. The cause remains 154 * uninitialized. {@link #fillInStackTrace()} will be called to set 155 * up the stack trace. 156 * 157 * @param message the message to associate with the Throwable 158 */ Throwable(String message)159 public Throwable(String message) 160 { 161 fillInStackTrace(); 162 detailMessage = message; 163 } 164 165 /** 166 * Instantiate this Throwable with the given message and cause. Note that 167 * the message is unrelated to the message of the cause. 168 * {@link #fillInStackTrace()} will be called to set up the stack trace. 169 * 170 * @param message the message to associate with the Throwable 171 * @param cause the cause, may be null 172 * @since 1.4 173 */ Throwable(String message, Throwable cause)174 public Throwable(String message, Throwable cause) 175 { 176 this(message); 177 initCause(cause); 178 } 179 180 /** 181 * Instantiate this Throwable with the given cause. The message is then 182 * built as <code>cause == null ? null : cause.toString()</code>. 183 * {@link #fillInStackTrace()} will be called to set up the stack trace. 184 * 185 * @param cause the cause, may be null 186 * @since 1.4 187 */ Throwable(Throwable cause)188 public Throwable(Throwable cause) 189 { 190 this(cause == null ? null : cause.toString(), cause); 191 } 192 193 /** 194 * Get the message associated with this Throwable. 195 * 196 * @return the error message associated with this Throwable, may be null 197 */ getMessage()198 public String getMessage() 199 { 200 return detailMessage; 201 } 202 203 /** 204 * Get a localized version of this Throwable's error message. 205 * This method must be overridden in a subclass of Throwable 206 * to actually produce locale-specific methods. The Throwable 207 * implementation just returns getMessage(). 208 * 209 * @return a localized version of this error message 210 * @see #getMessage() 211 * @since 1.1 212 */ getLocalizedMessage()213 public String getLocalizedMessage() 214 { 215 return getMessage(); 216 } 217 218 /** 219 * Returns the cause of this exception, or null if the cause is not known 220 * or non-existant. This cause is initialized by the new constructors, 221 * or by calling initCause. 222 * 223 * @return the cause of this Throwable 224 * @since 1.4 225 */ getCause()226 public Throwable getCause() 227 { 228 return cause == this ? null : cause; 229 } 230 231 /** 232 * Initialize the cause of this Throwable. This may only be called once 233 * during the object lifetime, including implicitly by chaining 234 * constructors. 235 * 236 * @param cause the cause of this Throwable, may be null 237 * @return this 238 * @throws IllegalArgumentException if cause is this (a Throwable can't be 239 * its own cause!) 240 * @throws IllegalStateException if the cause has already been set 241 * @since 1.4 242 */ initCause(Throwable cause)243 public Throwable initCause(Throwable cause) 244 { 245 if (cause == this) 246 throw new IllegalArgumentException(); 247 if (this.cause != this) 248 throw new IllegalStateException(); 249 this.cause = cause; 250 return this; 251 } 252 253 /** 254 * Get a human-readable representation of this Throwable. The detail message 255 * is retrieved by getLocalizedMessage(). Then, with a null detail 256 * message, this string is simply the object's class name; otherwise 257 * the string is <code>getClass().getName() + ": " + message</code>. 258 * 259 * @return a human-readable String represting this Throwable 260 */ toString()261 public String toString() 262 { 263 String msg = getLocalizedMessage(); 264 return getClass().getName() + (msg == null ? "" : ": " + msg); 265 } 266 267 /** 268 * Print a stack trace to the standard error stream. This stream is the 269 * current contents of <code>System.err</code>. The first line of output 270 * is the result of {@link #toString()}, and the remaining lines represent 271 * the data created by {@link #fillInStackTrace()}. While the format is 272 * unspecified, this implementation uses the suggested format, demonstrated 273 * by this example:<br> 274 * <pre> 275 * public class Junk 276 * { 277 * public static void main(String args[]) 278 * { 279 * try 280 * { 281 * a(); 282 * } 283 * catch(HighLevelException e) 284 * { 285 * e.printStackTrace(); 286 * } 287 * } 288 * static void a() throws HighLevelException 289 * { 290 * try 291 * { 292 * b(); 293 * } 294 * catch(MidLevelException e) 295 * { 296 * throw new HighLevelException(e); 297 * } 298 * } 299 * static void b() throws MidLevelException 300 * { 301 * c(); 302 * } 303 * static void c() throws MidLevelException 304 * { 305 * try 306 * { 307 * d(); 308 * } 309 * catch(LowLevelException e) 310 * { 311 * throw new MidLevelException(e); 312 * } 313 * } 314 * static void d() throws LowLevelException 315 * { 316 * e(); 317 * } 318 * static void e() throws LowLevelException 319 * { 320 * throw new LowLevelException(); 321 * } 322 * } 323 * class HighLevelException extends Exception 324 * { 325 * HighLevelException(Throwable cause) { super(cause); } 326 * } 327 * class MidLevelException extends Exception 328 * { 329 * MidLevelException(Throwable cause) { super(cause); } 330 * } 331 * class LowLevelException extends Exception 332 * { 333 * } 334 * </pre> 335 * <p> 336 * <pre> 337 * HighLevelException: MidLevelException: LowLevelException 338 * at Junk.a(Junk.java:13) 339 * at Junk.main(Junk.java:4) 340 * Caused by: MidLevelException: LowLevelException 341 * at Junk.c(Junk.java:23) 342 * at Junk.b(Junk.java:17) 343 * at Junk.a(Junk.java:11) 344 * ... 1 more 345 * Caused by: LowLevelException 346 * at Junk.e(Junk.java:30) 347 * at Junk.d(Junk.java:27) 348 * at Junk.c(Junk.java:21) 349 * ... 3 more 350 * </pre> 351 */ printStackTrace()352 public void printStackTrace() 353 { 354 printStackTrace(System.err); 355 } 356 357 /** 358 * Print a stack trace to the specified PrintStream. See 359 * {@link #printStackTrace()} for the sample format. 360 * 361 * @param s the PrintStream to write the trace to 362 */ printStackTrace(PrintStream s)363 public void printStackTrace(PrintStream s) 364 { 365 s.print(stackTraceString()); 366 } 367 368 /** 369 * Prints the exception, the detailed message and the stack trace 370 * associated with this Throwable to the given <code>PrintWriter</code>. 371 * The actual output written is implemention specific. Use the result of 372 * <code>getStackTrace()</code> when more precise information is needed. 373 * 374 * <p>This implementation first prints a line with the result of this 375 * object's <code>toString()</code> method. 376 * <br> 377 * Then for all elements given by <code>getStackTrace</code> it prints 378 * a line containing three spaces, the string "at " and the result of calling 379 * the <code>toString()</code> method on the <code>StackTraceElement</code> 380 * object. If <code>getStackTrace()</code> returns an empty array it prints 381 * a line containing three spaces and the string 382 * "<<No stacktrace available>>". 383 * <br> 384 * Then if <code>getCause()</code> doesn't return null it adds a line 385 * starting with "Caused by: " and the result of calling 386 * <code>toString()</code> on the cause. 387 * <br> 388 * Then for every cause (of a cause, etc) the stacktrace is printed the 389 * same as for the top level <code>Throwable</code> except that as soon 390 * as all the remaining stack frames of the cause are the same as the 391 * the last stack frames of the throwable that the cause is wrapped in 392 * then a line starting with three spaces and the string "... X more" is 393 * printed, where X is the number of remaining stackframes. 394 * 395 * @param w the PrintWriter to write the trace to 396 * @since 1.1 397 */ printStackTrace(PrintWriter pw)398 public void printStackTrace (PrintWriter pw) 399 { 400 pw.print(stackTraceString()); 401 } 402 403 private static final String nl = System.getProperty("line.separator"); 404 // Create whole stack trace in a stringbuffer so we don't have to print 405 // it line by line. This prevents printing multiple stack traces from 406 // different threads to get mixed up when written to the same PrintWriter. stackTraceString()407 private String stackTraceString() 408 { 409 StringBuffer sb = new StringBuffer(); 410 411 // Main stacktrace 412 StackTraceElement[] stack = getStackTrace(); 413 stackTraceStringBuffer(sb, this.toString(), stack, 0); 414 415 // The cause(s) 416 Throwable cause = getCause(); 417 while (cause != null) 418 { 419 // Cause start first line 420 sb.append("Caused by: "); 421 422 // Cause stacktrace 423 StackTraceElement[] parentStack = stack; 424 stack = cause.getStackTrace(); 425 if (parentStack == null || parentStack.length == 0) 426 stackTraceStringBuffer(sb, cause.toString(), stack, 0); 427 else 428 { 429 int equal = 0; // Count how many of the last stack frames are equal 430 int frame = stack.length-1; 431 int parentFrame = parentStack.length-1; 432 while (frame > 0 && parentFrame > 0) 433 { 434 if (stack[frame].equals(parentStack[parentFrame])) 435 { 436 equal++; 437 frame--; 438 parentFrame--; 439 } 440 else 441 break; 442 } 443 stackTraceStringBuffer(sb, cause.toString(), stack, equal); 444 } 445 cause = cause.getCause(); 446 } 447 448 return sb.toString(); 449 } 450 451 // Adds to the given StringBuffer a line containing the name and 452 // all stacktrace elements minus the last equal ones. stackTraceStringBuffer(StringBuffer sb, String name, StackTraceElement[] stack, int equal)453 private static void stackTraceStringBuffer(StringBuffer sb, String name, 454 StackTraceElement[] stack, int equal) 455 { 456 // (finish) first line 457 sb.append(name); 458 sb.append(nl); 459 460 // The stacktrace 461 if (stack == null || stack.length == 0) 462 { 463 sb.append(" <<No stacktrace available>>"); 464 sb.append(nl); 465 } 466 else 467 { 468 for (int i = 0; i < stack.length-equal; i++) 469 { 470 sb.append(" at "); 471 sb.append(stack[i] == null ? "<<Unknown>>" : stack[i].toString()); 472 sb.append(nl); 473 } 474 if (equal > 0) 475 { 476 sb.append(" ..."); 477 sb.append(equal); 478 sb.append(" more"); 479 sb.append(nl); 480 } 481 } 482 } 483 484 /** 485 * Fill in the stack trace with the current execution stack. 486 * 487 * @return this same throwable 488 * @see #printStackTrace() 489 */ fillInStackTrace()490 public Throwable fillInStackTrace() 491 { 492 vmState = VMThrowable.fillInStackTrace(this); 493 stackTrace = null; // Should be regenerated when used. 494 495 return this; 496 } 497 498 /** 499 * Provides access to the information printed in {@link #printStackTrace()}. 500 * The array is non-null, with no null entries, although the virtual 501 * machine is allowed to skip stack frames. If the array is not 0-length, 502 * then slot 0 holds the information on the stack frame where the Throwable 503 * was created (or at least where <code>fillInStackTrace()</code> was 504 * called). 505 * 506 * @return an array of stack trace information, as available from the VM 507 * @since 1.4 508 */ getStackTrace()509 public StackTraceElement[] getStackTrace() 510 { 511 if (stackTrace == null) 512 if (vmState == null) 513 stackTrace = new StackTraceElement[0]; 514 else 515 { 516 stackTrace = vmState.getStackTrace(this); 517 vmState = null; // No longer needed 518 } 519 520 return stackTrace; 521 } 522 523 /** 524 * Change the stack trace manually. This method is designed for remote 525 * procedure calls, which intend to alter the stack trace before or after 526 * serialization according to the context of the remote call. 527 * <p> 528 * The contents of the given stacktrace is copied so changes to the 529 * original array do not change the stack trace elements of this 530 * throwable. 531 * 532 * @param stackTrace the new trace to use 533 * @throws NullPointerException if stackTrace is null or has null elements 534 * @since 1.4 535 */ setStackTrace(StackTraceElement[] stackTrace)536 public void setStackTrace(StackTraceElement[] stackTrace) 537 { 538 int i = stackTrace.length; 539 StackTraceElement[] st = new StackTraceElement[i]; 540 541 while (--i >= 0) 542 { 543 st[i] = stackTrace[i]; 544 if (st[i] == null) 545 throw new NullPointerException("Element " + i + " null"); 546 } 547 548 this.stackTrace = st; 549 } 550 551 /** 552 * VM state when fillInStackTrace was called. 553 * Used by getStackTrace() to get an array of StackTraceElements. 554 * Cleared when no longer needed. 555 */ 556 private transient VMThrowable vmState; 557 } 558