GNU Classpath (0.95) | |
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 java.io.PrintStream; 43: import java.io.PrintWriter; 44: import java.io.Serializable; 45: 46: /** 47: * Throwable is the superclass of all exceptions that can be raised. 48: * 49: * <p>There are two special cases: {@link Error} and {@link RuntimeException}: 50: * these two classes (and their subclasses) are considered unchecked 51: * exceptions, and are either frequent enough or catastrophic enough that you 52: * do not need to declare them in <code>throws</code> clauses. Everything 53: * else is a checked exception, and is ususally a subclass of 54: * {@link Exception}; these exceptions have to be handled or declared. 55: * 56: * <p>Instances of this class are usually created with knowledge of the 57: * execution context, so that you can get a stack trace of the problem spot 58: * in the code. Also, since JDK 1.4, Throwables participate in "exception 59: * chaining." This means that one exception can be caused by another, and 60: * preserve the information of the original. 61: * 62: * <p>One reason this is useful is to wrap exceptions to conform to an 63: * interface. For example, it would be bad design to require all levels 64: * of a program interface to be aware of the low-level exceptions thrown 65: * at one level of abstraction. Another example is wrapping a checked 66: * exception in an unchecked one, to communicate that failure occured 67: * while still obeying the method throws clause of a superclass. 68: * 69: * <p>A cause is assigned in one of two ways; but can only be assigned once 70: * in the lifetime of the Throwable. There are new constructors added to 71: * several classes in the exception hierarchy that directly initialize the 72: * cause, or you can use the <code>initCause</code> method. This second 73: * method is especially useful if the superclass has not been retrofitted 74: * with new constructors:<br> 75: * <pre> 76: * try 77: * { 78: * lowLevelOp(); 79: * } 80: * catch (LowLevelException lle) 81: * { 82: * throw (HighLevelException) new HighLevelException().initCause(lle); 83: * } 84: * </pre> 85: * Notice the cast in the above example; without it, your method would need 86: * a throws clase that declared Throwable, defeating the purpose of chainig 87: * your exceptions. 88: * 89: * <p>By convention, exception classes have two constructors: one with no 90: * arguments, and one that takes a String for a detail message. Further, 91: * classes which are likely to be used in an exception chain also provide 92: * a constructor that takes a Throwable, with or without a detail message 93: * string. 94: * 95: * <p>Another 1.4 feature is the StackTrace, a means of reflection that 96: * allows the program to inspect the context of the exception, and which is 97: * serialized, so that remote procedure calls can correctly pass exceptions. 98: * 99: * @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: }
GNU Classpath (0.95) |