FileDocCategorySizeDatePackage
ExceptionUtils.javaAPI DocHibernate 3.2.524738Sat Nov 20 17:11:28 GMT 2004org.hibernate.exception

ExceptionUtils

public final class ExceptionUtils extends Object

Provides utilities for manipulating and examining Throwable objects.

author
Daniel Rall
author
Dmitri Plotnikov
author
Stephen Colebourne
author
Gary Gregory
author
Pete Gieser
version
$Id: ExceptionUtils.java 4782 2004-11-21 00:11:27Z pgmjsd $
since
1.0

Fields Summary
private static final String
LINE_SEPARATOR
static final String
WRAPPED_MARKER

Used when printing stack frames to denote the start of a wrapped exception.

Package private for accessibility by test suite.

private static final String[]
CAUSE_METHOD_NAMES

The names of methods commonly used to access a wrapped exception.

private static final Method
THROWABLE_CAUSE_METHOD

The Method object for JDK1.4 getCause.

Constructors Summary
private ExceptionUtils()


	 
		Method getCauseMethod;
		try {
			getCauseMethod = Throwable.class.getMethod( "getCause", null );
		}
		catch ( Exception e ) {
			getCauseMethod = null;
		}
		THROWABLE_CAUSE_METHOD = getCauseMethod;
	
	
Methods Summary
public static java.lang.ThrowablegetCause(java.lang.Throwable throwable)

Introspects the Throwable to obtain the cause.

The method searches for methods with specific names that return a Throwable object. This will pick up most wrapping exceptions, including those from JDK 1.4, and {@link org.apache.commons.lang.exception.NestableException NestableException}. The method names can be added to using {@link #addCauseMethodName(String)}.

The default list searched for are:

  • getCause()
  • getNextException()
  • getTargetException()
  • getException()
  • getSourceException()
  • getRootCause()
  • getCausedByException()
  • getNested()

In the absence of any such method, the object is inspected for a detail field assignable to a Throwable.

If none of the above is found, returns null.

param
throwable the throwable to introspect for a cause, may be null
return
the cause of the Throwable, null if none found or null throwable input

		return getCause( throwable, CAUSE_METHOD_NAMES );
	
public static java.lang.ThrowablegetCause(java.lang.Throwable throwable, java.lang.String[] methodNames)

Introspects the Throwable to obtain the cause.

  1. Try known exception types.
  2. Try the supplied array of method names.
  3. Try the field 'detail'.

A null set of method names means use the default set. A null in the set of method names will be ignored.

param
throwable the throwable to introspect for a cause, may be null
param
methodNames the method names, null treated as default set
return
the cause of the Throwable, null if none found or null throwable input

		if ( throwable == null ) {
			return null;
		}
		Throwable cause = getCauseUsingWellKnownTypes( throwable );
		if ( cause == null ) {
			if ( methodNames == null ) {
				methodNames = CAUSE_METHOD_NAMES;
			}
			for ( int i = 0; i < methodNames.length; i++ ) {
				String methodName = methodNames[i];
				if ( methodName != null ) {
					cause = getCauseUsingMethodName( throwable, methodName );
					if ( cause != null ) {
						break;
					}
				}
			}

			if ( cause == null ) {
				cause = getCauseUsingFieldName( throwable, "detail" );
			}
		}
		return cause;
	
private static java.lang.ThrowablegetCauseUsingFieldName(java.lang.Throwable throwable, java.lang.String fieldName)

Finds a Throwable by field name.

param
throwable the exception to examine
param
fieldName the name of the attribute to examine
return
the wrapped exception, or null if not found

		Field field = null;
		try {
			field = throwable.getClass().getField( fieldName );
		}
		catch ( NoSuchFieldException ignored ) {
		}
		catch ( SecurityException ignored ) {
		}

		if ( field != null && Throwable.class.isAssignableFrom( field.getType() ) ) {
			try {
				return ( Throwable ) field.get( throwable );
			}
			catch ( IllegalAccessException ignored ) {
			}
			catch ( IllegalArgumentException ignored ) {
			}
		}
		return null;
	
private static java.lang.ThrowablegetCauseUsingMethodName(java.lang.Throwable throwable, java.lang.String methodName)

Finds a Throwable by method name.

param
throwable the exception to examine
param
methodName the name of the method to find and invoke
return
the wrapped exception, or null if not found

		Method method = null;
		try {
			method = throwable.getClass().getMethod( methodName, null );
		}
		catch ( NoSuchMethodException ignored ) {
		}
		catch ( SecurityException ignored ) {
		}

		if ( method != null && Throwable.class.isAssignableFrom( method.getReturnType() ) ) {
			try {
				return ( Throwable ) method.invoke( throwable, ArrayHelper.EMPTY_OBJECT_ARRAY );
			}
			catch ( IllegalAccessException ignored ) {
			}
			catch ( IllegalArgumentException ignored ) {
			}
			catch ( InvocationTargetException ignored ) {
			}
		}
		return null;
	
private static java.lang.ThrowablegetCauseUsingWellKnownTypes(java.lang.Throwable throwable)

Finds a Throwable for known types.

Uses instanceof checks to examine the exception, looking for well known types which could contain chained or wrapped exceptions.

param
throwable the exception to examine
return
the wrapped exception, or null if not found

		if ( throwable instanceof Nestable ) {
			return ( ( Nestable ) throwable ).getCause();
		}
		else if ( throwable instanceof SQLException ) {
			return ( ( SQLException ) throwable ).getNextException();
		}
		else if ( throwable instanceof InvocationTargetException ) {
			return ( ( InvocationTargetException ) throwable ).getTargetException();
		}
		else {
			return null;
		}
	
public static java.lang.StringgetFullStackTrace(java.lang.Throwable throwable)

A way to get the entire nested stack-trace of an throwable.

param
throwable the Throwable to be examined
return
the nested stack trace, with the root cause first
since
2.0

		StringWriter sw = new StringWriter();
		PrintWriter pw = new PrintWriter( sw, true );
		Throwable[] ts = getThrowables( throwable );
		for ( int i = 0; i < ts.length; i++ ) {
			ts[i].printStackTrace( pw );
			if ( isNestedThrowable( ts[i] ) ) {
				break;
			}
		}
		return sw.getBuffer().toString();
	
public static java.lang.ThrowablegetRootCause(java.lang.Throwable throwable)

Introspects the Throwable to obtain the root cause.

This method walks through the exception chain to the last element, "root" of the tree, using {@link #getCause(Throwable)}, and returns that exception.

param
throwable the throwable to get the root cause for, may be null
return
the root cause of the Throwable, null if none found or null throwable input

		Throwable cause = getCause( throwable );
		if ( cause != null ) {
			throwable = cause;
			while ( ( throwable = getCause( throwable ) ) != null ) {
				cause = throwable;
			}
		}
		return cause;
	
public static java.lang.String[]getRootCauseStackTrace(java.lang.Throwable throwable)

Creates a compact stack trace for the root cause of the supplied Throwable.

param
throwable the throwable to examine, may be null
return
an array of stack trace frames, never null
since
2.0

		if ( throwable == null ) {
			return ArrayHelper.EMPTY_STRING_ARRAY;
		}
		Throwable throwables[] = getThrowables( throwable );
		int count = throwables.length;
		ArrayList frames = new ArrayList();
		List nextTrace = getStackFrameList( throwables[count - 1] );
		for ( int i = count; --i >= 0; ) {
			List trace = nextTrace;
			if ( i != 0 ) {
				nextTrace = getStackFrameList( throwables[i - 1] );
				removeCommonFrames( trace, nextTrace );
			}
			if ( i == count - 1 ) {
				frames.add( throwables[i].toString() );
			}
			else {
				frames.add( WRAPPED_MARKER + throwables[i].toString() );
			}
			for ( int j = 0; j < trace.size(); j++ ) {
				frames.add( trace.get( j ) );
			}
		}
		return ( String[] ) frames.toArray( new String[0] );
	
static java.util.ListgetStackFrameList(java.lang.Throwable t)

Produces a List of stack frames - the message is not included.

This works in most cases - it will only fail if the exception message contains a line that starts with: "   at".

param
t is any throwable
return
List of stack frames

		String stackTrace = getStackTrace( t );
		String linebreak = LINE_SEPARATOR;
		StringTokenizer frames = new StringTokenizer( stackTrace, linebreak );
		List list = new LinkedList();
		boolean traceStarted = false;
		while ( frames.hasMoreTokens() ) {
			String token = frames.nextToken();
			// Determine if the line starts with <whitespace>at
			int at = token.indexOf( "at" );
			if ( at != -1 && token.substring( 0, at ).trim().length() == 0 ) {
				traceStarted = true;
				list.add( token );
			}
			else if ( traceStarted ) {
				break;
			}
		}
		return list;
	
public static java.lang.String[]getStackFrames(java.lang.Throwable throwable)

Captures the stack trace associated with the specified Throwable object, decomposing it into a list of stack frames.

param
throwable the Throwable to exaamine, may be null
return
an array of strings describing each stack frame, never null

		if ( throwable == null ) {
			return ArrayHelper.EMPTY_STRING_ARRAY;
		}
		return getStackFrames( getStackTrace( throwable ) );
	
static java.lang.String[]getStackFrames(java.lang.String stackTrace)

Functionality shared between the getStackFrames(Throwable) methods of this and the {@link org.apache.commons.lang.exception.NestableDelegate} classes.

		String linebreak = LINE_SEPARATOR;
		StringTokenizer frames = new StringTokenizer( stackTrace, linebreak );
		List list = new LinkedList();
		while ( frames.hasMoreTokens() ) {
			list.add( frames.nextToken() );
		}
		return ( String[] ) list.toArray( new String[list.size()] );
	
public static java.lang.StringgetStackTrace(java.lang.Throwable throwable)

Gets the stack trace from a Throwable as a String.

param
throwable the Throwable to be examined
return
the stack trace as generated by the exception's printStackTrace(PrintWriter) method

		StringWriter sw = new StringWriter();
		PrintWriter pw = new PrintWriter( sw, true );
		throwable.printStackTrace( pw );
		return sw.getBuffer().toString();
	
public static intgetThrowableCount(java.lang.Throwable throwable)

Counts the number of Throwable objects in the exception chain.

A throwable without cause will return 1. A throwable with one cause will return 2 and so on. A null throwable will return 0.

param
throwable the throwable to inspect, may be null
return
the count of throwables, zero if null input

		int count = 0;
		while ( throwable != null ) {
			count++;
			throwable = ExceptionUtils.getCause( throwable );
		}
		return count;
	
public static java.lang.Throwable[]getThrowables(java.lang.Throwable throwable)

Returns the list of Throwable objects in the exception chain.

A throwable without cause will return an array containing one element - the input throwable. A throwable with one cause will return an array containing two elements. - the input throwable and the cause throwable. A null throwable will return an array size zero.

param
throwable the throwable to inspect, may be null
return
the array of throwables, never null

		List list = new ArrayList();
		while ( throwable != null ) {
			list.add( throwable );
			throwable = ExceptionUtils.getCause( throwable );
		}
		return ( Throwable[] ) list.toArray( new Throwable[list.size()] );
	
public static intindexOfThrowable(java.lang.Throwable throwable, java.lang.Class type)

Returns the (zero based) index of the first Throwable that matches the specified type in the exception chain.

A null throwable returns -1. A null type returns -1. No match in the chain returns -1.

param
throwable the throwable to inspect, may be null
param
type the type to search for
return
the index into the throwable chain, -1 if no match or null input

		return indexOfThrowable( throwable, type, 0 );
	
public static intindexOfThrowable(java.lang.Throwable throwable, java.lang.Class type, int fromIndex)

Returns the (zero based) index of the first Throwable that matches the specified type in the exception chain from a specified index.

A null throwable returns -1. A null type returns -1. No match in the chain returns -1. A negative start index is treated as zero. A start index greater than the number of throwables returns -1.

param
throwable the throwable to inspect, may be null
param
type the type to search for
param
fromIndex the (zero based) index of the starting position, negative treated as zero, larger than chain size returns -1
return
the index into the throwable chain, -1 if no match or null input

		if ( throwable == null ) {
			return -1;
		}
		if ( fromIndex < 0 ) {
			fromIndex = 0;
		}
		Throwable[] throwables = ExceptionUtils.getThrowables( throwable );
		if ( fromIndex >= throwables.length ) {
			return -1;
		}
		for ( int i = fromIndex; i < throwables.length; i++ ) {
			if ( throwables[i].getClass().equals( type ) ) {
				return i;
			}
		}
		return -1;
	
public static booleanisNestedThrowable(java.lang.Throwable throwable)

Checks whether this Throwable class can store a cause.

This method does not check whether it actually does store a cause.

param
throwable the Throwable to examine, may be null
return
boolean true if nested otherwise false
since
2.0

		if ( throwable == null ) {
			return false;
		}

		if ( throwable instanceof Nestable ) {
			return true;
		}
		else if ( throwable instanceof SQLException ) {
			return true;
		}
		else if ( throwable instanceof InvocationTargetException ) {
			return true;
		}
		else if ( isThrowableNested() ) {
			return true;
		}

		Class cls = throwable.getClass();
		for ( int i = 0, isize = CAUSE_METHOD_NAMES.length; i < isize; i++ ) {
			try {
				Method method = cls.getMethod( CAUSE_METHOD_NAMES[i], null );
				if ( method != null && Throwable.class.isAssignableFrom( method.getReturnType() ) ) {
					return true;
				}
			}
			catch ( NoSuchMethodException ignored ) {
			}
			catch ( SecurityException ignored ) {
			}
		}

		try {
			Field field = cls.getField( "detail" );
			if ( field != null ) {
				return true;
			}
		}
		catch ( NoSuchFieldException ignored ) {
		}
		catch ( SecurityException ignored ) {
		}

		return false;
	
public static booleanisThrowableNested()

Checks if the Throwable class has a getCause method.

This is true for JDK 1.4 and above.

return
true if Throwable is nestable
since
2.0

		return ( THROWABLE_CAUSE_METHOD != null );
	
public static voidprintRootCauseStackTrace(java.lang.Throwable throwable)

Prints a compact stack trace for the root cause of a throwable to System.err.

The compact stack trace starts with the root cause and prints stack frames up to the place where it was caught and wrapped. Then it prints the wrapped exception and continues with stack frames until the wrapper exception is caught and wrapped again, etc.

The method is equivalent to printStackTrace for throwables that don't have nested causes.

param
throwable the throwable to output
since
2.0

		printRootCauseStackTrace( throwable, System.err );
	
public static voidprintRootCauseStackTrace(java.lang.Throwable throwable, java.io.PrintStream stream)

Prints a compact stack trace for the root cause of a throwable.

The compact stack trace starts with the root cause and prints stack frames up to the place where it was caught and wrapped. Then it prints the wrapped exception and continues with stack frames until the wrapper exception is caught and wrapped again, etc.

The method is equivalent to printStackTrace for throwables that don't have nested causes.

param
throwable the throwable to output, may be null
param
stream the stream to output to, may not be null
throws
IllegalArgumentException if the stream is null
since
2.0

		if ( throwable == null ) {
			return;
		}
		if ( stream == null ) {
			throw new IllegalArgumentException( "The PrintStream must not be null" );
		}
		String trace[] = getRootCauseStackTrace( throwable );
		for ( int i = 0; i < trace.length; i++ ) {
			stream.println( trace[i] );
		}
		stream.flush();
	
public static voidprintRootCauseStackTrace(java.lang.Throwable throwable, java.io.PrintWriter writer)

Prints a compact stack trace for the root cause of a throwable.

The compact stack trace starts with the root cause and prints stack frames up to the place where it was caught and wrapped. Then it prints the wrapped exception and continues with stack frames until the wrapper exception is caught and wrapped again, etc.

The method is equivalent to printStackTrace for throwables that don't have nested causes.

param
throwable the throwable to output, may be null
param
writer the writer to output to, may not be null
throws
IllegalArgumentException if the writer is null
since
2.0

		if ( throwable == null ) {
			return;
		}
		if ( writer == null ) {
			throw new IllegalArgumentException( "The PrintWriter must not be null" );
		}
		String trace[] = getRootCauseStackTrace( throwable );
		for ( int i = 0; i < trace.length; i++ ) {
			writer.println( trace[i] );
		}
		writer.flush();
	
public static voidremoveCommonFrames(java.util.List causeFrames, java.util.List wrapperFrames)

Removes common frames from the cause trace given the two stack traces.

param
causeFrames stack trace of a cause throwable
param
wrapperFrames stack trace of a wrapper throwable
throws
IllegalArgumentException if either argument is null
since
2.0

		if ( causeFrames == null || wrapperFrames == null ) {
			throw new IllegalArgumentException( "The List must not be null" );
		}
		int causeFrameIndex = causeFrames.size() - 1;
		int wrapperFrameIndex = wrapperFrames.size() - 1;
		while ( causeFrameIndex >= 0 && wrapperFrameIndex >= 0 ) {
			// Remove the frame from the cause trace if it is the same
			// as in the wrapper trace
			String causeFrame = ( String ) causeFrames.get( causeFrameIndex );
			String wrapperFrame = ( String ) wrapperFrames.get( wrapperFrameIndex );
			if ( causeFrame.equals( wrapperFrame ) ) {
				causeFrames.remove( causeFrameIndex );
			}
			causeFrameIndex--;
			wrapperFrameIndex--;
		}