io.quarkus.runtime.util.ExceptionUtil Maven / Gradle / Ivy
package io.quarkus.runtime.util;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
/**
*
*/
public class ExceptionUtil {
/**
* Returns the string representation of the stacktrace of the passed {@code exception}
*
* @param exception
* @return
*/
public static String generateStackTrace(final Throwable exception) {
if (exception == null) {
return null;
}
final StringWriter stringWriter = new StringWriter();
exception.printStackTrace(new PrintWriter(stringWriter));
return stringWriter.toString().trim();
}
/**
* Returns an "upside down" stacktrace of the {@code exception} with the root
* cause showing up first in the stacktrace.
* Note: This is a relatively expensive method because it creates additional
* exceptions and manipulates their stacktrace. Care should be taken to determine whether
* usage of this method is necessary.
*
* @param exception The exception
* @return
*/
public static String rootCauseFirstStackTrace(final Throwable exception) {
if (exception == null) {
return null;
}
// create an exception chain with the root cause being at element 0
final List exceptionChain = new ArrayList<>();
Throwable curr = exception;
while (curr != null) {
exceptionChain.add(0, curr);
curr = curr.getCause();
}
Throwable prevStrippedCause = null;
Throwable modifiedRoot = null;
// We reverse the stacktrace as follows:
// - Iterate the exception chain that we created, which has the root cause at element 0
// - for each exception in this chain
// - create a new "copy" C1 of that exception
// - create a new copy C2 of the "next" exception in the chain with its cause stripped off
// - C1.initCause(C2)
// - keep track of the copy C1 of the first element in the exception chain. That C1, lets call
// it RC1, will be the modified representation of the root cause on which if printStackTrace()
// is called, then it will end up printing stacktrace in reverse order (because of the way we
// fiddled around with its causes and other details)
// - Finally, replace the occurrences of "Caused by:" string the in the stacktrace to "Resulted in:"
// to better phrase the reverse stacktrace representation.
for (int i = 0; i < exceptionChain.size(); i++) {
final Throwable x = prevStrippedCause == null ? stripCause(exceptionChain.get(0)) : prevStrippedCause;
if (i != exceptionChain.size() - 1) {
final Throwable strippedCause = stripCause(exceptionChain.get(i + 1));
x.initCause(strippedCause);
prevStrippedCause = strippedCause;
}
if (i == 0) {
modifiedRoot = x;
}
}
return generateStackTrace(modifiedRoot).replace("Caused by:", "Resulted in:");
}
public static Throwable getRootCause(Throwable exception) {
final List chain = new ArrayList<>();
Throwable curr = exception;
while (curr != null && !chain.contains(curr)) {
chain.add(curr);
curr = curr.getCause();
}
return chain.isEmpty() ? null : chain.get(chain.size() - 1);
}
public static boolean isAnyCauseInstanceOf(Throwable exception, Class classToCheck) {
Throwable curr = exception;
do {
if (classToCheck.isInstance(curr)) {
return true;
}
curr = curr.getCause();
} while (curr != null);
return false;
}
/**
* Creates and returns a new {@link Throwable} which has the following characteristics:
*
* - The {@code cause} of the Throwable hasn't yet been {@link Throwable#initCause(Throwable) inited}
* and thus can be "inited" later on if needed
*
* -
* The stacktrace elements of the Throwable have been set to the stacktrace elements of the passed
* {@code t}. That way, any call to {@link Throwable#printStackTrace(PrintStream)} for example
* will print the stacktrace of the passed {@code t}
*
*
*
* @param t The exception
* @return
*/
private static Throwable stripCause(final Throwable t) {
final Throwable stripped = delegatingToStringThrowable(t);
stripped.setStackTrace(t.getStackTrace());
return stripped;
}
/**
* Creates and returns a new {@link Throwable} whose {@link Throwable#toString()} has been
* overridden to call the {@code toString()} method of the passed {@code t}.
*
* @param t The exception
* @return
*/
private static Throwable delegatingToStringThrowable(final Throwable t) {
return new Throwable() {
@Override
public String toString() {
return t.toString();
}
};
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy