001/* java.lang.Throwable -- Root class for all Exceptions and Errors 002 Copyright (C) 1998, 1999, 2002, 2004, 2005 Free Software Foundation, Inc. 003 004This file is part of GNU Classpath. 005 006GNU Classpath is free software; you can redistribute it and/or modify 007it under the terms of the GNU General Public License as published by 008the Free Software Foundation; either version 2, or (at your option) 009any later version. 010 011GNU Classpath is distributed in the hope that it will be useful, but 012WITHOUT ANY WARRANTY; without even the implied warranty of 013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014General Public License for more details. 015 016You should have received a copy of the GNU General Public License 017along with GNU Classpath; see the file COPYING. If not, write to the 018Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 01902110-1301 USA. 020 021Linking this library statically or dynamically with other modules is 022making a combined work based on this library. Thus, the terms and 023conditions of the GNU General Public License cover the whole 024combination. 025 026As a special exception, the copyright holders of this library give you 027permission to link this library with independent modules to produce an 028executable, regardless of the license terms of these independent 029modules, and to copy and distribute the resulting executable under 030terms of your choice, provided that you also meet, for each linked 031independent module, the terms and conditions of the license of that 032module. An independent module is a module which is not derived from 033or based on this library. If you modify this library, you may extend 034this exception to your version of the library, but you are not 035obligated to do so. If you do not wish to do so, delete this 036exception statement from your version. */ 037 038package java.lang; 039 040import gnu.classpath.SystemProperties; 041 042import gnu.java.lang.CPStringBuilder; 043 044import java.io.PrintStream; 045import java.io.PrintWriter; 046import java.io.Serializable; 047 048/** 049 * Throwable is the superclass of all exceptions that can be raised. 050 * 051 * <p>There are two special cases: {@link Error} and {@link RuntimeException}: 052 * these two classes (and their subclasses) are considered unchecked 053 * exceptions, and are either frequent enough or catastrophic enough that you 054 * do not need to declare them in <code>throws</code> clauses. Everything 055 * else is a checked exception, and is ususally a subclass of 056 * {@link Exception}; these exceptions have to be handled or declared. 057 * 058 * <p>Instances of this class are usually created with knowledge of the 059 * execution context, so that you can get a stack trace of the problem spot 060 * in the code. Also, since JDK 1.4, Throwables participate in "exception 061 * chaining." This means that one exception can be caused by another, and 062 * preserve the information of the original. 063 * 064 * <p>One reason this is useful is to wrap exceptions to conform to an 065 * interface. For example, it would be bad design to require all levels 066 * of a program interface to be aware of the low-level exceptions thrown 067 * at one level of abstraction. Another example is wrapping a checked 068 * exception in an unchecked one, to communicate that failure occured 069 * while still obeying the method throws clause of a superclass. 070 * 071 * <p>A cause is assigned in one of two ways; but can only be assigned once 072 * in the lifetime of the Throwable. There are new constructors added to 073 * several classes in the exception hierarchy that directly initialize the 074 * cause, or you can use the <code>initCause</code> method. This second 075 * method is especially useful if the superclass has not been retrofitted 076 * with new constructors:<br> 077 * <pre> 078 * try 079 * { 080 * lowLevelOp(); 081 * } 082 * catch (LowLevelException lle) 083 * { 084 * throw (HighLevelException) new HighLevelException().initCause(lle); 085 * } 086 * </pre> 087 * Notice the cast in the above example; without it, your method would need 088 * a throws clase that declared Throwable, defeating the purpose of chainig 089 * your exceptions. 090 * 091 * <p>By convention, exception classes have two constructors: one with no 092 * arguments, and one that takes a String for a detail message. Further, 093 * classes which are likely to be used in an exception chain also provide 094 * a constructor that takes a Throwable, with or without a detail message 095 * string. 096 * 097 * <p>Another 1.4 feature is the StackTrace, a means of reflection that 098 * allows the program to inspect the context of the exception, and which is 099 * 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 */ 109public 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 */ 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 */ 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 */ 174 public Throwable(String message, Throwable cause) 175 { 176 this(message); 177 this.cause = 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 pw the PrintWriter to write the trace to 396 * @since 1.1 397 */ 398 public void printStackTrace (PrintWriter pw) 399 { 400 pw.print(stackTraceString()); 401 } 402 403 /* 404 * We use inner class to avoid a static initializer in this basic class. 405 */ 406 private static class StaticData 407 { 408 static final String nl = SystemProperties.getProperty("line.separator"); 409 } 410 411 // Create whole stack trace in a stringbuffer so we don't have to print 412 // it line by line. This prevents printing multiple stack traces from 413 // different threads to get mixed up when written to the same PrintWriter. 414 private String stackTraceString() 415 { 416 CPStringBuilder sb = new CPStringBuilder(); 417 418 // Main stacktrace 419 StackTraceElement[] stack = getStackTrace(); 420 stackTraceStringBuffer(sb, this.toString(), stack, 0); 421 422 // The cause(s) 423 Throwable cause = getCause(); 424 while (cause != null) 425 { 426 // Cause start first line 427 sb.append("Caused by: "); 428 429 // Cause stacktrace 430 StackTraceElement[] parentStack = stack; 431 stack = cause.getStackTrace(); 432 if (parentStack == null || parentStack.length == 0) 433 stackTraceStringBuffer(sb, cause.toString(), stack, 0); 434 else 435 { 436 int equal = 0; // Count how many of the last stack frames are equal 437 int frame = stack.length-1; 438 int parentFrame = parentStack.length-1; 439 while (frame > 0 && parentFrame > 0) 440 { 441 if (stack[frame].equals(parentStack[parentFrame])) 442 { 443 equal++; 444 frame--; 445 parentFrame--; 446 } 447 else 448 break; 449 } 450 stackTraceStringBuffer(sb, cause.toString(), stack, equal); 451 } 452 cause = cause.getCause(); 453 } 454 455 return sb.toString(); 456 } 457 458 // Adds to the given StringBuffer a line containing the name and 459 // all stacktrace elements minus the last equal ones. 460 private static void stackTraceStringBuffer(CPStringBuilder sb, String name, 461 StackTraceElement[] stack, int equal) 462 { 463 String nl = StaticData.nl; 464 // (finish) first line 465 sb.append(name); 466 sb.append(nl); 467 468 // The stacktrace 469 if (stack == null || stack.length == 0) 470 { 471 sb.append(" <<No stacktrace available>>"); 472 sb.append(nl); 473 } 474 else 475 { 476 for (int i = 0; i < stack.length-equal; i++) 477 { 478 sb.append(" at "); 479 sb.append(stack[i] == null ? "<<Unknown>>" : stack[i].toString()); 480 sb.append(nl); 481 } 482 if (equal > 0) 483 { 484 sb.append(" ..."); 485 sb.append(equal); 486 sb.append(" more"); 487 sb.append(nl); 488 } 489 } 490 } 491 492 /** 493 * Fill in the stack trace with the current execution stack. 494 * 495 * @return this same throwable 496 * @see #printStackTrace() 497 */ 498 public Throwable fillInStackTrace() 499 { 500 vmState = VMThrowable.fillInStackTrace(this); 501 stackTrace = null; // Should be regenerated when used. 502 503 return this; 504 } 505 506 /** 507 * Provides access to the information printed in {@link #printStackTrace()}. 508 * The array is non-null, with no null entries, although the virtual 509 * machine is allowed to skip stack frames. If the array is not 0-length, 510 * then slot 0 holds the information on the stack frame where the Throwable 511 * was created (or at least where <code>fillInStackTrace()</code> was 512 * called). 513 * 514 * @return an array of stack trace information, as available from the VM 515 * @since 1.4 516 */ 517 public StackTraceElement[] getStackTrace() 518 { 519 if (stackTrace == null) 520 if (vmState == null) 521 stackTrace = new StackTraceElement[0]; 522 else 523 { 524 stackTrace = vmState.getStackTrace(this); 525 vmState = null; // No longer needed 526 } 527 528 return stackTrace; 529 } 530 531 /** 532 * Change the stack trace manually. This method is designed for remote 533 * procedure calls, which intend to alter the stack trace before or after 534 * serialization according to the context of the remote call. 535 * <p> 536 * The contents of the given stacktrace is copied so changes to the 537 * original array do not change the stack trace elements of this 538 * throwable. 539 * 540 * @param stackTrace the new trace to use 541 * @throws NullPointerException if stackTrace is null or has null elements 542 * @since 1.4 543 */ 544 public void setStackTrace(StackTraceElement[] stackTrace) 545 { 546 int i = stackTrace.length; 547 StackTraceElement[] st = new StackTraceElement[i]; 548 549 while (--i >= 0) 550 { 551 st[i] = stackTrace[i]; 552 if (st[i] == null) 553 throw new NullPointerException("Element " + i + " null"); 554 } 555 556 this.stackTrace = st; 557 } 558 559 /** 560 * VM state when fillInStackTrace was called. 561 * Used by getStackTrace() to get an array of StackTraceElements. 562 * Cleared when no longer needed. 563 */ 564 private transient VMThrowable vmState; 565}