• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 The Guava Authors
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 static com.google.common.base.Preconditions.checkNotNull;
20 
21 import com.google.common.annotations.Beta;
22 
23 import java.io.PrintWriter;
24 import java.io.StringWriter;
25 import java.util.ArrayList;
26 import java.util.Collections;
27 import java.util.List;
28 
29 import javax.annotation.Nullable;
30 
31 /**
32  * Static utility methods pertaining to instances of {@link Throwable}.
33  *
34  * <p>See the Guava User Guide entry on <a href=
35  * "http://code.google.com/p/guava-libraries/wiki/ThrowablesExplained">
36  * Throwables</a>.
37  *
38  * @author Kevin Bourrillion
39  * @author Ben Yu
40  * @since 1.0
41  */
42 public final class Throwables {
Throwables()43   private Throwables() {}
44 
45   /**
46    * Propagates {@code throwable} exactly as-is, if and only if it is an
47    * instance of {@code declaredType}.  Example usage:
48    * <pre>
49    *   try {
50    *     someMethodThatCouldThrowAnything();
51    *   } catch (IKnowWhatToDoWithThisException e) {
52    *     handle(e);
53    *   } catch (Throwable t) {
54    *     Throwables.propagateIfInstanceOf(t, IOException.class);
55    *     Throwables.propagateIfInstanceOf(t, SQLException.class);
56    *     throw Throwables.propagate(t);
57    *   }
58    * </pre>
59    */
propagateIfInstanceOf( @ullable Throwable throwable, Class<X> declaredType)60   public static <X extends Throwable> void propagateIfInstanceOf(
61       @Nullable Throwable throwable, Class<X> declaredType) throws X {
62     // Check for null is needed to avoid frequent JNI calls to isInstance().
63     if (throwable != null && declaredType.isInstance(throwable)) {
64       throw declaredType.cast(throwable);
65     }
66   }
67 
68   /**
69    * Propagates {@code throwable} exactly as-is, if and only if it is an
70    * instance of {@link RuntimeException} or {@link Error}.  Example usage:
71    * <pre>
72    *   try {
73    *     someMethodThatCouldThrowAnything();
74    *   } catch (IKnowWhatToDoWithThisException e) {
75    *     handle(e);
76    *   } catch (Throwable t) {
77    *     Throwables.propagateIfPossible(t);
78    *     throw new RuntimeException("unexpected", t);
79    *   }
80    * </pre>
81    */
propagateIfPossible(@ullable Throwable throwable)82   public static void propagateIfPossible(@Nullable Throwable throwable) {
83     propagateIfInstanceOf(throwable, Error.class);
84     propagateIfInstanceOf(throwable, RuntimeException.class);
85   }
86 
87   /**
88    * Propagates {@code throwable} exactly as-is, if and only if it is an
89    * instance of {@link RuntimeException}, {@link Error}, or
90    * {@code declaredType}. Example usage:
91    * <pre>
92    *   try {
93    *     someMethodThatCouldThrowAnything();
94    *   } catch (IKnowWhatToDoWithThisException e) {
95    *     handle(e);
96    *   } catch (Throwable t) {
97    *     Throwables.propagateIfPossible(t, OtherException.class);
98    *     throw new RuntimeException("unexpected", t);
99    *   }
100    * </pre>
101    *
102    * @param throwable the Throwable to possibly propagate
103    * @param declaredType the single checked exception type declared by the
104    *     calling method
105    */
propagateIfPossible( @ullable Throwable throwable, Class<X> declaredType)106   public static <X extends Throwable> void propagateIfPossible(
107       @Nullable Throwable throwable, Class<X> declaredType) throws X {
108     propagateIfInstanceOf(throwable, declaredType);
109     propagateIfPossible(throwable);
110   }
111 
112   /**
113    * Propagates {@code throwable} exactly as-is, if and only if it is an
114    * instance of {@link RuntimeException}, {@link Error}, {@code declaredType1},
115    * or {@code declaredType2}.  In the unlikely case that you have three or more
116    * declared checked exception types, you can handle them all by invoking these
117    * methods repeatedly. See usage example in {@link
118    * #propagateIfPossible(Throwable, Class)}.
119    *
120    * @param throwable the Throwable to possibly propagate
121    * @param declaredType1 any checked exception type declared by the calling
122    *     method
123    * @param declaredType2 any other checked exception type declared by the
124    *     calling method
125    */
126   public static <X1 extends Throwable, X2 extends Throwable>
propagateIfPossible(@ullable Throwable throwable, Class<X1> declaredType1, Class<X2> declaredType2)127       void propagateIfPossible(@Nullable Throwable throwable,
128           Class<X1> declaredType1, Class<X2> declaredType2) throws X1, X2 {
129     checkNotNull(declaredType2);
130     propagateIfInstanceOf(throwable, declaredType1);
131     propagateIfPossible(throwable, declaredType2);
132   }
133 
134   /**
135    * Propagates {@code throwable} as-is if it is an instance of
136    * {@link RuntimeException} or {@link Error}, or else as a last resort, wraps
137    * it in a {@code RuntimeException} then propagates.
138    * <p>
139    * This method always throws an exception. The {@code RuntimeException} return
140    * type is only for client code to make Java type system happy in case a
141    * return value is required by the enclosing method. Example usage:
142    * <pre>
143    *   T doSomething() {
144    *     try {
145    *       return someMethodThatCouldThrowAnything();
146    *     } catch (IKnowWhatToDoWithThisException e) {
147    *       return handle(e);
148    *     } catch (Throwable t) {
149    *       throw Throwables.propagate(t);
150    *     }
151    *   }
152    * </pre>
153    *
154    * @param throwable the Throwable to propagate
155    * @return nothing will ever be returned; this return type is only for your
156    *     convenience, as illustrated in the example above
157    */
propagate(Throwable throwable)158   public static RuntimeException propagate(Throwable throwable) {
159     propagateIfPossible(checkNotNull(throwable));
160     throw new RuntimeException(throwable);
161   }
162 
163   /**
164    * Returns the innermost cause of {@code throwable}. The first throwable in a
165    * chain provides context from when the error or exception was initially
166    * detected. Example usage:
167    * <pre>
168    *   assertEquals("Unable to assign a customer id",
169    *       Throwables.getRootCause(e).getMessage());
170    * </pre>
171    */
getRootCause(Throwable throwable)172   public static Throwable getRootCause(Throwable throwable) {
173     Throwable cause;
174     while ((cause = throwable.getCause()) != null) {
175       throwable = cause;
176     }
177     return throwable;
178   }
179 
180   /**
181    * Gets a {@code Throwable} cause chain as a list.  The first entry in the
182    * list will be {@code throwable} followed by its cause hierarchy.  Note
183    * that this is a snapshot of the cause chain and will not reflect
184    * any subsequent changes to the cause chain.
185    *
186    * <p>Here's an example of how it can be used to find specific types
187    * of exceptions in the cause chain:
188    *
189    * <pre>
190    * Iterables.filter(Throwables.getCausalChain(e), IOException.class));
191    * </pre>
192    *
193    * @param throwable the non-null {@code Throwable} to extract causes from
194    * @return an unmodifiable list containing the cause chain starting with
195    *     {@code throwable}
196    */
197   @Beta // TODO(kevinb): decide best return type
getCausalChain(Throwable throwable)198   public static List<Throwable> getCausalChain(Throwable throwable) {
199     checkNotNull(throwable);
200     List<Throwable> causes = new ArrayList<Throwable>(4);
201     while (throwable != null) {
202       causes.add(throwable);
203       throwable = throwable.getCause();
204     }
205     return Collections.unmodifiableList(causes);
206   }
207 
208   /**
209    * Returns a string containing the result of
210    * {@link Throwable#toString() toString()}, followed by the full, recursive
211    * stack trace of {@code throwable}. Note that you probably should not be
212    * parsing the resulting string; if you need programmatic access to the stack
213    * frames, you can call {@link Throwable#getStackTrace()}.
214    */
getStackTraceAsString(Throwable throwable)215   public static String getStackTraceAsString(Throwable throwable) {
216     StringWriter stringWriter = new StringWriter();
217     throwable.printStackTrace(new PrintWriter(stringWriter));
218     return stringWriter.toString();
219   }
220 }
221