Frames | No Frames |
1: /* java.lang.Throwable -- Root class for all Exceptions and Errors 2: Copyright (C) 1998, 1999, 2002, 2004, 2005 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., 51 Franklin Street, Fifth Floor, Boston, MA 19: 02110-1301 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 gnu.classpath.SystemProperties; 41: 42: import gnu.java.lang.CPStringBuilder; 43: 44: import java.io.PrintStream; 45: import java.io.PrintWriter; 46: import java.io.Serializable; 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: */ 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: }