123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566 |
- /* java.lang.Throwable -- Root class for all Exceptions and Errors
- Copyright (C) 1998, 1999, 2002, 2004, 2005 Free Software Foundation, Inc.
- This file is part of GNU Classpath.
- GNU Classpath is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
- GNU Classpath is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with GNU Classpath; see the file COPYING. If not, write to the
- Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- 02110-1301 USA.
- Linking this library statically or dynamically with other modules is
- making a combined work based on this library. Thus, the terms and
- conditions of the GNU General Public License cover the whole
- combination.
- As a special exception, the copyright holders of this library give you
- permission to link this library with independent modules to produce an
- executable, regardless of the license terms of these independent
- modules, and to copy and distribute the resulting executable under
- terms of your choice, provided that you also meet, for each linked
- independent module, the terms and conditions of the license of that
- module. An independent module is a module which is not derived from
- or based on this library. If you modify this library, you may extend
- this exception to your version of the library, but you are not
- obligated to do so. If you do not wish to do so, delete this
- exception statement from your version. */
- package java.lang;
- import gnu.classpath.SystemProperties;
- import gnu.java.lang.CPStringBuilder;
- import java.io.PrintStream;
- import java.io.PrintWriter;
- import java.io.Serializable;
- /**
- * Throwable is the superclass of all exceptions that can be raised.
- *
- * <p>There are two special cases: {@link Error} and {@link RuntimeException}:
- * these two classes (and their subclasses) are considered unchecked
- * exceptions, and are either frequent enough or catastrophic enough that you
- * do not need to declare them in <code>throws</code> clauses. Everything
- * else is a checked exception, and is ususally a subclass of
- * {@link Exception}; these exceptions have to be handled or declared.
- *
- * <p>Instances of this class are usually created with knowledge of the
- * execution context, so that you can get a stack trace of the problem spot
- * in the code. Also, since JDK 1.4, Throwables participate in "exception
- * chaining." This means that one exception can be caused by another, and
- * preserve the information of the original.
- *
- * <p>One reason this is useful is to wrap exceptions to conform to an
- * interface. For example, it would be bad design to require all levels
- * of a program interface to be aware of the low-level exceptions thrown
- * at one level of abstraction. Another example is wrapping a checked
- * exception in an unchecked one, to communicate that failure occured
- * while still obeying the method throws clause of a superclass.
- *
- * <p>A cause is assigned in one of two ways; but can only be assigned once
- * in the lifetime of the Throwable. There are new constructors added to
- * several classes in the exception hierarchy that directly initialize the
- * cause, or you can use the <code>initCause</code> method. This second
- * method is especially useful if the superclass has not been retrofitted
- * with new constructors:<br>
- * <pre>
- * try
- * {
- * lowLevelOp();
- * }
- * catch (LowLevelException lle)
- * {
- * throw (HighLevelException) new HighLevelException().initCause(lle);
- * }
- * </pre>
- * Notice the cast in the above example; without it, your method would need
- * a throws clase that declared Throwable, defeating the purpose of chainig
- * your exceptions.
- *
- * <p>By convention, exception classes have two constructors: one with no
- * arguments, and one that takes a String for a detail message. Further,
- * classes which are likely to be used in an exception chain also provide
- * a constructor that takes a Throwable, with or without a detail message
- * string.
- *
- * <p>Another 1.4 feature is the StackTrace, a means of reflection that
- * allows the program to inspect the context of the exception, and which is
- * serialized, so that remote procedure calls can correctly pass exceptions.
- *
- * @author Brian Jones
- * @author John Keiser
- * @author Mark Wielaard
- * @author Tom Tromey
- * @author Eric Blake (ebb9@email.byu.edu)
- * @since 1.0
- * @status updated to 1.4
- */
- public class Throwable implements Serializable
- {
- /**
- * Compatible with JDK 1.0+.
- */
- private static final long serialVersionUID = -3042686055658047285L;
- /**
- * The detail message.
- *
- * @serial specific details about the exception, may be null
- */
- private final String detailMessage;
- /**
- * The cause of the throwable, including null for an unknown or non-chained
- * cause. This may only be set once; so the field is set to
- * <code>this</code> until initialized.
- *
- * @serial the cause, or null if unknown, or this if not yet set
- * @since 1.4
- */
- private Throwable cause = this;
- /**
- * The stack trace, in a serialized form.
- *
- * @serial the elements of the stack trace; this is non-null, and has
- * no null entries
- * @since 1.4
- */
- private StackTraceElement[] stackTrace;
- /**
- * Instantiate this Throwable with an empty message. The cause remains
- * uninitialized. {@link #fillInStackTrace()} will be called to set
- * up the stack trace.
- */
- public Throwable()
- {
- this((String) null);
- }
- /**
- * Instantiate this Throwable with the given message. The cause remains
- * uninitialized. {@link #fillInStackTrace()} will be called to set
- * up the stack trace.
- *
- * @param message the message to associate with the Throwable
- */
- public Throwable(String message)
- {
- fillInStackTrace();
- detailMessage = message;
- }
- /**
- * Instantiate this Throwable with the given message and cause. Note that
- * the message is unrelated to the message of the cause.
- * {@link #fillInStackTrace()} will be called to set up the stack trace.
- *
- * @param message the message to associate with the Throwable
- * @param cause the cause, may be null
- * @since 1.4
- */
- public Throwable(String message, Throwable cause)
- {
- this(message);
- this.cause = cause;
- }
- /**
- * Instantiate this Throwable with the given cause. The message is then
- * built as <code>cause == null ? null : cause.toString()</code>.
- * {@link #fillInStackTrace()} will be called to set up the stack trace.
- *
- * @param cause the cause, may be null
- * @since 1.4
- */
- public Throwable(Throwable cause)
- {
- this(cause == null ? null : cause.toString(), cause);
- }
- /**
- * Get the message associated with this Throwable.
- *
- * @return the error message associated with this Throwable, may be null
- */
- public String getMessage()
- {
- return detailMessage;
- }
- /**
- * Get a localized version of this Throwable's error message.
- * This method must be overridden in a subclass of Throwable
- * to actually produce locale-specific methods. The Throwable
- * implementation just returns getMessage().
- *
- * @return a localized version of this error message
- * @see #getMessage()
- * @since 1.1
- */
- public String getLocalizedMessage()
- {
- return getMessage();
- }
- /**
- * Returns the cause of this exception, or null if the cause is not known
- * or non-existant. This cause is initialized by the new constructors,
- * or by calling initCause.
- *
- * @return the cause of this Throwable
- * @since 1.4
- */
- public Throwable getCause()
- {
- return cause == this ? null : cause;
- }
- /**
- * Initialize the cause of this Throwable. This may only be called once
- * during the object lifetime, including implicitly by chaining
- * constructors.
- *
- * @param cause the cause of this Throwable, may be null
- * @return this
- * @throws IllegalArgumentException if cause is this (a Throwable can't be
- * its own cause!)
- * @throws IllegalStateException if the cause has already been set
- * @since 1.4
- */
- public Throwable initCause(Throwable cause)
- {
- if (cause == this)
- throw new IllegalArgumentException();
- if (this.cause != this)
- throw new IllegalStateException();
- this.cause = cause;
- return this;
- }
- /**
- * Get a human-readable representation of this Throwable. The detail message
- * is retrieved by getLocalizedMessage(). Then, with a null detail
- * message, this string is simply the object's class name; otherwise
- * the string is <code>getClass().getName() + ": " + message</code>.
- *
- * @return a human-readable String represting this Throwable
- */
- public String toString()
- {
- String msg = getLocalizedMessage();
- return getClass().getName() + (msg == null ? "" : ": " + msg);
- }
- /**
- * Print a stack trace to the standard error stream. This stream is the
- * current contents of <code>System.err</code>. The first line of output
- * is the result of {@link #toString()}, and the remaining lines represent
- * the data created by {@link #fillInStackTrace()}. While the format is
- * unspecified, this implementation uses the suggested format, demonstrated
- * by this example:<br>
- * <pre>
- * public class Junk
- * {
- * public static void main(String args[])
- * {
- * try
- * {
- * a();
- * }
- * catch(HighLevelException e)
- * {
- * e.printStackTrace();
- * }
- * }
- * static void a() throws HighLevelException
- * {
- * try
- * {
- * b();
- * }
- * catch(MidLevelException e)
- * {
- * throw new HighLevelException(e);
- * }
- * }
- * static void b() throws MidLevelException
- * {
- * c();
- * }
- * static void c() throws MidLevelException
- * {
- * try
- * {
- * d();
- * }
- * catch(LowLevelException e)
- * {
- * throw new MidLevelException(e);
- * }
- * }
- * static void d() throws LowLevelException
- * {
- * e();
- * }
- * static void e() throws LowLevelException
- * {
- * throw new LowLevelException();
- * }
- * }
- * class HighLevelException extends Exception
- * {
- * HighLevelException(Throwable cause) { super(cause); }
- * }
- * class MidLevelException extends Exception
- * {
- * MidLevelException(Throwable cause) { super(cause); }
- * }
- * class LowLevelException extends Exception
- * {
- * }
- * </pre>
- * <p>
- * <pre>
- * HighLevelException: MidLevelException: LowLevelException
- * at Junk.a(Junk.java:13)
- * at Junk.main(Junk.java:4)
- * Caused by: MidLevelException: LowLevelException
- * at Junk.c(Junk.java:23)
- * at Junk.b(Junk.java:17)
- * at Junk.a(Junk.java:11)
- * ... 1 more
- * Caused by: LowLevelException
- * at Junk.e(Junk.java:30)
- * at Junk.d(Junk.java:27)
- * at Junk.c(Junk.java:21)
- * ... 3 more
- * </pre>
- */
- public void printStackTrace()
- {
- printStackTrace(System.err);
- }
- /**
- * Print a stack trace to the specified PrintStream. See
- * {@link #printStackTrace()} for the sample format.
- *
- * @param s the PrintStream to write the trace to
- */
- public void printStackTrace(PrintStream s)
- {
- s.print(stackTraceString());
- }
- /**
- * Prints the exception, the detailed message and the stack trace
- * associated with this Throwable to the given <code>PrintWriter</code>.
- * The actual output written is implemention specific. Use the result of
- * <code>getStackTrace()</code> when more precise information is needed.
- *
- * <p>This implementation first prints a line with the result of this
- * object's <code>toString()</code> method.
- * <br>
- * Then for all elements given by <code>getStackTrace</code> it prints
- * a line containing three spaces, the string "at " and the result of calling
- * the <code>toString()</code> method on the <code>StackTraceElement</code>
- * object. If <code>getStackTrace()</code> returns an empty array it prints
- * a line containing three spaces and the string
- * "<<No stacktrace available>>".
- * <br>
- * Then if <code>getCause()</code> doesn't return null it adds a line
- * starting with "Caused by: " and the result of calling
- * <code>toString()</code> on the cause.
- * <br>
- * Then for every cause (of a cause, etc) the stacktrace is printed the
- * same as for the top level <code>Throwable</code> except that as soon
- * as all the remaining stack frames of the cause are the same as the
- * the last stack frames of the throwable that the cause is wrapped in
- * then a line starting with three spaces and the string "... X more" is
- * printed, where X is the number of remaining stackframes.
- *
- * @param pw the PrintWriter to write the trace to
- * @since 1.1
- */
- public void printStackTrace (PrintWriter pw)
- {
- pw.print(stackTraceString());
- }
- /*
- * We use inner class to avoid a static initializer in this basic class.
- */
- private static class StaticData
- {
- static final String nl = SystemProperties.getProperty("line.separator");
- }
- // Create whole stack trace in a stringbuffer so we don't have to print
- // it line by line. This prevents printing multiple stack traces from
- // different threads to get mixed up when written to the same PrintWriter.
- private String stackTraceString()
- {
- CPStringBuilder sb = new CPStringBuilder();
- // Main stacktrace
- StackTraceElement[] stack = getStackTrace();
- stackTraceStringBuffer(sb, this.toString(), stack, 0);
- // The cause(s)
- Throwable cause = getCause();
- while (cause != null)
- {
- // Cause start first line
- sb.append("Caused by: ");
- // Cause stacktrace
- StackTraceElement[] parentStack = stack;
- stack = cause.getStackTrace();
- if (parentStack == null || parentStack.length == 0)
- stackTraceStringBuffer(sb, cause.toString(), stack, 0);
- else
- {
- int equal = 0; // Count how many of the last stack frames are equal
- int frame = stack.length-1;
- int parentFrame = parentStack.length-1;
- while (frame > 0 && parentFrame > 0)
- {
- if (stack[frame].equals(parentStack[parentFrame]))
- {
- equal++;
- frame--;
- parentFrame--;
- }
- else
- break;
- }
- stackTraceStringBuffer(sb, cause.toString(), stack, equal);
- }
- cause = cause.getCause();
- }
- return sb.toString();
- }
- // Adds to the given StringBuffer a line containing the name and
- // all stacktrace elements minus the last equal ones.
- private static void stackTraceStringBuffer(CPStringBuilder sb, String name,
- StackTraceElement[] stack, int equal)
- {
- String nl = StaticData.nl;
- // (finish) first line
- sb.append(name);
- sb.append(nl);
- // The stacktrace
- if (stack == null || stack.length == 0)
- {
- sb.append(" <<No stacktrace available>>");
- sb.append(nl);
- }
- else
- {
- for (int i = 0; i < stack.length-equal; i++)
- {
- sb.append(" at ");
- sb.append(stack[i] == null ? "<<Unknown>>" : stack[i].toString());
- sb.append(nl);
- }
- if (equal > 0)
- {
- sb.append(" ...");
- sb.append(equal);
- sb.append(" more");
- sb.append(nl);
- }
- }
- }
- /**
- * Fill in the stack trace with the current execution stack.
- *
- * @return this same throwable
- * @see #printStackTrace()
- */
- public Throwable fillInStackTrace()
- {
- vmState = VMThrowable.fillInStackTrace(this);
- stackTrace = null; // Should be regenerated when used.
- return this;
- }
- /**
- * Provides access to the information printed in {@link #printStackTrace()}.
- * The array is non-null, with no null entries, although the virtual
- * machine is allowed to skip stack frames. If the array is not 0-length,
- * then slot 0 holds the information on the stack frame where the Throwable
- * was created (or at least where <code>fillInStackTrace()</code> was
- * called).
- *
- * @return an array of stack trace information, as available from the VM
- * @since 1.4
- */
- public StackTraceElement[] getStackTrace()
- {
- if (stackTrace == null)
- if (vmState == null)
- stackTrace = new StackTraceElement[0];
- else
- {
- stackTrace = vmState.getStackTrace(this);
- vmState = null; // No longer needed
- }
- return stackTrace;
- }
- /**
- * Change the stack trace manually. This method is designed for remote
- * procedure calls, which intend to alter the stack trace before or after
- * serialization according to the context of the remote call.
- * <p>
- * The contents of the given stacktrace is copied so changes to the
- * original array do not change the stack trace elements of this
- * throwable.
- *
- * @param stackTrace the new trace to use
- * @throws NullPointerException if stackTrace is null or has null elements
- * @since 1.4
- */
- public void setStackTrace(StackTraceElement[] stackTrace)
- {
- int i = stackTrace.length;
- StackTraceElement[] st = new StackTraceElement[i];
- while (--i >= 0)
- {
- st[i] = stackTrace[i];
- if (st[i] == null)
- throw new NullPointerException("Element " + i + " null");
- }
- this.stackTrace = st;
- }
- /**
- * VM state when fillInStackTrace was called.
- * Used by getStackTrace() to get an array of StackTraceElements.
- * Cleared when no longer needed.
- */
- private transient VMThrowable vmState;
- }
|