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