/*
* Copyright (c) 1994, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.lang;
import java.io.*;
import java.util.*;
final class ThrowableHelper {
/**
* Holder class to defer initializing sentinel objects only used
* for serialization.
*/
private static class SentinelHolder {
/**
* {@linkplain #setStackTrace(StackTraceElement[]) Setting the
* stack trace} to a one-element array containing this sentinel
* value indicates future attempts to set the stack trace will be
* ignored. The sentinal is equal to the result of calling:
* {@code new StackTraceElement("", "", null, Integer.MIN_VALUE)}
*/
public static final StackTraceElement STACK_TRACE_ELEMENT_SENTINEL =
new StackTraceElement("", "", null, Integer.MIN_VALUE);
/**
* Sentinel value used in the serial form to indicate an immutable
* stack trace.
*/
public static final StackTraceElement[] STACK_TRACE_SENTINEL =
new StackTraceElement[] {STACK_TRACE_ELEMENT_SENTINEL};
}
/** Caption for labeling causative exception stack traces */
private static final String CAUSE_CAPTION = "Caused by: ";
/** Caption for labeling suppressed exception stack traces */
private static final String SUPPRESSED_CAPTION = "Suppressed: ";
/**
* Prints this throwable and its backtrace to the
* standard error stream. This method prints a stack trace for this
* {@code Throwable} object on the error output stream that is
* the value of the field {@code System.err}. The first line of
* output contains the result of the {@link #toString()} method for
* this object. Remaining lines represent data previously recorded by
* the method {@link #fillInStackTrace()}. The format of this
* information depends on the implementation, but the following
* example may be regarded as typical:
*
* java.lang.NullPointerException
* at MyClass.mash(MyClass.java:9)
* at MyClass.crunch(MyClass.java:6)
* at MyClass.main(MyClass.java:3)
*
* This example was produced by running the program:
*
* class MyClass {
* public static void main(String[] args) {
* crunch(null);
* }
* static void crunch(int[] a) {
* mash(a);
* }
* static void mash(int[] b) {
* System.out.println(b[0]);
* }
* }
*
* The backtrace for a throwable with an initialized, non-null cause
* should generally include the backtrace for the cause. The format
* of this information depends on the implementation, but the following
* example may be regarded as typical:
*
* 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
*
* Note the presence of lines containing the characters {@code "..."}.
* These lines indicate that the remainder of the stack trace for this
* exception matches the indicated number of frames from the bottom of the
* stack trace of the exception that was caused by this exception (the
* "enclosing" exception). This shorthand can greatly reduce the length
* of the output in the common case where a wrapped exception is thrown
* from same method as the "causative exception" is caught. The above
* example was produced by running the program:
*
* 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 {
* }
*
* As of release 7, the platform supports the notion of
* suppressed exceptions (in conjunction with the {@code
* try}-with-resources statement). Any exceptions that were
* suppressed in order to deliver an exception are printed out
* beneath the stack trace. The format of this information
* depends on the implementation, but the following example may be
* regarded as typical:
*
*
* Exception in thread "main" java.lang.Exception: Something happened
* at Foo.bar(Foo.java:10)
* at Foo.main(Foo.java:5)
* Suppressed: Resource$CloseFailException: Resource ID = 0
* at Resource.close(Resource.java:26)
* at Foo.bar(Foo.java:9)
* ... 1 more
*
* Note that the "... n more" notation is used on suppressed exceptions
* just at it is used on causes. Unlike causes, suppressed exceptions are
* indented beyond their "containing exceptions."
*
* An exception can have both a cause and one or more suppressed * exceptions: *
* Exception in thread "main" java.lang.Exception: Main block
* at Foo3.main(Foo3.java:7)
* Suppressed: Resource$CloseFailException: Resource ID = 2
* at Resource.close(Resource.java:26)
* at Foo3.main(Foo3.java:5)
* Suppressed: Resource$CloseFailException: Resource ID = 1
* at Resource.close(Resource.java:26)
* at Foo3.main(Foo3.java:5)
* Caused by: java.lang.Exception: I did it
* at Foo3.main(Foo3.java:8)
*
* Likewise, a suppressed exception can have a cause:
*
* Exception in thread "main" java.lang.Exception: Main block
* at Foo4.main(Foo4.java:6)
* Suppressed: Resource2$CloseFailException: Resource ID = 1
* at Resource2.close(Resource2.java:20)
* at Foo4.main(Foo4.java:5)
* Caused by: java.lang.Exception: Rats, you caught me
* at Resource2$CloseFailException.(Resource2.java:45)
* ... 2 more
*
*/
public static void printStackTrace(Throwable _this) {
_this.printStackTrace(System.err);
}
/**
* Prints this throwable and its backtrace to the specified print stream.
*
* @param s {@code PrintStream} to use for output
*/
public static void printStackTrace(Throwable _this, PrintStream s) {
printStackTrace(_this, new WrappedPrintStream(s));
}
private static void printStackTrace(Throwable _this, PrintStreamOrWriter s) {
// Guard against malicious overrides of Throwable.equals by
// using a Set with identity equality semantics.
Set