001package votorola.g.lang; // Copyright 2007-2008, 2011, 2013, Michael Allan. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Votorola Software"), to deal in the Votorola Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicence, and/or sell copies of the Votorola Software, and to permit persons to whom the Votorola Software is furnished to do so, subject to the following conditions: The preceding copyright notice and this permission notice shall be included in all copies or substantial portions of the Votorola Software. THE VOTOROLA SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE VOTOROLA SOFTWARE OR THE USE OR OTHER DEALINGS IN THE VOTOROLA SOFTWARE. 002 003import java.util.*; 004 005 006/** Throwable utilities. 007 */ 008public final @ThreadSafe class ThrowableX 009{ 010 011 012 private ThrowableX() {} 013 014 015 016 /** An empty and immutable list of throwables for use with {@linkplain 017 * #listedThrowable(Throwable,List) listedThrowable}. 018 */ 019 public static final List<Throwable> ENLIST_NONE = Collections.emptyList(); 020 021 022 023 /** Returns true if both throwables are similar, or both null. Compares class, 024 * message, nested causes and stack trace. These comparisons are sufficient to 025 * discriminate among basic throwables, but not necessarily among their subclasses. 026 */ 027 public static boolean isSimilar( final Throwable t1, final Throwable t2 ) 028 { 029 if( t1 == null || t2 == null ) return t1 == t2; 030 031 return t1.getClass().equals( t2.getClass() ) 032 && ObjectX.nullEquals( t1.getMessage(), t2.getMessage() ) 033 && isSimilar( t1.getCause(), t2.getCause() ) 034 && Arrays.equals( t1.getStackTrace(), t2.getStackTrace() ); 035 } 036 037 038 039 /** Enlists the specified throwable and returns the list. 040 * 041 * @param list the pre-constructed list to use. {@linkplain #ENLIST_NONE 042 * ENLIST_NONE} may be specified in order to defeat enlistment and instead 043 * force immediate throwing, but the caller is responsible for detecting and 044 * implementing that. Passing ENLIST_NONE into this method will raise 045 * UnsupportedOperationException. 046 * @return the pre-constructed list, or if necessary a lazily constructed linked 047 * list. 048 */ 049 public static List<Throwable> listedThrowable( final Throwable x, List<Throwable> list ) 050 { 051 if( list == null ) list = new LinkedList<Throwable>(); 052 053 list.add( x ); 054 return list; 055 } 056 057 058 059 /** Contructs an expanded <code>toString</code> that includes the throwable's own, 060 * plus that of all nested causes. 061 */ 062 public static String toStringExpanded( final Throwable t ) 063 { 064 StringBuilder b = new StringBuilder(); 065 for( Throwable cause = t;; ) 066 { 067 b.append( cause.toString() ); 068 cause = cause.getCause(); 069 if( cause == null ) break; 070 071 b.append( ": " ); 072 } 073 return b.toString(); 074 } 075 076 077}