• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.common.base;
18 
19 import java.io.PrintWriter;
20 import java.io.StringWriter;
21 import java.util.List;
22 import java.util.ArrayList;
23 import java.util.Collections;
24 
25 /**
26  * Static utility methods pertaining to instances of {@link Throwable}.
27  *
28  * @author Kevin Bourrillion
29  * @author Ben Yu
30  * @since 2009.09.15 <b>tentative</b>
31  */
32 public final class Throwables {
Throwables()33   private Throwables() {}
34 
35   /**
36    * Propagates {@code throwable} exactly as-is, if and only if it is an
37    * instance of {@code declaredType}.  Example usage:
38    * <pre>
39    *   try {
40    *     someMethodThatCouldThrowAnything();
41    *   } catch (IKnowWhatToDoWithThisException e) {
42    *     handle(e);
43    *   } catch (Throwable t) {
44    *     Throwables.propagateIfInstanceOf(t, IOException.class);
45    *     Throwables.propagateIfInstanceOf(t, SQLException.class);
46    *     throw Throwables.propagate(t);
47    *   }
48    * </pre>
49    */
propagateIfInstanceOf( Throwable throwable, Class<X> declaredType)50   public static <X extends Throwable> void propagateIfInstanceOf(
51       Throwable throwable, Class<X> declaredType) throws X {
52     if (declaredType.isInstance(throwable)) {
53       throw declaredType.cast(throwable);
54     }
55   }
56 
57   /**
58    * Propagates {@code throwable} exactly as-is, if and only if it is an
59    * instance of {@link RuntimeException} or {@link Error}.  Example usage:
60    * <pre>
61    *   try {
62    *     someMethodThatCouldThrowAnything();
63    *   } catch (IKnowWhatToDoWithThisException e) {
64    *     handle(e);
65    *   } catch (Throwable t) {
66    *     Throwables.propagateIfPossible(t);
67    *     throw new RuntimeException("unexpected", t);
68    *   }
69    * </pre>
70    */
propagateIfPossible(Throwable throwable)71   public static void propagateIfPossible(Throwable throwable) {
72     propagateIfInstanceOf(throwable, Error.class);
73     propagateIfInstanceOf(throwable, RuntimeException.class);
74   }
75 
76   /**
77    * Propagates {@code throwable} exactly as-is, if and only if it is an
78    * instance of {@link RuntimeException}, {@link Error}, or
79    * {@code declaredType}. Example usage:
80    * <pre>
81    *   try {
82    *     someMethodThatCouldThrowAnything();
83    *   } catch (IKnowWhatToDoWithThisException e) {
84    *     handle(e);
85    *   } catch (Throwable t) {
86    *     Throwables.propagateIfPossible(t, OtherException.class);
87    *     throw new RuntimeException("unexpected", t);
88    *   }
89    * </pre>
90    *
91    * @param throwable the Throwable to possibly propagate
92    * @param declaredType the single checked exception type declared by the
93    *     calling method
94    */
propagateIfPossible( Throwable throwable, Class<X> declaredType)95   public static <X extends Throwable> void propagateIfPossible(
96       Throwable throwable, Class<X> declaredType) throws X {
97     propagateIfInstanceOf(throwable, declaredType);
98     propagateIfPossible(throwable);
99   }
100 
101   /**
102    * Propagates {@code throwable} exactly as-is, if and only if it is an
103    * instance of {@link RuntimeException}, {@link Error}, {@code aDeclaredType},
104    * or {@code anotherDeclaredType}.  In the unlikely case that you have three
105    * or more declared checked exception types, you can handle them all by
106    * invoking these methods repeatedly. See usage example in
107    * {@link #propagateIfPossible(Throwable, Class)}.
108    *
109    * @param throwable the Throwable to possibly propagate
110    * @param aDeclaredType any checked exception type declared by the calling
111    *     method
112    * @param anotherDeclaredType any other checked exception type declared by the
113    *     calling method
114    */
115   public static <X1 extends Throwable, X2 extends Throwable> void
propagateIfPossible(Throwable throwable, Class<X1> aDeclaredType, Class<X2> anotherDeclaredType)116       propagateIfPossible(Throwable throwable, Class<X1> aDeclaredType,
117           Class<X2> anotherDeclaredType) throws X1, X2 {
118     propagateIfInstanceOf(throwable, aDeclaredType);
119     propagateIfPossible(throwable, anotherDeclaredType);
120   }
121 
122   /**
123    * Propagates {@code throwable} as-is if it is an instance of
124    * {@link RuntimeException} or {@link Error}, or else as a last resort, wraps
125    * it in a {@code RuntimeException} then propagates.
126    * <p>
127    * This method always throws an exception. The {@code RuntimeException} return
128    * type is only for client code to make Java type system happy in case a
129    * return value is required by the enclosing method. Example usage:
130    * <pre>
131    *   T doSomething() {
132    *     try {
133    *       return someMethodThatCouldThrowAnything();
134    *     } catch (IKnowWhatToDoWithThisException e) {
135    *       return handle(e);
136    *     } catch (Throwable t) {
137    *       throw Throwables.propagate(t);
138    *     }
139    *   }
140    * </pre>
141    *
142    * @param throwable the Throwable to propagate
143    * @return nothing will ever be returned
144    */
propagate(Throwable throwable)145   public static RuntimeException propagate(Throwable throwable) {
146     propagateIfPossible(throwable);
147     throw new RuntimeException(throwable);
148   }
149 
150   /**
151    * Returns the innermost cause of {@code throwable}. The first throwable in a
152    * chain provides context from when the error or exception was initially
153    * detected. Example usage:
154    * <pre>
155    *   assertEquals("Unable to assign a customer id",
156    *       Throwables.getRootCause(e).getMessage());
157    * </pre>
158    */
getRootCause(Throwable throwable)159   public static Throwable getRootCause(Throwable throwable) {
160     Throwable cause;
161     while ((cause = throwable.getCause()) != null) {
162       throwable = cause;
163     }
164     return throwable;
165   }
166 
167   /**
168    * Gets a {@code Throwable} cause chain as a list.  The first entry in the
169    * list will be {@code throwable} followed by its cause hierarchy.  Note
170    * that this is a snapshot of the cause chain and will not reflect
171    * any subsequent changes to the cause chain.
172    *
173    * <p>Here's an example of how it can be used to find specific types
174    * of exceptions in the cause chain:
175    *
176    * <pre>
177    * Iterables.filter(Throwables.getCausalChain(e), IOException.class));
178    * </pre>
179    *
180    * @param throwable the non-null {@code Throwable} to extract causes from
181    * @return an unmodifiable list containing the cause chain starting with
182    *     {@code throwable}
183    */
getCausalChain(Throwable throwable)184   public static List<Throwable> getCausalChain(Throwable throwable) {
185     Preconditions.checkNotNull(throwable);
186     List<Throwable> causes = new ArrayList<Throwable>(4);
187     while (throwable != null) {
188       causes.add(throwable);
189       throwable = throwable.getCause();
190     }
191     return Collections.unmodifiableList(causes);
192   }
193 
194   /**
195    * Returns a string containing the result of
196    * {@link Throwable#toString() toString()}, followed by the full, recursive
197    * stack trace of {@code throwable}. Note that you probably should not be
198    * parsing the resulting string; if you need programmatic access to the stack
199    * frames, you can call {@link Throwable#getStackTrace()}.
200    */
getStackTraceAsString(Throwable throwable)201   public static String getStackTraceAsString(Throwable throwable) {
202     StringWriter stringWriter = new StringWriter();
203     throwable.printStackTrace(new PrintWriter(stringWriter));
204     return stringWriter.toString();
205   }
206 
207   /**
208    * Rethrows the cause exception of a given throwable, discarding the original
209    * throwable. Optionally, the stack frames of the cause and the outer
210    * exception are combined and the stack trace of the cause is set to this
211    * combined trace. If there is no cause the original exception is rethrown
212    * unchanged in all cases.
213    *
214    * @param exception the exception from which to extract the cause
215    * @param combineStackTraces if true the stack trace of the cause will be
216    *     replaced by the concatenation of the trace from the exception and the
217    *     trace from the cause.
218    */
throwCause(Exception exception, boolean combineStackTraces)219   public static Exception throwCause(Exception exception, boolean combineStackTraces)
220       throws Exception {
221     Throwable cause = exception.getCause();
222     if (cause == null) {
223       throw exception;
224     }
225     if (combineStackTraces) {
226       StackTraceElement[] causeTrace = cause.getStackTrace();
227       StackTraceElement[] outerTrace = exception.getStackTrace();
228       StackTraceElement[] combined = new StackTraceElement[causeTrace.length + outerTrace.length];
229       System.arraycopy(causeTrace, 0, combined, 0, causeTrace.length);
230       System.arraycopy(outerTrace, 0, combined, causeTrace.length, outerTrace.length);
231       cause.setStackTrace(combined);
232     }
233     if (cause instanceof Exception) {
234       throw (Exception) cause;
235     }
236     if (cause instanceof Error) {
237       throw (Error) cause;
238     }
239     // The cause is a weird kind of Throwable, so throw the outer exception
240     throw exception;
241   }
242 }
243