From 5fc484df58fdb0ebb8cd5c8711592207fc67acaa Mon Sep 17 00:00:00 2001 From: Dave Syer Date: Thu, 24 Apr 2014 12:10:40 +0100 Subject: [PATCH] Parameterize exception type in RetryCallback So RetryCallback and the E parameter appears in RetryOperations too, making it possible to call it with an unchecked exception type in the parameter and not catch exceptions. Users should beware: it's just syntactic sugar, and the actual runtime type of the exception is never checked at runtime. So, for instance, declaring a RetryCallback doesn't mean that other Exceptions won't be retried, just that you won't be able to explicitly throw them if they are checked. A project using Spring Batch 2.2 was used to test that this works with user code that uses a library compiled agains Spring Retry 1.0. Fixes gh-6 --- .../springframework/retry/RetryCallback.java | 4 +- .../springframework/retry/RetryListener.java | 6 +- .../retry/RetryOperations.java | 10 +- .../RetryOperationsInterceptor.java | 2 +- .../StatefulRetryOperationsInterceptor.java | 2 +- .../retry/listener/RetryListenerSupport.java | 6 +- .../retry/support/RetrySimulator.java | 2 +- .../retry/support/RetryTemplate.java | 52 +++++--- .../retry/listener/RetryListenerTests.java | 26 ++-- .../FatalExceptionRetryPolicyTests.java | 2 +- .../policy/StatefulRetryIntegrationTests.java | 4 +- .../RetrySynchronizationManagerTests.java | 2 +- .../retry/support/RetryTemplateTests.java | 124 +++++++++++------- .../support/StatefulRecoveryRetryTests.java | 12 +- 14 files changed, 149 insertions(+), 105 deletions(-) diff --git a/src/main/java/org/springframework/retry/RetryCallback.java b/src/main/java/org/springframework/retry/RetryCallback.java index b21ca2f..5926d58 100644 --- a/src/main/java/org/springframework/retry/RetryCallback.java +++ b/src/main/java/org/springframework/retry/RetryCallback.java @@ -23,7 +23,7 @@ package org.springframework.retry; * @author Rob Harrop * @author Dave Syer */ -public interface RetryCallback { +public interface RetryCallback { /** * Execute an operation with retry semantics. Operations should generally be @@ -33,5 +33,5 @@ public interface RetryCallback { * @return the result of the successful operation. * @throws Exception if processing fails */ - T doWithRetry(RetryContext context) throws Throwable; + T doWithRetry(RetryContext context) throws E; } diff --git a/src/main/java/org/springframework/retry/RetryListener.java b/src/main/java/org/springframework/retry/RetryListener.java index 1541fcf..c649bb8 100644 --- a/src/main/java/org/springframework/retry/RetryListener.java +++ b/src/main/java/org/springframework/retry/RetryListener.java @@ -38,7 +38,7 @@ public interface RetryListener { * @param callback the current {@link RetryCallback}. * @return true if the retry should proceed. */ - boolean open(RetryContext context, RetryCallback callback); + boolean open(RetryContext context, RetryCallback callback); /** * Called after the final attempt (successful or not). Allow the interceptor @@ -49,7 +49,7 @@ public interface RetryListener { * @param callback the current {@link RetryCallback}. * @param throwable the last exception that was thrown by the callback. */ - void close(RetryContext context, RetryCallback callback, Throwable throwable); + void close(RetryContext context, RetryCallback callback, Throwable throwable); /** * Called after every unsuccessful attempt at a retry. @@ -58,5 +58,5 @@ public interface RetryListener { * @param callback the current {@link RetryCallback}. * @param throwable the last exception that was thrown by the callback. */ - void onError(RetryContext context, RetryCallback callback, Throwable throwable); + void onError(RetryContext context, RetryCallback callback, Throwable throwable); } diff --git a/src/main/java/org/springframework/retry/RetryOperations.java b/src/main/java/org/springframework/retry/RetryOperations.java index dd2bc04..745b371 100644 --- a/src/main/java/org/springframework/retry/RetryOperations.java +++ b/src/main/java/org/springframework/retry/RetryOperations.java @@ -37,7 +37,7 @@ public interface RetryOperations { * {@link RetryCallback} upon unsuccessful retry. * @throws Throwable */ - T execute(RetryCallback retryCallback) throws Throwable; + T execute(RetryCallback retryCallback) throws E; /** * Execute the supplied {@link RetryCallback} with a fallback on exhausted @@ -49,7 +49,7 @@ public interface RetryOperations { * @throws Exception any {@link Exception} raised by the * {@link RecoveryCallback} upon unsuccessful retry. */ - T execute(RetryCallback retryCallback, RecoveryCallback recoveryCallback) throws Throwable; + T execute(RetryCallback retryCallback, RecoveryCallback recoveryCallback) throws E; /** * A simple stateful retry. Execute the supplied {@link RetryCallback} with @@ -69,7 +69,7 @@ public interface RetryOperations { * @throws ExhaustedRetryException if the last attempt for this state has * already been reached */ - T execute(RetryCallback retryCallback, RetryState retryState) throws Throwable, ExhaustedRetryException; + T execute(RetryCallback retryCallback, RetryState retryState) throws E, ExhaustedRetryException; /** * A stateful retry with a recovery path. Execute the supplied @@ -84,7 +84,7 @@ public interface RetryOperations { * @throws Exception any {@link Exception} raised by the * {@link RecoveryCallback} upon unsuccessful retry. */ - T execute(RetryCallback retryCallback, RecoveryCallback recoveryCallback, RetryState retryState) - throws Throwable; + T execute(RetryCallback retryCallback, RecoveryCallback recoveryCallback, RetryState retryState) + throws E; } diff --git a/src/main/java/org/springframework/retry/interceptor/RetryOperationsInterceptor.java b/src/main/java/org/springframework/retry/interceptor/RetryOperationsInterceptor.java index a7db158..43e570d 100644 --- a/src/main/java/org/springframework/retry/interceptor/RetryOperationsInterceptor.java +++ b/src/main/java/org/springframework/retry/interceptor/RetryOperationsInterceptor.java @@ -57,7 +57,7 @@ public class RetryOperationsInterceptor implements MethodInterceptor { public Object invoke(final MethodInvocation invocation) throws Throwable { - RetryCallback retryCallback = new RetryCallback() { + RetryCallback retryCallback = new RetryCallback() { public Object doWithRetry(RetryContext context) throws Exception { diff --git a/src/main/java/org/springframework/retry/interceptor/StatefulRetryOperationsInterceptor.java b/src/main/java/org/springframework/retry/interceptor/StatefulRetryOperationsInterceptor.java index e896686..50754f8 100644 --- a/src/main/java/org/springframework/retry/interceptor/StatefulRetryOperationsInterceptor.java +++ b/src/main/java/org/springframework/retry/interceptor/StatefulRetryOperationsInterceptor.java @@ -156,7 +156,7 @@ public class StatefulRetryOperationsInterceptor implements MethodInterceptor { * */ private static final class MethodInvocationRetryCallback implements - RetryCallback { + RetryCallback { /** * */ diff --git a/src/main/java/org/springframework/retry/listener/RetryListenerSupport.java b/src/main/java/org/springframework/retry/listener/RetryListenerSupport.java index fbc542b..96e866c 100644 --- a/src/main/java/org/springframework/retry/listener/RetryListenerSupport.java +++ b/src/main/java/org/springframework/retry/listener/RetryListenerSupport.java @@ -28,13 +28,13 @@ import org.springframework.retry.RetryListener; */ public class RetryListenerSupport implements RetryListener { - public void close(RetryContext context, RetryCallback callback, Throwable throwable) { + public void close(RetryContext context, RetryCallback callback, Throwable throwable) { } - public void onError(RetryContext context, RetryCallback callback, Throwable throwable) { + public void onError(RetryContext context, RetryCallback callback, Throwable throwable) { } - public boolean open(RetryContext context, RetryCallback callback) { + public boolean open(RetryContext context, RetryCallback callback) { return true; } diff --git a/src/main/java/org/springframework/retry/support/RetrySimulator.java b/src/main/java/org/springframework/retry/support/RetrySimulator.java index 31f84b8..fe6a1dd 100644 --- a/src/main/java/org/springframework/retry/support/RetrySimulator.java +++ b/src/main/java/org/springframework/retry/support/RetrySimulator.java @@ -96,7 +96,7 @@ public class RetrySimulator { return stealingSleeper.getSleeps(); } - static class FailingRetryCallback implements RetryCallback { + static class FailingRetryCallback implements RetryCallback { public Object doWithRetry(RetryContext context) throws Exception { throw new FailingRetryException(); } diff --git a/src/main/java/org/springframework/retry/support/RetryTemplate.java b/src/main/java/org/springframework/retry/support/RetryTemplate.java index a163225..5c1ee08 100644 --- a/src/main/java/org/springframework/retry/support/RetryTemplate.java +++ b/src/main/java/org/springframework/retry/support/RetryTemplate.java @@ -150,7 +150,7 @@ public class RetryTemplate implements RetryOperations { * @throws TerminatedRetryException if the retry has been manually terminated by a * listener. */ - public final T execute(RetryCallback retryCallback) throws Throwable { + public final T execute(RetryCallback retryCallback) throws E { return doExecute(retryCallback, null, null); } @@ -163,8 +163,8 @@ public class RetryTemplate implements RetryOperations { * @throws TerminatedRetryException if the retry has been manually terminated by a * listener. */ - public final T execute(RetryCallback retryCallback, - RecoveryCallback recoveryCallback) throws Throwable { + public final T execute(RetryCallback retryCallback, + RecoveryCallback recoveryCallback) throws E { return doExecute(retryCallback, recoveryCallback, null); } @@ -176,8 +176,8 @@ public class RetryTemplate implements RetryOperations { * * @throws ExhaustedRetryException if the retry has been exhausted. */ - public final T execute(RetryCallback retryCallback, RetryState retryState) - throws Throwable, ExhaustedRetryException { + public final T execute(RetryCallback retryCallback, RetryState retryState) + throws E, ExhaustedRetryException { return doExecute(retryCallback, null, retryState); } @@ -187,9 +187,9 @@ public class RetryTemplate implements RetryOperations { * * @see RetryOperations#execute(RetryCallback, RetryState) */ - public final T execute(RetryCallback retryCallback, + public final T execute(RetryCallback retryCallback, RecoveryCallback recoveryCallback, RetryState retryState) - throws Throwable, ExhaustedRetryException { + throws E, ExhaustedRetryException { return doExecute(retryCallback, recoveryCallback, retryState); } @@ -198,10 +198,11 @@ public class RetryTemplate implements RetryOperations { * recovery callback. * * @see RetryOperations#execute(RetryCallback, RecoveryCallback, RetryState) - * @throws ExhaustedRetryException if the retry has been exhausted. + * @throws ExhaustedRetryException if the retry has been exhausted. finally { + */ - protected T doExecute(RetryCallback retryCallback, - RecoveryCallback recoveryCallback, RetryState state) throws Throwable, + protected T doExecute(RetryCallback retryCallback, + RecoveryCallback recoveryCallback, RetryState state) throws E, ExhaustedRetryException { RetryPolicy retryPolicy = this.retryPolicy; @@ -290,7 +291,9 @@ public class RetryTemplate implements RetryOperations { if (shouldRethrow(retryPolicy, context, state)) { logger.debug("Rethrow in retry for policy: count=" + context.getRetryCount()); - throw wrapIfNecessary(e); + @SuppressWarnings("unchecked") + E rethrow = (E) wrapIfNecessary(e); + throw rethrow; } } @@ -311,7 +314,12 @@ public class RetryTemplate implements RetryOperations { return handleRetryExhausted(recoveryCallback, context, state); - } finally { + } catch (Throwable e) { + @SuppressWarnings("unchecked") + E rethrow = (E) wrapIfNecessary(e); + throw rethrow; + } + finally { close(retryPolicy, context, state, lastException == null); doCloseInterceptors(retryCallback, context, lastException); RetrySynchronizationManager.clear(); @@ -451,9 +459,11 @@ public class RetryTemplate implements RetryOperations { throw wrapIfNecessary(context.getLastThrowable()); } - protected void rethrow(RetryContext context, String message) throws Throwable { + protected void rethrow(RetryContext context, String message) throws E { if (throwLastExceptionOnExhausted) { - throw (Throwable) context.getLastThrowable(); + @SuppressWarnings("unchecked") + E rethrow = (E) context.getLastThrowable(); + throw rethrow; } else { throw new ExhaustedRetryException(message, context.getLastThrowable()); } @@ -478,7 +488,7 @@ public class RetryTemplate implements RetryOperations { } } - private boolean doOpenInterceptors(RetryCallback callback, RetryContext context) { + private boolean doOpenInterceptors(RetryCallback callback, RetryContext context) { boolean result = true; @@ -490,14 +500,14 @@ public class RetryTemplate implements RetryOperations { } - private void doCloseInterceptors(RetryCallback callback, RetryContext context, + private void doCloseInterceptors(RetryCallback callback, RetryContext context, Throwable lastException) { for (int i = listeners.length; i-- > 0;) { listeners[i].close(context, callback, lastException); } } - private void doOnErrorInterceptors(RetryCallback callback, + private void doOnErrorInterceptors(RetryCallback callback, RetryContext context, Throwable throwable) { for (int i = listeners.length; i-- > 0;) { listeners[i].onError(context, callback, throwable); @@ -508,13 +518,15 @@ public class RetryTemplate implements RetryOperations { * Re-throws the original throwable if it is unchecked, wraps checked exceptions into * {@link RetryException}. */ - private static Exception wrapIfNecessary(Throwable throwable) { + private static E wrapIfNecessary(Throwable throwable) throws RetryException { if (throwable instanceof Error) { throw (Error) throwable; } else if (throwable instanceof Exception) { - return (Exception) throwable; + @SuppressWarnings("unchecked") + E rethrow = (E) throwable; + return rethrow; } else { - return new RetryException("Exception in batch process", throwable); + throw new RetryException("Exception in batch process", throwable); } } diff --git a/src/test/java/org/springframework/retry/listener/RetryListenerTests.java b/src/test/java/org/springframework/retry/listener/RetryListenerTests.java index 876e4e1..5e5f230 100644 --- a/src/test/java/org/springframework/retry/listener/RetryListenerTests.java +++ b/src/test/java/org/springframework/retry/listener/RetryListenerTests.java @@ -42,19 +42,19 @@ public class RetryListenerTests { @Test public void testOpenInterceptors() throws Throwable { template.setListeners(new RetryListener[] { new RetryListenerSupport() { - public boolean open(RetryContext context, RetryCallback callback) { + public boolean open(RetryContext context, RetryCallback callback) { count++; list.add("1:" + count); return true; } }, new RetryListenerSupport() { - public boolean open(RetryContext context, RetryCallback callback) { + public boolean open(RetryContext context, RetryCallback callback) { count++; list.add("2:" + count); return true; } } }); - template.execute(new RetryCallback() { + template.execute(new RetryCallback() { public String doWithRetry(RetryContext context) throws Exception { return null; } @@ -67,13 +67,13 @@ public class RetryListenerTests { @Test public void testOpenCanVetoRetry() throws Throwable { template.registerListener(new RetryListenerSupport() { - public boolean open(RetryContext context, RetryCallback callback) { + public boolean open(RetryContext context, RetryCallback callback) { list.add("1"); return false; } }); try { - template.execute(new RetryCallback() { + template.execute(new RetryCallback() { public String doWithRetry(RetryContext context) throws Exception { count++; return null; @@ -92,17 +92,17 @@ public class RetryListenerTests { @Test public void testCloseInterceptors() throws Throwable { template.setListeners(new RetryListener[] { new RetryListenerSupport() { - public void close(RetryContext context, RetryCallback callback, Throwable t) { + public void close(RetryContext context, RetryCallback callback, Throwable t) { count++; list.add("1:" + count); } }, new RetryListenerSupport() { - public void close(RetryContext context, RetryCallback callback, Throwable t) { + public void close(RetryContext context, RetryCallback callback, Throwable t) { count++; list.add("2:" + count); } } }); - template.execute(new RetryCallback() { + template.execute(new RetryCallback() { public String doWithRetry(RetryContext context) throws Exception { return null; } @@ -117,16 +117,16 @@ public class RetryListenerTests { public void testOnError() throws Throwable { template.setRetryPolicy(new NeverRetryPolicy()); template.setListeners(new RetryListener[] { new RetryListenerSupport() { - public void onError(RetryContext context, RetryCallback callback, Throwable throwable) { + public void onError(RetryContext context, RetryCallback callback, Throwable throwable) { list.add("1"); } }, new RetryListenerSupport() { - public void onError(RetryContext context, RetryCallback callback, Throwable throwable) { + public void onError(RetryContext context, RetryCallback callback, Throwable throwable) { list.add("2"); } } }); try { - template.execute(new RetryCallback() { + template.execute(new RetryCallback() { public String doWithRetry(RetryContext context) throws Exception { count++; throw new IllegalStateException("foo"); @@ -148,13 +148,13 @@ public class RetryListenerTests { @Test public void testCloseInterceptorsAfterRetry() throws Throwable { template.registerListener(new RetryListenerSupport() { - public void close(RetryContext context, RetryCallback callback, Throwable t) { + public void close(RetryContext context, RetryCallback callback, Throwable t) { list.add("" + count); // The last attempt should have been successful: assertNull(t); } }); - template.execute(new RetryCallback() { + template.execute(new RetryCallback() { public String doWithRetry(RetryContext context) throws Exception { if (count++ < 1) throw new RuntimeException("Retry!"); diff --git a/src/test/java/org/springframework/retry/policy/FatalExceptionRetryPolicyTests.java b/src/test/java/org/springframework/retry/policy/FatalExceptionRetryPolicyTests.java index 3f92fdf..ae5b5a3 100644 --- a/src/test/java/org/springframework/retry/policy/FatalExceptionRetryPolicyTests.java +++ b/src/test/java/org/springframework/retry/policy/FatalExceptionRetryPolicyTests.java @@ -100,7 +100,7 @@ public class FatalExceptionRetryPolicyTests { assertEquals("bar", result); } - private static class MockRetryCallback implements RetryCallback { + private static class MockRetryCallback implements RetryCallback { private int attempts; diff --git a/src/test/java/org/springframework/retry/policy/StatefulRetryIntegrationTests.java b/src/test/java/org/springframework/retry/policy/StatefulRetryIntegrationTests.java index 42a135a..deda94b 100644 --- a/src/test/java/org/springframework/retry/policy/StatefulRetryIntegrationTests.java +++ b/src/test/java/org/springframework/retry/policy/StatefulRetryIntegrationTests.java @@ -130,7 +130,7 @@ public class StatefulRetryIntegrationTests { RetryState retryState = new DefaultRetryState("bar"); for (int i = 0; i < 3; i++) { try { - template.execute(new RetryCallback() { + template.execute(new RetryCallback() { public String doWithRetry(RetryContext context) throws Exception { times.add(System.currentTimeMillis()); throw new Exception("Fail"); @@ -155,7 +155,7 @@ public class StatefulRetryIntegrationTests { * @author Dave Syer * */ - private static final class MockRetryCallback implements RetryCallback { + private static final class MockRetryCallback implements RetryCallback { int attempts = 0; public String doWithRetry(RetryContext context) throws Exception { diff --git a/src/test/java/org/springframework/retry/support/RetrySynchronizationManagerTests.java b/src/test/java/org/springframework/retry/support/RetrySynchronizationManagerTests.java index 1b33597..4d7f543 100644 --- a/src/test/java/org/springframework/retry/support/RetrySynchronizationManagerTests.java +++ b/src/test/java/org/springframework/retry/support/RetrySynchronizationManagerTests.java @@ -47,7 +47,7 @@ public class RetrySynchronizationManagerTests { RetryContext status = RetrySynchronizationManager.getContext(); assertNull(status); - template.execute(new RetryCallback() { + template.execute(new RetryCallback() { public Object doWithRetry(RetryContext status) throws Exception { RetryContext global = RetrySynchronizationManager.getContext(); assertNotNull(status); diff --git a/src/test/java/org/springframework/retry/support/RetryTemplateTests.java b/src/test/java/org/springframework/retry/support/RetryTemplateTests.java index 0a5ae49..6a31af2 100644 --- a/src/test/java/org/springframework/retry/support/RetryTemplateTests.java +++ b/src/test/java/org/springframework/retry/support/RetryTemplateTests.java @@ -28,6 +28,7 @@ import static org.junit.Assert.assertSame; import static org.junit.Assert.fail; import java.util.Collections; +import java.util.concurrent.atomic.AtomicInteger; import org.junit.Test; import org.springframework.classify.BinaryExceptionClassifier; @@ -60,19 +61,48 @@ public class RetryTemplateTests { callback.setAttemptsBeforeSuccess(x); RetryTemplate retryTemplate = new RetryTemplate(); retryTemplate.setRetryPolicy(new SimpleRetryPolicy(x, Collections - ., Boolean> singletonMap(Exception.class, true))); + ., Boolean> singletonMap(Exception.class, + true))); retryTemplate.execute(callback); assertEquals(x, callback.attempts); } } + @Test + public void testSpecificExceptionRetry() throws Throwable { + for (int x = 1; x <= 10; x++) { + final int attemptsBeforeSuccess = x; + final AtomicInteger attempts = new AtomicInteger(0); + RetryCallback callback = new RetryCallback() { + @Override + public String doWithRetry(RetryContext context) + throws IllegalStateException { + if (attempts.incrementAndGet() < attemptsBeforeSuccess) { + // The parametrized exception type in the callback is really just + // syntactic sugar since rules of erasure mean that the handler + // can't really tell the difference between runtime exceptions. + throw new IllegalArgumentException("Planned"); + } + return "foo"; + } + }; + RetryTemplate retryTemplate = new RetryTemplate(); + retryTemplate.setRetryPolicy(new SimpleRetryPolicy(x, Collections + ., Boolean> singletonMap(Exception.class, + true))); + retryTemplate.execute(callback); + assertEquals(x, attempts.get()); + } + } + @Test public void testSuccessfulRecovery() throws Throwable { MockRetryCallback callback = new MockRetryCallback(); callback.setAttemptsBeforeSuccess(3); RetryTemplate retryTemplate = new RetryTemplate(); - retryTemplate.setRetryPolicy(new SimpleRetryPolicy(2, Collections - ., Boolean> singletonMap(Exception.class, true))); + retryTemplate.setRetryPolicy(new SimpleRetryPolicy(2, + Collections., Boolean> singletonMap( + Exception.class, true))); final Object value = new Object(); Object result = retryTemplate.execute(callback, new RecoveryCallback() { public Object recover(RetryContext context) throws Exception { @@ -100,13 +130,13 @@ public class RetryTemplateTests { callback.setAttemptsBeforeSuccess(Integer.MAX_VALUE); RetryTemplate retryTemplate = new RetryTemplate(); int retryAttempts = 2; - retryTemplate.setRetryPolicy(new SimpleRetryPolicy(retryAttempts, Collections - ., Boolean> singletonMap(Exception.class, true))); + retryTemplate.setRetryPolicy(new SimpleRetryPolicy(retryAttempts, + Collections., Boolean> singletonMap( + Exception.class, true))); try { retryTemplate.execute(callback); fail("Expected IllegalArgumentException"); - } - catch (IllegalArgumentException e) { + } catch (IllegalArgumentException e) { assertNotNull(e); assertEquals(retryAttempts, callback.attempts); return; @@ -122,8 +152,9 @@ public class RetryTemplateTests { callback.setExceptionToThrow(new IllegalArgumentException()); RetryTemplate retryTemplate = new RetryTemplate(); - retryTemplate.setRetryPolicy(new SimpleRetryPolicy(attempts, Collections - ., Boolean> singletonMap(Exception.class, true))); + retryTemplate.setRetryPolicy(new SimpleRetryPolicy(attempts, + Collections., Boolean> singletonMap( + Exception.class, true))); retryTemplate.execute(callback); assertEquals(attempts, callback.attempts); } @@ -136,10 +167,13 @@ public class RetryTemplateTests { callback.setExceptionToThrow(new IllegalArgumentException()); RetryTemplate retryTemplate = new RetryTemplate(); - retryTemplate.setRetryPolicy(new SimpleRetryPolicy(attempts, Collections - ., Boolean> singletonMap(Exception.class, true))); - BinaryExceptionClassifier classifier = new BinaryExceptionClassifier(Collections - .> singleton(IllegalArgumentException.class), false); + retryTemplate.setRetryPolicy(new SimpleRetryPolicy(attempts, + Collections., Boolean> singletonMap( + Exception.class, true))); + BinaryExceptionClassifier classifier = new BinaryExceptionClassifier( + Collections + .> singleton(IllegalArgumentException.class), + false); retryTemplate.execute(callback, new DefaultRetryState("foo", classifier)); assertEquals(attempts, callback.attempts); } @@ -147,8 +181,9 @@ public class RetryTemplateTests { @Test public void testSetExceptions() throws Throwable { RetryTemplate template = new RetryTemplate(); - SimpleRetryPolicy policy = new SimpleRetryPolicy(3, Collections - ., Boolean> singletonMap(RuntimeException.class, true)); + SimpleRetryPolicy policy = new SimpleRetryPolicy(3, + Collections., Boolean> singletonMap( + RuntimeException.class, true)); template.setRetryPolicy(policy); int attempts = 3; @@ -158,8 +193,7 @@ public class RetryTemplateTests { try { template.execute(callback); - } - catch (Exception e) { + } catch (Exception e) { assertNotNull(e); assertEquals(1, callback.attempts); } @@ -178,7 +212,8 @@ public class RetryTemplateTests { RetryTemplate retryTemplate = new RetryTemplate(); retryTemplate.setBackOffPolicy(backOff); retryTemplate.setRetryPolicy(new SimpleRetryPolicy(x, Collections - ., Boolean> singletonMap(Exception.class, true))); + ., Boolean> singletonMap(Exception.class, + true))); retryTemplate.execute(callback); assertEquals(x, callback.attempts); assertEquals(1, backOff.startCalls); @@ -190,15 +225,14 @@ public class RetryTemplateTests { public void testEarlyTermination() throws Throwable { try { RetryTemplate retryTemplate = new RetryTemplate(); - retryTemplate.execute(new RetryCallback() { + retryTemplate.execute(new RetryCallback() { public Object doWithRetry(RetryContext status) throws Exception { status.setExhaustedOnly(); throw new IllegalStateException("Retry this operation"); } }); fail("Expected ExhaustedRetryException"); - } - catch (ExhaustedRetryException ex) { + } catch (ExhaustedRetryException ex) { // Expected for internal retry policy (external would recover // gracefully) assertEquals("Retry this operation", ex.getCause().getMessage()); @@ -210,15 +244,14 @@ public class RetryTemplateTests { try { RetryTemplate retryTemplate = new RetryTemplate(); retryTemplate.setThrowLastExceptionOnExhausted(true); - retryTemplate.execute(new RetryCallback() { + retryTemplate.execute(new RetryCallback() { public Object doWithRetry(RetryContext status) throws Exception { status.setExhaustedOnly(); throw new IllegalStateException("Retry this operation"); } }); fail("Expected ExhaustedRetryException"); - } - catch (IllegalStateException ex) { + } catch (IllegalStateException ex) { // Expected for internal retry policy (external would recover // gracefully) assertEquals("Retry this operation", ex.getMessage()); @@ -229,21 +262,23 @@ public class RetryTemplateTests { public void testNestedContexts() throws Throwable { RetryTemplate outer = new RetryTemplate(); final RetryTemplate inner = new RetryTemplate(); - outer.execute(new RetryCallback() { + outer.execute(new RetryCallback() { public Object doWithRetry(RetryContext status) throws Throwable { context = status; count++; - Object result = inner.execute(new RetryCallback() { + Object result = inner.execute(new RetryCallback() { public Object doWithRetry(RetryContext status) throws Throwable { count++; assertNotNull(context); assertNotSame(status, context); assertSame(context, status.getParent()); - assertSame("The context should be the child", status, RetrySynchronizationManager.getContext()); + assertSame("The context should be the child", status, + RetrySynchronizationManager.getContext()); return null; } }); - assertSame("The context should be restored", status, RetrySynchronizationManager.getContext()); + assertSame("The context should be restored", status, + RetrySynchronizationManager.getContext()); return result; } }); @@ -255,14 +290,13 @@ public class RetryTemplateTests { RetryTemplate retryTemplate = new RetryTemplate(); retryTemplate.setRetryPolicy(new NeverRetryPolicy()); try { - retryTemplate.execute(new RetryCallback() { + retryTemplate.execute(new RetryCallback() { public Object doWithRetry(RetryContext context) throws Exception { throw new Error("Realllly bad!"); } }); fail("Expected Error"); - } - catch (Error e) { + } catch (Error e) { assertEquals("Realllly bad!", e.getMessage()); } } @@ -277,14 +311,13 @@ public class RetryTemplateTests { } }); try { - retryTemplate.execute(new RetryCallback() { + retryTemplate.execute(new RetryCallback() { public Object doWithRetry(RetryContext context) throws Exception { throw new RuntimeException("Realllly bad!"); } }); fail("Expected Error"); - } - catch (TerminatedRetryException e) { + } catch (TerminatedRetryException e) { assertEquals("Planned", e.getCause().getMessage()); } } @@ -298,28 +331,27 @@ public class RetryTemplateTests { } }); try { - retryTemplate.execute(new RetryCallback() { + retryTemplate.execute(new RetryCallback() { public Object doWithRetry(RetryContext context) throws Exception { throw new RuntimeException("Bad!"); } }); fail("Expected RuntimeException"); - } - catch (BackOffInterruptedException e) { + } catch (BackOffInterruptedException e) { assertEquals("foo", e.getMessage()); } } /** - * {@link BackOffPolicy} should apply also for exceptions that are - * re-thrown. + * {@link BackOffPolicy} should apply also for exceptions that are re-thrown. */ @Test public void testNoBackOffForRethrownException() throws Throwable { RetryTemplate tested = new RetryTemplate(); - tested.setRetryPolicy(new SimpleRetryPolicy(1, Collections., Boolean> singletonMap( - Exception.class, true))); + tested.setRetryPolicy(new SimpleRetryPolicy(1, + Collections., Boolean> singletonMap( + Exception.class, true))); BackOffPolicy bop = createStrictMock(BackOffPolicy.class); BackOffContext backOffContext = new BackOffContext() { @@ -330,7 +362,7 @@ public class RetryTemplateTests { replay(bop); try { - tested.execute(new RetryCallback() { + tested.execute(new RetryCallback() { public Object doWithRetry(RetryContext context) throws Exception { throw new Exception("maybe next time!"); @@ -345,15 +377,14 @@ public class RetryTemplateTests { }); fail(); - } - catch (Exception expected) { + } catch (Exception expected) { assertEquals("maybe next time!", expected.getMessage()); } verify(bop); } - private static class MockRetryCallback implements RetryCallback { + private static class MockRetryCallback implements RetryCallback { private int attempts; @@ -389,7 +420,8 @@ public class RetryTemplateTests { return null; } - public void backOff(BackOffContext backOffContext) throws BackOffInterruptedException { + public void backOff(BackOffContext backOffContext) + throws BackOffInterruptedException { backOffCalls++; } } diff --git a/src/test/java/org/springframework/retry/support/StatefulRecoveryRetryTests.java b/src/test/java/org/springframework/retry/support/StatefulRecoveryRetryTests.java index b3b4afd..3b69616 100644 --- a/src/test/java/org/springframework/retry/support/StatefulRecoveryRetryTests.java +++ b/src/test/java/org/springframework/retry/support/StatefulRecoveryRetryTests.java @@ -86,7 +86,7 @@ public class StatefulRecoveryRetryTests { ., Boolean> singletonMap(Exception.class, true))); final String input = "foo"; RetryState state = new DefaultRetryState(input); - RetryCallback callback = new RetryCallback() { + RetryCallback callback = new RetryCallback() { public String doWithRetry(RetryContext context) throws Exception { throw new RuntimeException("Barf!"); } @@ -124,7 +124,7 @@ public class StatefulRecoveryRetryTests { assertFalse(classifier.classify(new RuntimeException())); final String input = "foo"; RetryState state = new DefaultRetryState(input, classifier); - RetryCallback callback = new RetryCallback() { + RetryCallback callback = new RetryCallback() { public String doWithRetry(RetryContext context) throws Exception { throw new RuntimeException("Barf!"); } @@ -152,7 +152,7 @@ public class StatefulRecoveryRetryTests { final String input = "foo"; RetryState state = new DefaultRetryState(input); - RetryCallback callback = new RetryCallback() { + RetryCallback callback = new RetryCallback() { public String doWithRetry(RetryContext context) throws Exception { throw new RuntimeException("Barf!"); } @@ -188,7 +188,7 @@ public class StatefulRecoveryRetryTests { final StringHolder item = new StringHolder("bar"); RetryState state = new DefaultRetryState(item); - RetryCallback callback = new RetryCallback() { + RetryCallback callback = new RetryCallback() { public StringHolder doWithRetry(RetryContext context) throws Exception { // This simulates what happens if someone uses a primary key // for hashCode and equals and then relies on default key @@ -231,7 +231,7 @@ public class StatefulRecoveryRetryTests { ., Boolean> singletonMap(Exception.class, true))); retryTemplate.setRetryContextCache(new MapRetryContextCache(1)); - RetryCallback callback = new RetryCallback() { + RetryCallback callback = new RetryCallback() { public Object doWithRetry(RetryContext context) throws Exception { count++; throw new RuntimeException("Barf!"); @@ -266,7 +266,7 @@ public class StatefulRecoveryRetryTests { final StringHolder item = new StringHolder("foo"); RetryState state = new DefaultRetryState(item); - RetryCallback callback = new RetryCallback() { + RetryCallback callback = new RetryCallback() { public Object doWithRetry(RetryContext context) throws Exception { count++; throw new RuntimeException("Barf!");