/* * Copyright (c) 2002-2012 Alibaba Group Holding Limited. * All rights reserved. * * 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 com.alibaba.toolkit.util.exception; import java.io.PrintStream; import java.io.PrintWriter; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.rmi.RemoteException; import java.sql.SQLException; /** * 可嵌套的异常代理, 简化可嵌套的异常的实现. * * @author Michael Zhou * @version $Id: ChainedThrowableDelegate.java,v 1.1 2003/07/03 07:26:22 baobao * Exp $ */ public class ChainedThrowableDelegate implements ChainedThrowable { private static final long serialVersionUID = 6847759975589708959L; /** 表示异常不存在的常量. */ protected static final Throwable NO_CAUSE = new Throwable(); /** 常见的用来取得异常起因的方法名. */ private static final String[] CAUSE_METHOD_NAMES = { "getNested", "getNestedException", "getNextException", "getTargetException", "getException", "getSourceException", "getCausedByException", "getRootCause", "getCause" }; /** 常见的用来取得异常起因的字段名. */ private static final String[] CAUSE_FIELD_NAMES = { "detail" }; /** 被代理的<code>Throwable</code>对象. */ protected Throwable delegatedThrowable; /** * 创建一个<code>Throwable</code>代理. * * @param throwable 被代理的异常 */ public ChainedThrowableDelegate(Throwable throwable) { this.delegatedThrowable = throwable; } /** * 取得被代理的异常的起因. * * @return 异常的起因. */ public Throwable getCause() { Throwable cause = getCauseByWellKnownTypes(delegatedThrowable); for (Class throwableClass = delegatedThrowable.getClass(); cause == null && Throwable.class.isAssignableFrom(throwableClass); throwableClass = throwableClass.getSuperclass()) { // 尝试常见的方法 for (int i = 0; cause == null && i < CAUSE_METHOD_NAMES.length; i++) { cause = getCauseByMethodName(delegatedThrowable, throwableClass, CAUSE_METHOD_NAMES[i]); } // 尝试常见的字段 for (int i = 0; cause == null && i < CAUSE_FIELD_NAMES.length; i++) { cause = getCauseByFieldName(delegatedThrowable, throwableClass, CAUSE_FIELD_NAMES[i]); } } if (cause == delegatedThrowable) { cause = null; } if (cause == NO_CAUSE) { return null; } return cause; } /** * 取得常见<code>Throwable</code>类的异常起因. * * @param throwable 异常 * @return 异常起因 */ protected Throwable getCauseByWellKnownTypes(Throwable throwable) { Throwable cause = null; boolean isWellKnownType = false; if (throwable instanceof ChainedThrowable) { isWellKnownType = true; cause = ((ChainedThrowable) throwable).getCause(); } else if (throwable instanceof SQLException) { isWellKnownType = true; cause = ((SQLException) throwable).getNextException(); } else if (throwable instanceof InvocationTargetException) { isWellKnownType = true; cause = ((InvocationTargetException) throwable).getTargetException(); } else if (throwable instanceof RemoteException) { isWellKnownType = true; cause = ((RemoteException) throwable).detail; } if (isWellKnownType && cause == null) { return NO_CAUSE; } return cause; } /** * 通过常见的方法动态地取得异常起因. * * @param throwable 异常 * @param throwableClass 异常类 * @param methodName 方法名 * @return 异常起因或<code>NO_CAUSE</code> */ protected Throwable getCauseByMethodName(Throwable throwable, Class throwableClass, String methodName) { Method method = null; try { method = throwableClass.getMethod(methodName, new Class[0]); } catch (NoSuchMethodException ignored) { } if (method != null && Throwable.class.isAssignableFrom(method.getReturnType())) { Throwable cause = null; try { cause = (Throwable) method.invoke(throwable, new Object[0]); } catch (IllegalAccessException ignored) { } catch (IllegalArgumentException ignored) { } catch (InvocationTargetException ignored) { } if (cause == null) { return NO_CAUSE; } return cause; } return null; } /** * 通过常见的方法动态地取得异常起因. * * @param throwable 异常 * @param throwableClass 异常类 * @param fieldName 字段名 * @return 异常起因或<code>NO_CAUSE</code> */ protected Throwable getCauseByFieldName(Throwable throwable, Class throwableClass, String fieldName) { Field field = null; try { field = throwableClass.getField(fieldName); } catch (NoSuchFieldException ignored) { } if (field != null && Throwable.class.isAssignableFrom(field.getType())) { Throwable cause = null; try { cause = (Throwable) field.get(throwable); } catch (IllegalAccessException ignored) { } catch (IllegalArgumentException ignored) { } if (cause == null) { return NO_CAUSE; } return cause; } return null; } /** 打印调用栈到标准错误. */ public void printStackTrace() { ExceptionHelper.printStackTrace(this); } /** * 打印调用栈到指定输出流. * * @param stream 输出字节流. */ public void printStackTrace(PrintStream stream) { ExceptionHelper.printStackTrace(this, stream); } /** * 打印调用栈到指定输出流. * * @param writer 输出字符流. */ public void printStackTrace(PrintWriter writer) { ExceptionHelper.printStackTrace(this, writer); } /** * 打印异常的调用栈, 不包括起因异常的信息. * * @param writer 打印到输出流 */ public void printCurrentStackTrace(PrintWriter writer) { if (delegatedThrowable instanceof ChainedThrowable) { ((ChainedThrowable) delegatedThrowable).printCurrentStackTrace(writer); } else { delegatedThrowable.printStackTrace(writer); } } }