1 16 package org.apache.commons.lang.exception; 17 18 import java.io.PrintStream ; 19 import java.io.PrintWriter ; 20 import java.io.StringWriter ; 21 import java.lang.reflect.Field ; 22 import java.lang.reflect.InvocationTargetException ; 23 import java.lang.reflect.Method ; 24 import java.sql.SQLException ; 25 import java.util.ArrayList ; 26 import java.util.Arrays ; 27 import java.util.LinkedList ; 28 import java.util.List ; 29 import java.util.StringTokenizer ; 30 31 import org.apache.commons.lang.ArrayUtils; 32 import org.apache.commons.lang.StringUtils; 33 import org.apache.commons.lang.SystemUtils; 34 35 47 public class ExceptionUtils { 48 49 55 static final String WRAPPED_MARKER = " [wrapped] "; 56 57 60 private static String [] CAUSE_METHOD_NAMES = { 61 "getCause", 62 "getNextException", 63 "getTargetException", 64 "getException", 65 "getSourceException", 66 "getRootCause", 67 "getCausedByException", 68 "getNested", 69 "getLinkedException", 70 "getNestedException", 71 "getLinkedCause", 72 "getThrowable", 73 }; 74 75 78 private static final Method THROWABLE_CAUSE_METHOD; 79 static { 80 Method getCauseMethod; 81 try { 82 getCauseMethod = Throwable .class.getMethod("getCause", null); 83 } catch (Exception e) { 84 getCauseMethod = null; 85 } 86 THROWABLE_CAUSE_METHOD = getCauseMethod; 87 } 88 89 93 public ExceptionUtils() { 94 } 95 96 105 public static void addCauseMethodName(String methodName) { 106 if (StringUtils.isNotEmpty(methodName) && !isCauseMethodName(methodName)) { 107 List list = getCauseMethodNameList(); 108 if (list.add(methodName)) { 109 CAUSE_METHOD_NAMES = toArray(list); 110 } 111 } 112 } 113 114 122 public static void removeCauseMethodName(String methodName) { 123 if (StringUtils.isNotEmpty(methodName)) { 124 List list = getCauseMethodNameList(); 125 if (list.remove(methodName)) { 126 CAUSE_METHOD_NAMES = toArray(list); 127 } 128 } 129 } 130 131 136 private static String [] toArray(List list) { 137 return (String []) list.toArray(new String [list.size()]); 138 } 139 140 144 private static ArrayList getCauseMethodNameList() { 145 return new ArrayList (Arrays.asList(CAUSE_METHOD_NAMES)); 146 } 147 148 157 public static boolean isCauseMethodName(String methodName) { 158 return ArrayUtils.indexOf(CAUSE_METHOD_NAMES, methodName) >= 0; 159 } 160 161 192 public static Throwable getCause(Throwable throwable) { 193 return getCause(throwable, CAUSE_METHOD_NAMES); 194 } 195 196 214 public static Throwable getCause(Throwable throwable, String [] methodNames) { 215 if (throwable == null) { 216 return null; 217 } 218 Throwable cause = getCauseUsingWellKnownTypes(throwable); 219 if (cause == null) { 220 if (methodNames == null) { 221 methodNames = CAUSE_METHOD_NAMES; 222 } 223 for (int i = 0; i < methodNames.length; i++) { 224 String methodName = methodNames[i]; 225 if (methodName != null) { 226 cause = getCauseUsingMethodName(throwable, methodName); 227 if (cause != null) { 228 break; 229 } 230 } 231 } 232 233 if (cause == null) { 234 cause = getCauseUsingFieldName(throwable, "detail"); 235 } 236 } 237 return cause; 238 } 239 240 251 public static Throwable getRootCause(Throwable throwable) { 252 Throwable cause = getCause(throwable); 253 if (cause != null) { 254 throwable = cause; 255 while ((throwable = getCause(throwable)) != null) { 256 cause = throwable; 257 } 258 } 259 return cause; 260 } 261 262 272 private static Throwable getCauseUsingWellKnownTypes(Throwable throwable) { 273 if (throwable instanceof Nestable) { 274 return ((Nestable) throwable).getCause(); 275 } else if (throwable instanceof SQLException ) { 276 return ((SQLException ) throwable).getNextException(); 277 } else if (throwable instanceof InvocationTargetException ) { 278 return ((InvocationTargetException ) throwable).getTargetException(); 279 } else { 280 return null; 281 } 282 } 283 284 291 private static Throwable getCauseUsingMethodName(Throwable throwable, String methodName) { 292 Method method = null; 293 try { 294 method = throwable.getClass().getMethod(methodName, null); 295 } catch (NoSuchMethodException ignored) { 296 } catch (SecurityException ignored) { 297 } 298 299 if (method != null && Throwable .class.isAssignableFrom(method.getReturnType())) { 300 try { 301 return (Throwable ) method.invoke(throwable, ArrayUtils.EMPTY_OBJECT_ARRAY); 302 } catch (IllegalAccessException ignored) { 303 } catch (IllegalArgumentException ignored) { 304 } catch (InvocationTargetException ignored) { 305 } 306 } 307 return null; 308 } 309 310 317 private static Throwable getCauseUsingFieldName(Throwable throwable, String fieldName) { 318 Field field = null; 319 try { 320 field = throwable.getClass().getField(fieldName); 321 } catch (NoSuchFieldException ignored) { 322 } catch (SecurityException ignored) { 323 } 324 325 if (field != null && Throwable .class.isAssignableFrom(field.getType())) { 326 try { 327 return (Throwable ) field.get(throwable); 328 } catch (IllegalAccessException ignored) { 329 } catch (IllegalArgumentException ignored) { 330 } 331 } 332 return null; 333 } 334 335 344 public static boolean isThrowableNested() { 345 return THROWABLE_CAUSE_METHOD != null; 346 } 347 348 357 public static boolean isNestedThrowable(Throwable throwable) { 358 if (throwable == null) { 359 return false; 360 } 361 362 if (throwable instanceof Nestable) { 363 return true; 364 } else if (throwable instanceof SQLException ) { 365 return true; 366 } else if (throwable instanceof InvocationTargetException ) { 367 return true; 368 } else if (isThrowableNested()) { 369 return true; 370 } 371 372 Class cls = throwable.getClass(); 373 for (int i = 0, isize = CAUSE_METHOD_NAMES.length; i < isize; i++) { 374 try { 375 Method method = cls.getMethod(CAUSE_METHOD_NAMES[i], null); 376 if (method != null && Throwable .class.isAssignableFrom(method.getReturnType())) { 377 return true; 378 } 379 } catch (NoSuchMethodException ignored) { 380 } catch (SecurityException ignored) { 381 } 382 } 383 384 try { 385 Field field = cls.getField("detail"); 386 if (field != null) { 387 return true; 388 } 389 } catch (NoSuchFieldException ignored) { 390 } catch (SecurityException ignored) { 391 } 392 393 return false; 394 } 395 396 408 public static int getThrowableCount(Throwable throwable) { 409 int count = 0; 410 while (throwable != null) { 411 count++; 412 throwable = ExceptionUtils.getCause(throwable); 413 } 414 return count; 415 } 416 417 430 public static Throwable [] getThrowables(Throwable throwable) { 431 List list = new ArrayList (); 432 while (throwable != null) { 433 list.add(throwable); 434 throwable = ExceptionUtils.getCause(throwable); 435 } 436 return (Throwable []) list.toArray(new Throwable [list.size()]); 437 } 438 439 454 public static int indexOfThrowable(Throwable throwable, Class clazz) { 455 return indexOf(throwable, clazz, 0, false); 456 } 457 458 477 public static int indexOfThrowable(Throwable throwable, Class clazz, int fromIndex) { 478 return indexOf(throwable, clazz, fromIndex, false); 479 } 480 481 497 public static int indexOfType(Throwable throwable, Class type) { 498 return indexOf(throwable, type, 0, true); 499 } 500 501 521 public static int indexOfType(Throwable throwable, Class type, int fromIndex) { 522 return indexOf(throwable, type, fromIndex, true); 523 } 524 525 private static int indexOf(Throwable throwable, Class type, int fromIndex, boolean subclass) { 526 if (throwable == null || type == null) { 527 return -1; 528 } 529 if (fromIndex < 0) { 530 fromIndex = 0; 531 } 532 Throwable [] throwables = ExceptionUtils.getThrowables(throwable); 533 if (fromIndex >= throwables.length) { 534 return -1; 535 } 536 if (subclass) { 537 for (int i = fromIndex; i < throwables.length; i++) { 538 if (type.isAssignableFrom(throwables[i].getClass())) { 539 return i; 540 } 541 } 542 } else { 543 for (int i = fromIndex; i < throwables.length; i++) { 544 if (type.equals(throwables[i].getClass())) { 545 return i; 546 } 547 } 548 } 549 return -1; 550 } 551 552 568 public static void printRootCauseStackTrace(Throwable throwable) { 569 printRootCauseStackTrace(throwable, System.err); 570 } 571 572 588 public static void printRootCauseStackTrace(Throwable throwable, PrintStream stream) { 589 if (throwable == null) { 590 return; 591 } 592 if (stream == null) { 593 throw new IllegalArgumentException ("The PrintStream must not be null"); 594 } 595 String trace[] = getRootCauseStackTrace(throwable); 596 for (int i = 0; i < trace.length; i++) { 597 stream.println(trace[i]); 598 } 599 stream.flush(); 600 } 601 602 618 public static void printRootCauseStackTrace(Throwable throwable, PrintWriter writer) { 619 if (throwable == null) { 620 return; 621 } 622 if (writer == null) { 623 throw new IllegalArgumentException ("The PrintWriter must not be null"); 624 } 625 String trace[] = getRootCauseStackTrace(throwable); 626 for (int i = 0; i < trace.length; i++) { 627 writer.println(trace[i]); 628 } 629 writer.flush(); 630 } 631 632 641 public static String [] getRootCauseStackTrace(Throwable throwable) { 642 if (throwable == null) { 643 return ArrayUtils.EMPTY_STRING_ARRAY; 644 } 645 Throwable throwables[] = getThrowables(throwable); 646 int count = throwables.length; 647 ArrayList frames = new ArrayList (); 648 List nextTrace = getStackFrameList(throwables[count - 1]); 649 for (int i = count; --i >= 0;) { 650 List trace = nextTrace; 651 if (i != 0) { 652 nextTrace = getStackFrameList(throwables[i - 1]); 653 removeCommonFrames(trace, nextTrace); 654 } 655 if (i == count - 1) { 656 frames.add(throwables[i].toString()); 657 } else { 658 frames.add(WRAPPED_MARKER + throwables[i].toString()); 659 } 660 for (int j = 0; j < trace.size(); j++) { 661 frames.add(trace.get(j)); 662 } 663 } 664 return (String []) frames.toArray(new String [0]); 665 } 666 667 675 public static void removeCommonFrames(List causeFrames, List wrapperFrames) { 676 if (causeFrames == null || wrapperFrames == null) { 677 throw new IllegalArgumentException ("The List must not be null"); 678 } 679 int causeFrameIndex = causeFrames.size() - 1; 680 int wrapperFrameIndex = wrapperFrames.size() - 1; 681 while (causeFrameIndex >= 0 && wrapperFrameIndex >= 0) { 682 String causeFrame = (String ) causeFrames.get(causeFrameIndex); 685 String wrapperFrame = (String ) wrapperFrames.get(wrapperFrameIndex); 686 if (causeFrame.equals(wrapperFrame)) { 687 causeFrames.remove(causeFrameIndex); 688 } 689 causeFrameIndex--; 690 wrapperFrameIndex--; 691 } 692 } 693 694 702 public static String getStackTrace(Throwable throwable) { 703 StringWriter sw = new StringWriter (); 704 PrintWriter pw = new PrintWriter (sw, true); 705 throwable.printStackTrace(pw); 706 return sw.getBuffer().toString(); 707 } 708 709 716 public static String getFullStackTrace(Throwable throwable) { 717 StringWriter sw = new StringWriter (); 718 PrintWriter pw = new PrintWriter (sw, true); 719 Throwable [] ts = getThrowables(throwable); 720 for (int i = 0; i < ts.length; i++) { 721 ts[i].printStackTrace(pw); 722 if (isNestedThrowable(ts[i])) { 723 break; 724 } 725 } 726 return sw.getBuffer().toString(); 727 } 728 729 738 public static String [] getStackFrames(Throwable throwable) { 739 if (throwable == null) { 740 return ArrayUtils.EMPTY_STRING_ARRAY; 741 } 742 return getStackFrames(getStackTrace(throwable)); 743 } 744 745 756 static String [] getStackFrames(String stackTrace) { 757 String linebreak = SystemUtils.LINE_SEPARATOR; 758 StringTokenizer frames = new StringTokenizer (stackTrace, linebreak); 759 List list = new LinkedList (); 760 while (frames.hasMoreTokens()) { 761 list.add(frames.nextToken()); 762 } 763 return toArray(list); 764 } 765 766 777 static List getStackFrameList(Throwable t) { 778 String stackTrace = getStackTrace(t); 779 String linebreak = SystemUtils.LINE_SEPARATOR; 780 StringTokenizer frames = new StringTokenizer (stackTrace, linebreak); 781 List list = new LinkedList (); 782 boolean traceStarted = false; 783 while (frames.hasMoreTokens()) { 784 String token = frames.nextToken(); 785 int at = token.indexOf("at"); 787 if (at != -1 && token.substring(0, at).trim().length() == 0) { 788 traceStarted = true; 789 list.add(token); 790 } else if (traceStarted) { 791 break; 792 } 793 } 794 return list; 795 } 796 797 } 798 | Popular Tags |