View Javadoc
1   /*
2    * Copyright (C) 2007 The Guava Authors
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5    * in compliance with the License. You may obtain a copy of the License at
6    *
7    * http://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software distributed under the License
10   * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11   * or implied. See the License for the specific language governing permissions and limitations under
12   * the License.
13   */
14  
15  package com.google.common.base;
16  
17  import static com.google.common.base.Preconditions.checkNotNull;
18  import static java.util.Arrays.asList;
19  import static java.util.Collections.unmodifiableList;
20  
21  import com.google.common.annotations.Beta;
22  import com.google.common.annotations.GwtCompatible;
23  import com.google.common.annotations.GwtIncompatible;
24  import com.google.common.annotations.VisibleForTesting;
25  import com.google.errorprone.annotations.CanIgnoreReturnValue;
26  import java.io.IOException;
27  import java.io.PrintWriter;
28  import java.io.StringWriter;
29  import java.lang.reflect.InvocationTargetException;
30  import java.lang.reflect.Method;
31  import java.util.AbstractList;
32  import java.util.ArrayList;
33  import java.util.Collections;
34  import java.util.List;
35  import javax.annotation.Nullable;
36  
37  /**
38   * Static utility methods pertaining to instances of {@link Throwable}.
39   *
40   * <p>See the Guava User Guide entry on <a
41   * href="https://github.com/google/guava/wiki/ThrowablesExplained">Throwables</a>.
42   *
43   * @author Kevin Bourrillion
44   * @author Ben Yu
45   * @since 1.0
46   */
47  @GwtCompatible(emulated = true)
48  public final class Throwables {
49    private Throwables() {}
50  
51    /**
52     * Throws {@code throwable} if it is an instance of {@code declaredType}. Example usage:
53     *
54     * <pre>
55     * for (Foo foo : foos) {
56     *   try {
57     *     foo.bar();
58     *   } catch (BarException | RuntimeException | Error t) {
59     *     failure = t;
60     *   }
61     * }
62     * if (failure != null) {
63     *   throwIfInstanceOf(failure, BarException.class);
64     *   throwIfUnchecked(failure);
65     *   throw new AssertionError(failure);
66     * }
67     * </pre>
68     *
69     * @since 20.0
70     */
71    @GwtIncompatible // Class.cast, Class.isInstance
72    public static <X extends Throwable> void throwIfInstanceOf(
73        Throwable throwable, Class<X> declaredType) throws X {
74      checkNotNull(throwable);
75      if (declaredType.isInstance(throwable)) {
76        throw declaredType.cast(throwable);
77      }
78    }
79  
80    /**
81     * Propagates {@code throwable} exactly as-is, if and only if it is an instance of {@code
82     * declaredType}. Example usage:
83     *
84     * <pre>
85     * try {
86     *   someMethodThatCouldThrowAnything();
87     * } catch (IKnowWhatToDoWithThisException e) {
88     *   handle(e);
89     * } catch (Throwable t) {
90     *   Throwables.propagateIfInstanceOf(t, IOException.class);
91     *   Throwables.propagateIfInstanceOf(t, SQLException.class);
92     *   throw Throwables.propagate(t);
93     * }
94     * </pre>
95     *
96     * @deprecated Use {@link #throwIfInstanceOf}, which has the same behavior but rejects {@code
97     *     null}.
98     */
99    @Deprecated
100   @GwtIncompatible // throwIfInstanceOf
101   public static <X extends Throwable> void propagateIfInstanceOf(
102       @Nullable Throwable throwable, Class<X> declaredType) throws X {
103     if (throwable != null) {
104       throwIfInstanceOf(throwable, declaredType);
105     }
106   }
107 
108   /**
109    * Throws {@code throwable} if it is a {@link RuntimeException} or {@link Error}. Example usage:
110    *
111    * <pre>
112    * for (Foo foo : foos) {
113    *   try {
114    *     foo.bar();
115    *   } catch (RuntimeException | Error t) {
116    *     failure = t;
117    *   }
118    * }
119    * if (failure != null) {
120    *   throwIfUnchecked(failure);
121    *   throw new AssertionError(failure);
122    * }
123    * </pre>
124    *
125    * @since 20.0
126    */
127   public static void throwIfUnchecked(Throwable throwable) {
128     checkNotNull(throwable);
129     if (throwable instanceof RuntimeException) {
130       throw (RuntimeException) throwable;
131     }
132     if (throwable instanceof Error) {
133       throw (Error) throwable;
134     }
135   }
136 
137   /**
138    * Propagates {@code throwable} exactly as-is, if and only if it is an instance of {@link
139    * RuntimeException} or {@link Error}. Example usage:
140    *
141    * <pre>
142    * try {
143    *   someMethodThatCouldThrowAnything();
144    * } catch (IKnowWhatToDoWithThisException e) {
145    *   handle(e);
146    * } catch (Throwable t) {
147    *   Throwables.propagateIfPossible(t);
148    *   throw new RuntimeException("unexpected", t);
149    * }
150    * </pre>
151    *
152    * @deprecated Use {@link #throwIfUnchecked}, which has the same behavior but rejects {@code
153    *     null}.
154    */
155   @Deprecated
156   @GwtIncompatible
157   public static void propagateIfPossible(@Nullable Throwable throwable) {
158     if (throwable != null) {
159       throwIfUnchecked(throwable);
160     }
161   }
162 
163   /**
164    * Propagates {@code throwable} exactly as-is, if and only if it is an instance of {@link
165    * RuntimeException}, {@link Error}, or {@code declaredType}. Example usage:
166    *
167    * <pre>
168    * try {
169    *   someMethodThatCouldThrowAnything();
170    * } catch (IKnowWhatToDoWithThisException e) {
171    *   handle(e);
172    * } catch (Throwable t) {
173    *   Throwables.propagateIfPossible(t, OtherException.class);
174    *   throw new RuntimeException("unexpected", t);
175    * }
176    * </pre>
177    *
178    * @param throwable the Throwable to possibly propagate
179    * @param declaredType the single checked exception type declared by the calling method
180    */
181   @GwtIncompatible // propagateIfInstanceOf
182   public static <X extends Throwable> void propagateIfPossible(
183       @Nullable Throwable throwable, Class<X> declaredType) throws X {
184     propagateIfInstanceOf(throwable, declaredType);
185     propagateIfPossible(throwable);
186   }
187 
188   /**
189    * Propagates {@code throwable} exactly as-is, if and only if it is an instance of {@link
190    * RuntimeException}, {@link Error}, {@code declaredType1}, or {@code declaredType2}. In the
191    * unlikely case that you have three or more declared checked exception types, you can handle them
192    * all by invoking these methods repeatedly. See usage example in {@link
193    * #propagateIfPossible(Throwable, Class)}.
194    *
195    * @param throwable the Throwable to possibly propagate
196    * @param declaredType1 any checked exception type declared by the calling method
197    * @param declaredType2 any other checked exception type declared by the calling method
198    */
199   @GwtIncompatible // propagateIfInstanceOf
200   public static <X1 extends Throwable, X2 extends Throwable> void propagateIfPossible(
201       @Nullable Throwable throwable, Class<X1> declaredType1, Class<X2> declaredType2)
202       throws X1, X2 {
203     checkNotNull(declaredType2);
204     propagateIfInstanceOf(throwable, declaredType1);
205     propagateIfPossible(throwable, declaredType2);
206   }
207 
208   /**
209    * Propagates {@code throwable} as-is if it is an instance of {@link RuntimeException} or {@link
210    * Error}, or else as a last resort, wraps it in a {@code RuntimeException} and then propagates.
211    *
212    * <p>This method always throws an exception. The {@code RuntimeException} return type allows
213    * client code to signal to the compiler that statements after the call are unreachable. Example
214    * usage:
215    *
216    * <pre>
217    * T doSomething() {
218    *   try {
219    *     return someMethodThatCouldThrowAnything();
220    *   } catch (IKnowWhatToDoWithThisException e) {
221    *     return handle(e);
222    *   } catch (Throwable t) {
223    *     throw Throwables.propagate(t);
224    *   }
225    * }
226    * </pre>
227    *
228    * @param throwable the Throwable to propagate
229    * @return nothing will ever be returned; this return type is only for your convenience, as
230    *     illustrated in the example above
231    * @deprecated Use {@code throw e} or {@code throw new RuntimeException(e)} directly, or use a
232    *     combination of {@link #throwIfUnchecked} and {@code throw new RuntimeException(e)}. For
233    *     background on the deprecation, read <a href="https://goo.gl/Ivn2kc">Why we deprecated
234    *     {@code Throwables.propagate}</a>.
235    */
236   @CanIgnoreReturnValue
237   @GwtIncompatible
238   @Deprecated
239   public static RuntimeException propagate(Throwable throwable) {
240     throwIfUnchecked(throwable);
241     throw new RuntimeException(throwable);
242   }
243 
244   /**
245    * Returns the innermost cause of {@code throwable}. The first throwable in a chain provides
246    * context from when the error or exception was initially detected. Example usage:
247    *
248    * <pre>
249    * assertEquals("Unable to assign a customer id", Throwables.getRootCause(e).getMessage());
250    * </pre>
251    *
252    * @throws IllegalArgumentException if there is a loop in the causal chain
253    */
254   public static Throwable getRootCause(Throwable throwable) {
255     // Keep a second pointer that slowly walks the causal chain. If the fast pointer ever catches
256     // the slower pointer, then there's a loop.
257     Throwable slowPointer = throwable;
258     boolean advanceSlowPointer = false;
259 
260     Throwable cause;
261     while ((cause = throwable.getCause()) != null) {
262       throwable = cause;
263 
264       if (throwable == slowPointer) {
265         throw new IllegalArgumentException("Loop in causal chain detected.", throwable);
266       }
267       if (advanceSlowPointer) {
268         slowPointer = slowPointer.getCause();
269       }
270       advanceSlowPointer = !advanceSlowPointer; // only advance every other iteration
271     }
272     return throwable;
273   }
274 
275   /**
276    * Gets a {@code Throwable} cause chain as a list. The first entry in the list will be {@code
277    * throwable} followed by its cause hierarchy. Note that this is a snapshot of the cause chain and
278    * will not reflect any subsequent changes to the cause chain.
279    *
280    * <p>Here's an example of how it can be used to find specific types of exceptions in the cause
281    * chain:
282    *
283    * <pre>
284    * Iterables.filter(Throwables.getCausalChain(e), IOException.class));
285    * </pre>
286    *
287    * @param throwable the non-null {@code Throwable} to extract causes from
288    * @return an unmodifiable list containing the cause chain starting with {@code throwable}
289    * @throws IllegalArgumentException if there is a loop in the causal chain
290    */
291   @Beta // TODO(kevinb): decide best return type
292   public static List<Throwable> getCausalChain(Throwable throwable) {
293     checkNotNull(throwable);
294     List<Throwable> causes = new ArrayList<>(4);
295     causes.add(throwable);
296 
297     // Keep a second pointer that slowly walks the causal chain. If the fast pointer ever catches
298     // the slower pointer, then there's a loop.
299     Throwable slowPointer = throwable;
300     boolean advanceSlowPointer = false;
301 
302     Throwable cause;
303     while ((cause = throwable.getCause()) != null) {
304       throwable = cause;
305       causes.add(throwable);
306 
307       if (throwable == slowPointer) {
308         throw new IllegalArgumentException("Loop in causal chain detected.", throwable);
309       }
310       if (advanceSlowPointer) {
311         slowPointer = slowPointer.getCause();
312       }
313       advanceSlowPointer = !advanceSlowPointer; // only advance every other iteration
314     }
315     return Collections.unmodifiableList(causes);
316   }
317 
318   /**
319    * Returns {@code throwable}'s cause, cast to {@code expectedCauseType}.
320    *
321    * <p>Prefer this method instead of manually casting an exception's cause. For example, {@code
322    * (IOException) e.getCause()} throws a {@link ClassCastException} that discards the original
323    * exception {@code e} if the cause is not an {@link IOException}, but {@code
324    * Throwables.getCauseAs(e, IOException.class)} keeps {@code e} as the {@link
325    * ClassCastException}'s cause.
326    *
327    * @throws ClassCastException if the cause cannot be cast to the expected type. The {@code
328    *     ClassCastException}'s cause is {@code throwable}.
329    * @since 22.0
330    */
331   @Beta
332   @GwtIncompatible // Class.cast(Object)
333   public static <X extends Throwable> X getCauseAs(
334       Throwable throwable, Class<X> expectedCauseType) {
335     try {
336       return expectedCauseType.cast(throwable.getCause());
337     } catch (ClassCastException e) {
338       e.initCause(throwable);
339       throw e;
340     }
341   }
342 
343   /**
344    * Returns a string containing the result of {@link Throwable#toString() toString()}, followed by
345    * the full, recursive stack trace of {@code throwable}. Note that you probably should not be
346    * parsing the resulting string; if you need programmatic access to the stack frames, you can call
347    * {@link Throwable#getStackTrace()}.
348    */
349   @GwtIncompatible // java.io.PrintWriter, java.io.StringWriter
350   public static String getStackTraceAsString(Throwable throwable) {
351     StringWriter stringWriter = new StringWriter();
352     throwable.printStackTrace(new PrintWriter(stringWriter));
353     return stringWriter.toString();
354   }
355 
356   /**
357    * Returns the stack trace of {@code throwable}, possibly providing slower iteration over the full
358    * trace but faster iteration over parts of the trace. Here, "slower" and "faster" are defined in
359    * comparison to the normal way to access the stack trace, {@link Throwable#getStackTrace()
360    * throwable.getStackTrace()}. Note, however, that this method's special implementation is not
361    * available for all platforms and configurations. If that implementation is unavailable, this
362    * method falls back to {@code getStackTrace}. Callers that require the special implementation can
363    * check its availability with {@link #lazyStackTraceIsLazy()}.
364    *
365    * <p>The expected (but not guaranteed) performance of the special implementation differs from
366    * {@code getStackTrace} in one main way: The {@code lazyStackTrace} call itself returns quickly
367    * by delaying the per-stack-frame work until each element is accessed. Roughly speaking:
368    *
369    * <ul>
370    *   <li>{@code getStackTrace} takes {@code stackSize} time to return but then negligible time to
371    *       retrieve each element of the returned list.
372    *   <li>{@code lazyStackTrace} takes negligible time to return but then {@code 1/stackSize} time
373    *       to retrieve each element of the returned list (probably slightly more than {@code
374    *       1/stackSize}).
375    * </ul>
376    *
377    * <p>Note: The special implementation does not respect calls to {@link Throwable#setStackTrace
378    * throwable.setStackTrace}. Instead, it always reflects the original stack trace from the
379    * exception's creation.
380    *
381    * @since 19.0
382    */
383   // TODO(cpovirk): Say something about the possibility that List access could fail at runtime?
384   @Beta
385   @GwtIncompatible // lazyStackTraceIsLazy, jlaStackTrace
386   // TODO(cpovirk): Consider making this available under GWT (slow implementation only).
387   public static List<StackTraceElement> lazyStackTrace(Throwable throwable) {
388     return lazyStackTraceIsLazy()
389         ? jlaStackTrace(throwable)
390         : unmodifiableList(asList(throwable.getStackTrace()));
391   }
392 
393   /**
394    * Returns whether {@link #lazyStackTrace} will use the special implementation described in its
395    * documentation.
396    *
397    * @since 19.0
398    */
399   @Beta
400   @GwtIncompatible // getStackTraceElementMethod
401   public static boolean lazyStackTraceIsLazy() {
402     return getStackTraceElementMethod != null && getStackTraceDepthMethod != null;
403   }
404 
405   @GwtIncompatible // invokeAccessibleNonThrowingMethod
406   private static List<StackTraceElement> jlaStackTrace(final Throwable t) {
407     checkNotNull(t);
408     /*
409      * TODO(cpovirk): Consider optimizing iterator() to catch IOOBE instead of doing bounds checks.
410      *
411      * TODO(cpovirk): Consider the UnsignedBytes pattern if it performs faster and doesn't cause
412      * AOSP grief.
413      */
414     return new AbstractList<StackTraceElement>() {
415       @Override
416       public StackTraceElement get(int n) {
417         return (StackTraceElement)
418             invokeAccessibleNonThrowingMethod(getStackTraceElementMethod, jla, t, n);
419       }
420 
421       @Override
422       public int size() {
423         return (Integer) invokeAccessibleNonThrowingMethod(getStackTraceDepthMethod, jla, t);
424       }
425     };
426   }
427 
428   @GwtIncompatible // java.lang.reflect
429   private static Object invokeAccessibleNonThrowingMethod(
430       Method method, Object receiver, Object... params) {
431     try {
432       return method.invoke(receiver, params);
433     } catch (IllegalAccessException e) {
434       throw new RuntimeException(e);
435     } catch (InvocationTargetException e) {
436       throw propagate(e.getCause());
437     }
438   }
439 
440   /** JavaLangAccess class name to load using reflection */
441   @GwtIncompatible // not used by GWT emulation
442   private static final String JAVA_LANG_ACCESS_CLASSNAME = "sun.misc.JavaLangAccess";
443 
444   /** SharedSecrets class name to load using reflection */
445   @GwtIncompatible // not used by GWT emulation
446   @VisibleForTesting
447   static final String SHARED_SECRETS_CLASSNAME = "sun.misc.SharedSecrets";
448 
449   /** Access to some fancy internal JVM internals. */
450   @GwtIncompatible // java.lang.reflect
451   @Nullable
452   private static final Object jla = getJLA();
453 
454   /**
455    * The "getStackTraceElementMethod" method, only available on some JDKs so we use reflection to
456    * find it when available. When this is null, use the slow way.
457    */
458   @GwtIncompatible // java.lang.reflect
459   @Nullable
460   private static final Method getStackTraceElementMethod = (jla == null) ? null : getGetMethod();
461 
462   /**
463    * The "getStackTraceDepth" method, only available on some JDKs so we use reflection to find it
464    * when available. When this is null, use the slow way.
465    */
466   @GwtIncompatible // java.lang.reflect
467   @Nullable
468   private static final Method getStackTraceDepthMethod = (jla == null) ? null : getSizeMethod();
469 
470   /**
471    * Returns the JavaLangAccess class that is present in all Sun JDKs. It is not whitelisted for
472    * AppEngine, and not present in non-Sun JDKs.
473    */
474   @GwtIncompatible // java.lang.reflect
475   @Nullable
476   private static Object getJLA() {
477     try {
478       /*
479        * We load sun.misc.* classes using reflection since Android doesn't support these classes and
480        * would result in compilation failure if we directly refer to these classes.
481        */
482       Class<?> sharedSecrets = Class.forName(SHARED_SECRETS_CLASSNAME, false, null);
483       Method langAccess = sharedSecrets.getMethod("getJavaLangAccess");
484       return langAccess.invoke(null);
485     } catch (ThreadDeath death) {
486       throw death;
487     } catch (Throwable t) {
488       /*
489        * This is not one of AppEngine's whitelisted classes, so even in Sun JDKs, this can fail with
490        * a NoClassDefFoundError. Other apps might deny access to sun.misc packages.
491        */
492       return null;
493     }
494   }
495 
496   /**
497    * Returns the Method that can be used to resolve an individual StackTraceElement, or null if that
498    * method cannot be found (it is only to be found in fairly recent JDKs).
499    */
500   @GwtIncompatible // java.lang.reflect
501   @Nullable
502   private static Method getGetMethod() {
503     return getJlaMethod("getStackTraceElement", Throwable.class, int.class);
504   }
505 
506   /**
507    * Returns the Method that can be used to return the size of a stack, or null if that method
508    * cannot be found (it is only to be found in fairly recent JDKs). Tries to test method {@link
509    * sun.misc.JavaLangAccess#getStackTraceDepth(Throwable)} getStackTraceDepth} prior to return it
510    * (might fail some JDKs).
511    *
512    * <p>See <a href="https://github.com/google/guava/issues/2887">Throwables#lazyStackTrace throws
513    * UnsupportedOperationException</a>.
514    */
515   @GwtIncompatible // java.lang.reflect
516   @Nullable
517   private static Method getSizeMethod() {
518     try {
519       Method getStackTraceDepth = getJlaMethod("getStackTraceDepth", Throwable.class);
520       if (getStackTraceDepth == null) {
521         return null;
522       }
523       getStackTraceDepth.invoke(getJLA(), new Throwable());
524       return getStackTraceDepth;
525     } catch (UnsupportedOperationException | IllegalAccessException | InvocationTargetException e) {
526       return null;
527     }
528   }
529 
530   @GwtIncompatible // java.lang.reflect
531   @Nullable
532   private static Method getJlaMethod(String name, Class<?>... parameterTypes) throws ThreadDeath {
533     try {
534       return Class.forName(JAVA_LANG_ACCESS_CLASSNAME, false, null).getMethod(name, parameterTypes);
535     } catch (ThreadDeath death) {
536       throw death;
537     } catch (Throwable t) {
538       /*
539        * Either the JavaLangAccess class itself is not found, or the method is not supported on the
540        * JVM.
541        */
542       return null;
543     }
544   }
545 }