All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cn.webfuse.core.kit.ExceptionKits Maven / Gradle / Ivy

/*
 * Copyright [2018] [https://github.com/vipshop/vjtools]
 *
 * Further modifications copyright (c) 2019 by webfuse.cn
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.webfuse.core.kit;

import cn.webfuse.core.exception.UncheckedException;
import cn.webfuse.core.kit.text.StringBuilderWriter;
import com.google.common.base.Throwables;
import org.apache.commons.lang3.ClassUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;

import java.io.PrintWriter;
import java.lang.reflect.UndeclaredThrowableException;

/**
 * 关于异常的工具类.
 * 

* 1. Checked/Uncheked及Wrap(如ExecutionException)的转换. *

* 2. 打印Exception的辅助函数. (其中一些来自Common Lang ExceptionUtils) *

* 3. 查找Cause(其中一些来自Guava Throwables) *

* 4. StackTrace性能优化相关,尽量使用静态异常避免异常生成时获取StackTrace(Netty) *

* copy from vjtools */ public class ExceptionKits { private static final StackTraceElement[] EMPTY_STACK_TRACE = new StackTraceElement[0]; ///// Checked/Unchecked及Wrap(如ExecutionException)的转换///// /** * 将CheckedException转换为RuntimeException重新抛出, 可以减少函数签名中的CheckExcetpion定义. *

* CheckedException会用UndeclaredThrowableException包裹,RunTimeException和Error则不会被转变. *

* copy from Commons Lange 3.5 ExceptionUtils. *

* 虽然unchecked()里已直接抛出异常,但仍然定义返回值,方便欺骗Sonar。因此本函数也改变了一下返回值 *

* 示例代码: * *

     * try{ ... }catch(Exception e){ throw unchecked(t); }
     * 
* * @see ExceptionUtils#wrapAndThrow(Throwable) */ public static RuntimeException unchecked(Throwable t) { if (t instanceof RuntimeException) { throw (RuntimeException) t; } if (t instanceof Error) { throw (Error) t; } throw new UncheckedException(t); } /** * 如果是著名的包裹类,从cause中获得真正异常. 其他异常则不变. *

* Future中使用的ExecutionException 与 反射时定义的InvocationTargetException, 真正的异常都封装在Cause中 *

* 前面 unchecked() 使用的UncheckedException同理. */ public static Throwable unwrap(Throwable t) { if (t instanceof UncheckedException || t instanceof java.util.concurrent.ExecutionException || t instanceof java.lang.reflect.InvocationTargetException || t instanceof UndeclaredThrowableException) { return t.getCause(); } return t; } /** * 组合unwrap与unchecked,用于处理反射/Callable的异常 */ public static RuntimeException unwrapAndUnchecked(Throwable t) { throw unchecked(unwrap(t)); } ////// 输出内容相关 ////// /** * 将StackTrace[]转换为String, 供Logger或e.printStackTrace()外的其他地方使用. *

* 为了使用StringBuilderWriter,没有用Throwables#getStackTraceAsString(Throwable) */ public static String stackTraceText(Throwable t) { StringBuilderWriter stringWriter = new StringBuilderWriter(); t.printStackTrace(new PrintWriter(stringWriter)); // NOSONAR return stringWriter.toString(); } /** * 拼装 短异常类名: 异常信息. *

* 与Throwable.toString()相比使用了短类名 * * @see ExceptionUtils#getMessage(Throwable) */ public static String toStringWithShortName(Throwable t) { return ExceptionUtils.getMessage(t); } /** * 拼装 短异常类名: 异常信息 <-- RootCause的短异常类名: 异常信息 */ public static String toStringWithRootCause(Throwable t) { if (t == null) { return StringUtils.EMPTY; } final String clsName = ClassUtils.getShortClassName(t, null); final String message = StringUtils.defaultString(t.getMessage()); Throwable cause = getRootCause(t); StringBuilder sb = new StringBuilder(128).append(clsName).append(": ").append(message); if (cause != t) { sb.append("; <---").append(toStringWithShortName(cause)); } return sb.toString(); } ////////// Cause 相关 ///////// /** * 获取异常的Root Cause. *

* 如无底层Cause, 则返回自身 * * @see Throwables#getRootCause(Throwable) */ public static Throwable getRootCause(Throwable t) { return Throwables.getRootCause(t); } /** * 获取某种类型的cause,如果没有则返回空 *

* copy from Jodd ExceptionUtil */ public static T findCause(Throwable throwable, Class cause) { while (throwable != null) { if (throwable.getClass().equals(cause)) { return (T) throwable; } throwable = throwable.getCause(); } return null; } /** * 判断异常是否由某些底层的异常引起. */ @SuppressWarnings("unchecked") public static boolean isCausedBy(Throwable throwable, Class... causeExceptionClasses) { Throwable cause = throwable; while (cause != null) { for (Class causeClass : causeExceptionClasses) { if (causeClass.isInstance(cause)) { return true; } } cause = cause.getCause(); } return false; } /////////// StackTrace 性能优化相关//////// /** * copy from Netty, 为静态异常设置StackTrace. *

* 对某些已知且经常抛出的异常, 不需要每次创建异常类并很消耗性能的并生成完整的StackTrace. 此时可使用静态声明的异常. *

* 如果异常可能在多个地方抛出,使用本函数设置抛出的类名和方法名. * *

     * private static RuntimeException TIMEOUT_EXCEPTION = ExceptionUtil.setStackTrace(new RuntimeException("Timeout"),
     * 		MyClass.class, "mymethod");
     * 
*/ public static T setStackTrace(T throwable, Class throwClass, String throwClazz) { throwable.setStackTrace( new StackTraceElement[]{new StackTraceElement(throwClass.getName(), throwClazz, null, -1)}); return throwable; } /** * 清除StackTrace. 假设StackTrace已生成, 但把它打印出来也有不小的消耗. *

* 如果不能控制StackTrace的生成,也不能控制它的打印端(如logger),可用此方法暴力清除Trace. *

* 但Cause链依然不能清除, 只能清除每一个Cause的StackTrace. */ public static T clearStackTrace(T throwable) { Throwable cause = throwable; while (cause != null) { cause.setStackTrace(EMPTY_STACK_TRACE); cause = cause.getCause(); } return throwable; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy