cn.hutool.core.exceptions.ExceptionUtil Maven / Gradle / Ivy
package cn.hutool.core.exceptions;
import cn.hutool.core.io.FastByteArrayOutputStream;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import java.io.PrintStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.UndeclaredThrowableException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 异常工具类
*
* @author Looly
*/
public class ExceptionUtil {
/**
* 获得完整消息,包括异常名,消息格式为:{SimpleClassName}: {ThrowableMessage}
*
* @param e 异常
* @return 完整消息
*/
public static String getMessage(Throwable e) {
if (null == e) {
return StrUtil.NULL;
}
return StrUtil.format("{}: {}", e.getClass().getSimpleName(), e.getMessage());
}
/**
* 获得消息,调用异常类的getMessage方法
*
* @param e 异常
* @return 消息
*/
public static String getSimpleMessage(Throwable e) {
return (null == e) ? StrUtil.NULL : e.getMessage();
}
/**
* 使用运行时异常包装编译异常
*
* 如果传入参数已经是运行时异常,则直接返回,不再额外包装
*
* @param throwable 异常
* @return 运行时异常
*/
public static RuntimeException wrapRuntime(Throwable throwable) {
if (throwable instanceof RuntimeException) {
return (RuntimeException) throwable;
}
return new RuntimeException(throwable);
}
/**
* 将指定的消息包装为运行时异常
*
* @param message 异常消息
* @return 运行时异常
* @since 5.5.2
*/
public static RuntimeException wrapRuntime(String message) {
return new RuntimeException(message);
}
/**
* 包装一个异常
*
* @param 被包装的异常类型
* @param throwable 异常
* @param wrapThrowable 包装后的异常类
* @return 包装后的异常
* @since 3.3.0
*/
@SuppressWarnings("unchecked")
public static T wrap(Throwable throwable, Class wrapThrowable) {
if (wrapThrowable.isInstance(throwable)) {
return (T) throwable;
}
return ReflectUtil.newInstance(wrapThrowable, throwable);
}
/**
* 包装异常并重新抛出此异常
* {@link RuntimeException} 和{@link Error} 直接抛出,其它检查异常包装为{@link UndeclaredThrowableException} 后抛出
*
* @param throwable 异常
*/
public static void wrapAndThrow(Throwable throwable) {
if (throwable instanceof RuntimeException) {
throw (RuntimeException) throwable;
}
if (throwable instanceof Error) {
throw (Error) throwable;
}
throw new UndeclaredThrowableException(throwable);
}
/**
* 将消息包装为运行时异常并抛出
*
* @param message 异常消息
* @since 5.5.2
*/
public static void wrapRuntimeAndThrow(String message) {
throw new RuntimeException(message);
}
/**
* 剥离反射引发的InvocationTargetException、UndeclaredThrowableException中间异常,返回业务本身的异常
*
* @param wrapped 包装的异常
* @return 剥离后的异常
*/
public static Throwable unwrap(Throwable wrapped) {
Throwable unwrapped = wrapped;
while (true) {
if (unwrapped instanceof InvocationTargetException) {
unwrapped = ((InvocationTargetException) unwrapped).getTargetException();
} else if (unwrapped instanceof UndeclaredThrowableException) {
unwrapped = ((UndeclaredThrowableException) unwrapped).getUndeclaredThrowable();
} else {
return unwrapped;
}
}
}
/**
* 获取当前栈信息
*
* @return 当前栈信息
*/
public static StackTraceElement[] getStackElements() {
// return (new Throwable()).getStackTrace();
return Thread.currentThread().getStackTrace();
}
/**
* 获取指定层的堆栈信息
*
* @param i 层数
* @return 指定层的堆栈信息
* @since 4.1.4
*/
public static StackTraceElement getStackElement(int i) {
return Thread.currentThread().getStackTrace()[i];
}
/**
* 获取指定层的堆栈信息
*
* @param fqcn 指定类名为基础
* @param i 指定类名的类堆栈相对层数
* @return 指定层的堆栈信息
* @since 5.6.6
*/
public static StackTraceElement getStackElement(String fqcn, int i) {
final StackTraceElement[] stackTraceArray = Thread.currentThread().getStackTrace();
final int index = ArrayUtil.matchIndex((ele) -> StrUtil.equals(fqcn, ele.getClassName()), stackTraceArray);
if(index > 0){
return stackTraceArray[index + i];
}
return null;
}
/**
* 获取入口堆栈信息
*
* @return 入口堆栈信息
* @since 4.1.4
*/
public static StackTraceElement getRootStackElement() {
final StackTraceElement[] stackElements = Thread.currentThread().getStackTrace();
return Thread.currentThread().getStackTrace()[stackElements.length - 1];
}
/**
* 堆栈转为单行完整字符串
*
* @param throwable 异常对象
* @return 堆栈转为的字符串
*/
public static String stacktraceToOneLineString(Throwable throwable) {
return stacktraceToOneLineString(throwable, 3000);
}
/**
* 堆栈转为单行完整字符串
*
* @param throwable 异常对象
* @param limit 限制最大长度
* @return 堆栈转为的字符串
*/
public static String stacktraceToOneLineString(Throwable throwable, int limit) {
Map replaceCharToStrMap = new HashMap<>();
replaceCharToStrMap.put(StrUtil.C_CR, StrUtil.SPACE);
replaceCharToStrMap.put(StrUtil.C_LF, StrUtil.SPACE);
replaceCharToStrMap.put(StrUtil.C_TAB, StrUtil.SPACE);
return stacktraceToString(throwable, limit, replaceCharToStrMap);
}
/**
* 堆栈转为完整字符串
*
* @param throwable 异常对象
* @return 堆栈转为的字符串
*/
public static String stacktraceToString(Throwable throwable) {
return stacktraceToString(throwable, 3000);
}
/**
* 堆栈转为完整字符串
*
* @param throwable 异常对象
* @param limit 限制最大长度
* @return 堆栈转为的字符串
*/
public static String stacktraceToString(Throwable throwable, int limit) {
return stacktraceToString(throwable, limit, null);
}
/**
* 堆栈转为完整字符串
*
* @param throwable 异常对象
* @param limit 限制最大长度,>0表示不限制长度
* @param replaceCharToStrMap 替换字符为指定字符串
* @return 堆栈转为的字符串
*/
public static String stacktraceToString(Throwable throwable, int limit, Map replaceCharToStrMap) {
final FastByteArrayOutputStream baos = new FastByteArrayOutputStream();
throwable.printStackTrace(new PrintStream(baos));
final String exceptionStr = baos.toString();
final int length = exceptionStr.length();
if (limit < 0 || limit > length) {
limit = length;
}
if (MapUtil.isNotEmpty(replaceCharToStrMap)) {
final StringBuilder sb = StrUtil.builder();
char c;
String value;
for (int i = 0; i < limit; i++) {
c = exceptionStr.charAt(i);
value = replaceCharToStrMap.get(c);
if (null != value) {
sb.append(value);
} else {
sb.append(c);
}
}
return sb.toString();
} else {
if(limit == length){
return exceptionStr;
}
return StrUtil.subPre(exceptionStr, limit);
}
}
/**
* 判断是否由指定异常类引起
*
* @param throwable 异常
* @param causeClasses 定义的引起异常的类
* @return 是否由指定异常类引起
* @since 4.1.13
*/
@SuppressWarnings("unchecked")
public static boolean isCausedBy(Throwable throwable, Class extends Exception>... causeClasses) {
return null != getCausedBy(throwable, causeClasses);
}
/**
* 获取由指定异常类引起的异常
*
* @param throwable 异常
* @param causeClasses 定义的引起异常的类
* @return 是否由指定异常类引起
* @since 4.1.13
*/
@SuppressWarnings("unchecked")
public static Throwable getCausedBy(Throwable throwable, Class extends Exception>... causeClasses) {
Throwable cause = throwable;
while (cause != null) {
for (Class extends Exception> causeClass : causeClasses) {
if (causeClass.isInstance(cause)) {
return cause;
}
}
cause = cause.getCause();
}
return null;
}
/**
* 判断指定异常是否来自或者包含指定异常
*
* @param throwable 异常
* @param exceptionClass 定义的引起异常的类
* @return true 来自或者包含
* @since 4.3.2
*/
public static boolean isFromOrSuppressedThrowable(Throwable throwable, Class extends Throwable> exceptionClass) {
return convertFromOrSuppressedThrowable(throwable, exceptionClass, true) != null;
}
/**
* 判断指定异常是否来自或者包含指定异常
*
* @param throwable 异常
* @param exceptionClass 定义的引起异常的类
* @param checkCause 判断cause
* @return true 来自或者包含
* @since 4.4.1
*/
public static boolean isFromOrSuppressedThrowable(Throwable throwable, Class extends Throwable> exceptionClass, boolean checkCause) {
return convertFromOrSuppressedThrowable(throwable, exceptionClass, checkCause) != null;
}
/**
* 转化指定异常为来自或者包含指定异常
*
* @param 异常类型
* @param throwable 异常
* @param exceptionClass 定义的引起异常的类
* @return 结果为null 不是来自或者包含
* @since 4.3.2
*/
public static T convertFromOrSuppressedThrowable(Throwable throwable, Class exceptionClass) {
return convertFromOrSuppressedThrowable(throwable, exceptionClass, true);
}
/**
* 转化指定异常为来自或者包含指定异常
*
* @param 异常类型
* @param throwable 异常
* @param exceptionClass 定义的引起异常的类
* @param checkCause 判断cause
* @return 结果为null 不是来自或者包含
* @since 4.4.1
*/
@SuppressWarnings("unchecked")
public static T convertFromOrSuppressedThrowable(Throwable throwable, Class exceptionClass, boolean checkCause) {
if (throwable == null || exceptionClass == null) {
return null;
}
if (exceptionClass.isAssignableFrom(throwable.getClass())) {
return (T) throwable;
}
if (checkCause) {
Throwable cause = throwable.getCause();
if (cause != null && exceptionClass.isAssignableFrom(cause.getClass())) {
return (T) cause;
}
}
Throwable[] throwables = throwable.getSuppressed();
if (ArrayUtil.isNotEmpty(throwables)) {
for (Throwable throwable1 : throwables) {
if (exceptionClass.isAssignableFrom(throwable1.getClass())) {
return (T) throwable1;
}
}
}
return null;
}
/**
* 获取异常链上所有异常的集合,如果{@link Throwable} 对象没有cause,返回只有一个节点的List
* 如果传入null,返回空集合
*
*
* 此方法来自Apache-Commons-Lang3
*
*
* @param throwable 异常对象,可以为null
* @return 异常链中所有异常集合
* @since 4.6.2
*/
public static List getThrowableList(Throwable throwable) {
final List list = new ArrayList<>();
while (throwable != null && false == list.contains(throwable)) {
list.add(throwable);
throwable = throwable.getCause();
}
return list;
}
/**
* 获取异常链中最尾端的异常,即异常最早发生的异常对象。
* 此方法通过调用{@link Throwable#getCause()} 直到没有cause为止,如果异常本身没有cause,返回异常本身
* 传入null返回也为null
*
*
* 此方法来自Apache-Commons-Lang3
*
*
* @param throwable 异常对象,可能为null
* @return 最尾端异常,传入null参数返回也为null
*/
public static Throwable getRootCause(final Throwable throwable) {
final List list = getThrowableList(throwable);
return list.size() < 1 ? null : list.get(list.size() - 1);
}
/**
* 获取异常链中最尾端的异常的消息,消息格式为:{SimpleClassName}: {ThrowableMessage}
*
* @param th 异常
* @return 消息
* @since 4.6.2
*/
public static String getRootCauseMessage(final Throwable th) {
return getMessage(getRootCause(th));
}
}