Index: java/lang/ClassNotFoundException.java =================================================================== RCS file: /cvs/classpath/java/lang/ClassNotFoundException.java,v retrieving revision 1.5 diff -u -u -r1.5 ClassNotFoundException.java --- java/lang/ClassNotFoundException.java 2000/03/16 23:31:21 1.5 +++ java/lang/ClassNotFoundException.java 2001/07/10 00:45:59 @@ -31,10 +31,11 @@ import java.io.ObjectOutputStream; import java.io.ObjectInputStream; import java.io.IOException; -import java.io.PrintStream; -import java.io.PrintWriter; /** + * Thrown when a class represented by a String could not be found by either + * Class.forName(), ClassLoader.findSystemClass() + * or ClassLoader.loadClass(). * Exceptions may be thrown by one part of a Java program and caught * by another in order to deal with exceptional conditions. This * exception can by thrown by specific methods of ClassLoader @@ -93,50 +94,16 @@ } /** - * Print a stack trace of the exception that occurred. - */ - public void printStackTrace() - { - if (ex == null) - { - super.printStackTrace(); - } - else - { - ex.printStackTrace(); - } - } - - /** - * Print a stack trace of the exception that occurred to - * the specified PrintStream. - */ - public void printStackTrace(PrintStream ps) - { - if (ex == null) - { - super.printStackTrace(ps); - } - else - { - ex.printStackTrace(ps); - } - } - - /** - * Print a stack trace of the exception that occurred to - * the specified PrintWriter. + * Returns the exception which occurred while loading the class, + * otherwise returns null. + * Returns the same as getException() to support the general + * exception chaining mechanism of 1.4. + * + * @since JDK 1.4 */ - public void printStackTrace(PrintWriter pw) + public Throwable getCause() { - if (ex == null) - { - super.printStackTrace(pw); - } - else - { - ex.printStackTrace(pw); - } + return ex; } /** Index: java/lang/Error.java =================================================================== RCS file: /cvs/classpath/java/lang/Error.java,v retrieving revision 1.4 diff -u -u -r1.4 Error.java --- java/lang/Error.java 2001/03/11 15:52:38 1.4 +++ java/lang/Error.java 2001/07/10 00:45:59 @@ -55,6 +55,8 @@ /** * Create an error without a message. + * The cause will not be initialized which means it can be set later by + * calling initCause(). */ public Error() { @@ -63,9 +65,34 @@ /** * Create an error with a message. + * The cause will not be initialized which means it can be set later by + * calling initCause(). */ public Error(String s) { super(s); + } + + /** + * Create an error with a cause. + * If the cause is not null the message will be set to the result of calling + * toString() on the cause otherwise the message will be null. + * + * @since 1.4 + */ + public Error(Throwable c) + { + super(c); + } + + /** + * Create an error with a cause and a message. + * Both parameters may be null. + * + * @since 1.4 + */ + public Error(String s, Throwable c) + { + super(s, c); } } Index: java/lang/Exception.java =================================================================== RCS file: /cvs/classpath/java/lang/Exception.java,v retrieving revision 1.6 diff -u -u -r1.6 Exception.java --- java/lang/Exception.java 2001/03/11 15:52:38 1.6 +++ java/lang/Exception.java 2001/07/10 00:45:59 @@ -51,6 +51,8 @@ /** * Create an exception without a message. + * The cause will not be initialized which means it can be set later by + * calling initCause(). */ public Exception() { @@ -59,9 +61,34 @@ /** * Create an exception with a message. + * The cause will not be initialized which means it can be set later by + * calling initCause(). */ public Exception(String s) { super(s); + } + + /** + * Create an exception with a cause. + * If the cause is not null the message will be set to the result of calling + * toString() on the cause otherwise the message will be null. + * + * @since 1.4 + */ + public Exception(Throwable c) + { + super(c); + } + + /** + * Create an exception with a cause and a message. + * Both parameters may be null. + * + * @since 1.4 + */ + public Exception(String s, Throwable c) + { + super(s, c); } } Index: java/lang/ExceptionInInitializerError.java =================================================================== RCS file: /cvs/classpath/java/lang/ExceptionInInitializerError.java,v retrieving revision 1.6 diff -u -u -r1.6 ExceptionInInitializerError.java --- java/lang/ExceptionInInitializerError.java 2001/03/19 22:15:47 1.6 +++ java/lang/ExceptionInInitializerError.java 2001/07/10 00:45:59 @@ -27,8 +27,6 @@ package java.lang; -import java.io.PrintStream; -import java.io.PrintWriter; /* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3 * "The Java Language Specification", ISBN 0-201-63451-1 @@ -92,53 +90,19 @@ return exception; } - /** - * Print a stack trace of the exception that occurred. - */ - public void printStackTrace() - { - if (exception == null) - { - super.printStackTrace(); - } - else - { - System.err.print(this.getClass() + ": "); - exception.printStackTrace(); - } - } - - /** - * Print a stack trace of the exception that occurred to - * the specified PrintStream. - */ - public void printStackTrace(PrintStream ps) - { - if (exception == null) - { - super.printStackTrace(ps); - } - else - { - ps.print(this.getClass() + ": "); - exception.printStackTrace(ps); - } - } - - /** - * Print a stack trace of the exception that occurred to - * the specified PrintWriter. + /** + * Return the exception that caused this error to be created. + * Returns the same exception as getException to support + * the general exception chaining mechanism of 1.4. + * + * @return the stored Throwable object or null + * if this ExceptionInInitializerError has no stored + * Throwable object. + * + * @since 1.4 */ - public void printStackTrace(PrintWriter pw) + public Throwable getCause() { - if (exception == null) - { - super.printStackTrace(pw); - } - else - { - pw.print(this.getClass() + ": "); - exception.printStackTrace(pw); - } + return exception; } } Index: java/lang/RuntimeException.java =================================================================== RCS file: /cvs/classpath/java/lang/RuntimeException.java,v retrieving revision 1.6 diff -u -u -r1.6 RuntimeException.java --- java/lang/RuntimeException.java 2001/03/11 15:52:38 1.6 +++ java/lang/RuntimeException.java 2001/07/10 00:45:59 @@ -54,6 +54,8 @@ /** * Create an exception without a message. + * The cause will not be initialized which means it can be set later by + * calling initCause(). */ public RuntimeException() { @@ -62,9 +64,35 @@ /** * Create an exception with a message. + * The cause will not be initialized which means it can be set later by + * calling initCause(). */ public RuntimeException(String s) { super(s); } + + /** + * Create an exception with a cause. + * If the cause is not null the message will be set to the result of calling + * toString() on the cause otherwise the message will be null. + * + * @since 1.4 + */ + public RuntimeException(Throwable c) + { + super(c); + } + + /** + * Create an exception with a cause and a message. + * Both parameters may be null. + * + * @since 1.4 + */ + public RuntimeException(String s, Throwable c) + { + super(s, c); + } + } Index: java/lang/StackTraceElement.java =================================================================== RCS file: StackTraceElement.java diff -N StackTraceElement.java --- /dev/null Sat Apr 14 17:46:23 2001 +++ StackTraceElement.java Mon Jul 9 17:45:59 2001 @@ -0,0 +1,208 @@ +/* java.lang.StackTraceElement - One function call or call stack element. + Copyright (C) 2001 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., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +As a special exception, if you link this library with other files to +produce an executable, this library does not by itself cause the +resulting executable to be covered by the GNU General Public License. +This exception does not however invalidate any other reasons why the +executable file might be covered by the GNU General Public License. */ + +package java.lang; + +import java.io.Serializable; + +/** + * One function call or stack trace element. Gives information about + * the execution point such as the source file name, the line number, + * the fully qualified class name, the method name and wether this method + * is native if this information is known. + *

+ * XXX - FIXME - Lookup serializable information. + * + * @author Mark Wielaard (address@hidden) + * + * @since 1.4 + */ +public class StackTraceElement implements Serializable { + + // Variables + + /** The name of the file or null if unknown */ + final private String fileName; + + /** The line number in the file or negative if unknown */ + final private int lineNumber; + + /** The fully qualified class name or null if unknown */ + final private String className; + + /** The method name in the class or null if unknown */ + final private String methodName; + + /** If the method is a native method true, otherwise false */ + final private boolean isNative; + + // Constructors + + /** + * A package local constructor for the StackTraceElement class. + * There are no public constructors defined for this class. Creation + * of new elements is implementation specific. + * + * @param fileName The name of the file or null if unknown + * @param lineNumber The line in the file or negative if unknown + * @param className The fully qualified name of the class or null if unknown + * @param methodName The name of the method or null if unknown + * @param isNative true if native, false otherwise + */ + StackTraceElement(String fileName, int lineNumber, String className, + String methodName, boolean isNative) + { + this.fileName = fileName; + this.lineNumber = lineNumber; + this.className = className; + this.methodName = methodName; + this.isNative = isNative; + } + + // Methods + + /** + * Returns the name of the file or null if unknown. + */ + public String getFileName() + { + return fileName; + } + + /** + * Returns the line number in the file or a negative number if unknown. + */ + public int getLineNumber() + { + return lineNumber; + } + + /** + * Returns the fully qualified class name or null if unknown. + */ + public String getClassName() + { + return className; + } + + /** + * Returns the method name in the class or null if unknown. + */ + public String getMethodName() + { + return methodName; + } + + /** + * Returns true if the method is native or false if it is not or unknown. + */ + public boolean isNativeMethod() + { + return isNative; + } + + /** + * Returns true if the given object is also a StackTraceElement + * and all attributes, except the native flag are equal. + */ + public boolean equals(Object o) + { + if (o instanceof StackTraceElement) { + StackTraceElement e = (StackTraceElement)o; + boolean equal = + ((fileName == e.fileName) + || ((fileName != null) && fileName.equals(e.fileName))) + && + ((lineNumber == e.lineNumber) + || ((lineNumber < 0) && (e.lineNumber < 0))) + && + ((className == e.className) + || ((className != null) && className.equals(e.className))) + && + ((methodName == e.methodName) + || ((methodName != null) && methodName.equals(e.methodName))); + + return equal; + } + return false; + } + + /** + * Returns the hashCode of this StackTraceElement. + *

+ * This implementation computes the hashcode by xor-ing the hashcode of all + * attributes except the native flag. + */ + public int hashCode() + { + return fileName.hashCode() ^ lineNumber + ^ className.hashCode() ^ methodName.hashCode(); + } + + /** + * Returns a string representation of this stack trace element. + *

+ * The returned String is implementation specific. This implementation + * returns the following String: "[class][.][method]([file][:line])". + * If the fully qualified class name or the method is unknown it is + * omitted including the point seperator. If the source file name is + * unknown it is replaced by "Unknown Source" if the method is not native + * or by "Native Method" if the method is native. If the line number + * is unknown it and the colon are omitted. + */ + public String toString() { + StringBuffer sb = new StringBuffer(); + + if (className != null) + sb.append(className); + + if (className != null && methodName != null) + sb.append('.'); + + if (methodName != null) + sb.append(methodName); + + sb.append('('); + + if (fileName != null) + sb.append(fileName); + else + if (!isNative) + sb.append("Unknown Source"); + else + sb.append("Native Method"); + + if (lineNumber >= 0) + { + sb.append(':'); + sb.append(lineNumber); + } + + sb.append(')'); + + return sb.toString(); + } +} Index: java/lang/reflect/InvocationTargetException.java =================================================================== RCS file: /cvs/classpath/java/lang/reflect/InvocationTargetException.java,v retrieving revision 1.6 diff -u -u -r1.6 InvocationTargetException.java --- java/lang/reflect/InvocationTargetException.java 2001/03/19 22:15:47 1.6 +++ java/lang/reflect/InvocationTargetException.java 2001/07/10 00:45:59 @@ -27,9 +27,6 @@ package java.lang.reflect; -import java.io.PrintStream; -import java.io.PrintWriter; - /* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3 * "The Java Language Specification", ISBN 0-201-63451-1 * Status: Believed complete and correct. @@ -92,37 +89,18 @@ { return target; } - - public void printStackTrace() - { - if (target == null) - super.printStackTrace(); - else - { - System.err.print(this.getClass() + ": "); - target.printStackTrace(); - } - } - - public void printStackTrace(PrintStream ps) - { - if (target == null) - super.printStackTrace(ps); - else - { - ps.print(this.getClass() + ": "); - target.printStackTrace(ps); - } - } - public void printStackTrace(PrintWriter pw) + /** + * Get the wrapped (targeted) exception. + * Returns the same exception as getTargetException() to + * support the general 1.4 exception chaining mechanism. + * + * @return the targeted exception. + * + * @since 1.4 + */ + public Throwable getCause() { - if (target == null) - super.printStackTrace(pw); - else - { - pw.print(this.getClass() + ": "); - target.printStackTrace(pw); - } + return target; } } Index: java/security/PrivilegedActionException.java =================================================================== RCS file: /cvs/classpath/java/security/PrivilegedActionException.java,v retrieving revision 1.2 diff -u -u -r1.2 PrivilegedActionException.java --- java/security/PrivilegedActionException.java 2000/03/16 20:18:21 1.2 +++ java/security/PrivilegedActionException.java 2001/07/10 00:45:59 @@ -1,6 +1,6 @@ /* PrivilegedActionException.java -- An exception occurred in a privileged action - Copyright (C) 1998 Free Software Foundation, Inc. + Copyright (C) 1998, 2001 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -28,9 +28,6 @@ package java.security; -import java.io.PrintStream; -import java.io.PrintWriter; - /** * This exception is thrown when an exception is thrown during a * privileged action being performed with the @@ -91,43 +88,20 @@ return(e); } -/*************************************************************************/ - /** - * This method prints the stack trace of the wrappered exception. - */ -public void -printStackTrace() -{ - e.printStackTrace(); -} - -/*************************************************************************/ - -/** - * This method prints the stack trace of the wrappered exception to the - * specified PrintStream. + * This method returns the underlying Exception that caused + * this exception to be raised. + * Returns the same exception as getException() to support + * the general exception chaining mechanism of 1.4. * - * @param ps The PrintStream to print the stack trace to. - */ -public void -printStackTrace(PrintStream ps) -{ - e.printStackTrace(ps); -} - -/*************************************************************************/ - -/** - * This method prints the stack trace of the wrappered exception to the - * specified PrintWriter. + * @return The wrappered Exception. * - * @param pw The PrintWriter to print the stack trace to. + * @since 1.4 */ -public void -printStackTrace(PrintWriter pw) +public Throwable +getCause() { - e.printStackTrace(pw); + return(e); } } // class PrivilegedActionException Index: vm/reference/java/lang/Throwable.java =================================================================== RCS file: /cvs/classpath/vm/reference/java/lang/Throwable.java,v retrieving revision 1.1 diff -u -u -r1.1 Throwable.java --- vm/reference/java/lang/Throwable.java 2000/12/10 17:42:10 1.1 +++ vm/reference/java/lang/Throwable.java 2001/07/10 00:45:59 @@ -1,5 +1,5 @@ /* java.lang.Throwable - Copyright (C) 1998 Free Software Foundation, Inc. + Copyright (C) 1998, 2001 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -37,9 +37,10 @@ /** * Throwable is the superclass of all exceptions that can be raised. * - * @version 1.1.0, Oct 5 1998 + * @version 1.3.99, Jul 8 2001 * @author Brian Jones * @author John Keiser + * @author Mark Wielaard * @since JDK1.0 */ public class Throwable extends Object implements Serializable @@ -48,28 +49,71 @@ private String message = null; + /** + * The Throwable that caused this Throwable. This field is null if the + * cause is explicitly set to null, it points to 'this' if it has not yet + * been explicitly set and it points to another Throwable if it has been + * explicitly set by initCause(). + */ + private Throwable cause; + static { System.loadLibrary ("runtime"); } /** - * Instantiate this Throwable with an empty message. + * Instantiate this Throwable with an empty message. + * Does not initialize the cause which means that initCause + * can be called later. */ public Throwable() { - this(null); + fillInStackTrace(); + this.message = null; + this.cause = this; } /** * Instantiate this Throwable with the given message. + * Does not initialize the cause which means that initCause + * can be called later. * @param message the message to associate with the Throwable. */ public Throwable(String message) { fillInStackTrace(); this.message = message; + this.cause = this; } - + /** + * Instantiate this Throwable with the given cause. + * If the cause if not null the message will be set to the result of + * the cause.toString(), otherwise it will be set to null. + * @param cause the cause to associate with the Throwable + * + * @since 1.4 + */ + public Throwable(Throwable cause) { + fillInStackTrace(); + this.message = (cause != null) ? cause.toString() : null; + this.cause = cause; + } + + /** + * Instantiate this Throwable with the given message and cause. + * Both parameters may be null. + * @param message the message to associate with the Throwable + * @param cause the cause to associate with the Throwable + * + * @since 1.4 + */ + public Throwable(String message, Throwable cause) { + fillInStackTrace(); + this.message = message; + this.cause = cause; + } + + /** * Get the message associated with this Throwable. * @return the error message associated with this Throwable. */ @@ -88,14 +132,71 @@ public String getLocalizedMessage() { return getMessage(); } - /** + * Sets the cause of this Throwable if it has not already been set. + * This can be even be used when the Throwable subclass has no contructor + * that takes a cause. So if the only declared exception for an method + * or interface allows you to throw for example a IOException + * but the real cause is some SQLException then you can + * do the following: + *

+   *   try {
+   *       ...
+   *   } catch (SQLException sqle) {
+   *       throw new IOException(sqle.toString()).initCause(sqle);
+   *   }
+   * 
+ * The cause cannot be the Throwable itself and the cause can be set + * only once. Note that this method returns the Throwable itself so + * it can be easily used as above in a return statement. + * + * @return this Throwable + * @exception IllegalArgumentException if cause == this + * @exception IllegalStateException if the cause was already initialized + * + * @since 1.4 + */ + public Throwable initCause(Throwable cause) { + if (cause == this) + throw new IllegalArgumentException("Throwable cannot be its own cause"); + + if (this.cause != this) + throw new IllegalStateException("cause already initialized"); + + this.cause = cause; + + return this; + } + + /** + * Returns the cause of this Throwable or null when it is unknown or + * has not yet been set. + * + * @since 1.4 + */ + public Throwable getCause() { + // Check that the cause has been initialized + if (cause == this) + return null; + else + return cause; + } + + /** * Get a human-readable representation of this Throwable. - * @return a human-readable String represting this Throwable. - * @XXX find out what exactly this should look like. + * The string returned starts with the actual class name (as given by + * getClass().getName()), if getMessage() + * does not return null then the string ": " and the actual message + * is appended. + * @return a human-readable String representing this Throwable. */ public String toString() { - return getClass().getName() + (message != null ? ": " + message : ""); + String name = getClass().getName(); + String message = getMessage(); + if (message == null) + return name; + else + return name + ": " + message; } /** @@ -125,6 +226,89 @@ private native void printStackTrace0 (Object stream); + /** + * Alternative printStackTrace that uses getStrackTrace() + * to print the exception, stack trace and cause (recursively). Not used + * since getStackTrace() has not yet been implemented - FIXME. + *

+ * Prints the exception, the detailed message and the stack trace associated + * with this Throwable to the given PrintWriter. + * The actual output written is implemention specific. Use the result of + * getStackTrace() when more precise information is needed. + *

+ * This implementation first prints a line with the result of this objects + * toString() method. + *
+ * Then for all elements given by getStackTrace it prints + * a line containing a tab, the string "at " and the result of calling the + * toString() method on the StackTraceElement + * object. If getStackTrace() returns an empty array it prints + * a line containing a tab and the string "<>". + *
+ * Then if getCause() doesn't return null it adds a line + * starting with "Caused by: " and the result of calling + * toString() on the cause. + *
+ * Then for every cause (of a cause, etc) the stacktrace is printed the + * same as for the top level Throwable 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 a tab and the string "... X more" is printed, + * where X is the number of remaining stackframes. + */ + private void printStackTrace1(PrintWriter pw) { + // First line + pw.println(toString()); + + // The stacktrace + StackTraceElement[] stack = getStackTrace(); + for (int i = 0; i < stack.length; i++) { + pw.print("\tat "); + pw.println(stack[i].toString()); + } + + // The cause(s) + Throwable cause = getCause(); + while (cause != null) { + // Cause first line + pw.print("Caused by: "); + pw.println(cause.toString()); + + // Cause stacktrace + StackTraceElement[] parentStack = stack; + stack = cause.getStackTrace(); + boolean equal = false; // Is rest of the stack is equal to parent frame? + for (int i = 0; i < stack.length && !equal; i++) { + // Check if we already printed the rest of the stack + // since it was the tail of the parent stack + int remaining = stack.length - i; + int element = i; + int parentElement = parentStack.length - remaining; + equal = parentElement >= 0 + && parentElement < parentStack.length; // be optimistic + while(equal && element < stack.length) { + if (stack[element].equals(parentStack[parentElement])) { + element++; + parentElement++; + } else { + equal = false; + } + } + // Print stacktrace element or indicate the rest is equal + if (!equal) { + pw.print("\tat "); + pw.println(stack[i]); + } else { + pw.print("\t..."); + pw.print(remaining); + pw.println(" more"); + break; // from stack printing for loop + } + } + cause = cause.getCause(); + } + } + /** * Fill in the stack trace with the current execution stack. * Normally used when rethrowing an exception, to strip @@ -132,6 +316,21 @@ * @return this same throwable. */ public native Throwable fillInStackTrace(); + + /** + * Returns an array of stack trace elements representing the execution + * points on the call stack when fillInStackTrace() was + * called. The first element represents the most recent execution point + * the last element is the oldest. Depending on the implementation all, + * some or none of the elements are included. + *

+ * XXX - FIXME - Not implemented yet, always returns an empty array. + * + * @since 1.4 + */ + public StackTraceElement[] getStackTrace() { + return new StackTraceElement[0]; + } /** * Serialize the object in a manner binary compatible with the JDK 1.2