guava/src/com/google/common/base/Throwables.java
@Beta
  @GwtIncompatible // Class.cast(Object)
  public static <X extends Throwable> X getCauseAs(
      Throwable throwable, Class<X> expectedCauseType) {
    try {
      return expectedCauseType.cast(throwable.getCause());
    } catch (ClassCastException e) {
      e.initCause(throwable);
      throw e;
    }
  }
@Beta
  @GwtIncompatible // Class.cast(Object)
  public static <X extends Throwable> X getCauseAs(
      Throwable throwable, Class<X> expectedCauseType) {
    try {
      return expectedCauseType.cast(throwable.getCause());
    } catch (ClassCastException e) {
      e.initCause(throwable);
      throw e;
    }
  }
Returns {@code throwable}'s cause, cast to {@code expectedCauseType}.

<p>Prefer this method instead of manually casting an exception's cause. For example, {@code
(IOException) e.getCause()} throws a {@link ClassCastException} that discards the original
exception {@code e} if the cause is not an {@link IOException}, but {@code
Throwables.getCauseAs(e, IOException.class)} keeps {@code e} as the {@link
ClassCastException}'s cause.

@throws ClassCastException if the cause cannot be cast to the expected type. The {@code
ClassCastException}'s cause is {@code throwable}.
@since 22.0