DefaultRetryable implements Retryable<T> { public <X extends Throwable> T executeWithCheckedException(RetryExecutor executor, Class<X> propagateAsIsException) throws X { if (executor == null) { try { return this.call(); } catch (Exception e) { if (e instanceof RuntimeException) { throw (RuntimeException) e; } throw new RuntimeException(e); } } try { return executor.runInterruptible(this); } catch (RetryGiveupException e) { final Exception cause = e.getCause(); if (cause != null) { if (propagateAsIsException.isInstance(cause)) { throw propagateAsIsException.cast(cause); } } if (cause instanceof RuntimeException) { throw (RuntimeException) cause; } throw new RuntimeException(cause); } catch (InterruptedException e) { throw new RuntimeException(e); } } DefaultRetryable(String operationName);  DefaultRetryable(String operationName, Callable<T> callable);  DefaultRetryable();  DefaultRetryable(Callable<T> callable); @Override T call(); @Override boolean isRetryableException(Exception exception); @Override void onRetry(Exception exception, int retryCount, int retryLimit, int retryWait); @Override void onGiveup(Exception firstException, Exception lastException); T executeWith(RetryExecutor executor); T executeWithCheckedException(RetryExecutor executor,
                                                               Class<X> propagateAsIsException);  }
@Test(expected = IOException.class) public void executeAndPropagateAsIs_should_leave_original_exception_unwrapped() throws IOException { RetryExecutor retryExc = retryExecutorBuilder().withRetryLimit(3).build(); new DefaultRetryable<Object>() { @Override public Object call() throws IOException { throw new IOException(); } }.executeWithCheckedException(retryExc, IOException.class); }