Skip to content

Commit

Permalink
Add a typed parameter for the failure in FailurePolicy.handleIf
Browse files Browse the repository at this point in the history
  • Loading branch information
jhalterman committed Aug 13, 2021
1 parent c285214 commit 052d55f
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 24 deletions.
8 changes: 5 additions & 3 deletions src/main/java/net/jodah/failsafe/Failsafe.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ public class Failsafe {
* Failsafe.with(fallback, retryPolicy, circuitBreaker).get(supplier);
* </pre>
* </p>
* This results in the following internal composition when executing the {@code supplier} and handling its result:
* This results in the following internal composition when executing a {@code runnable} or {@code supplier} and
* handling its result:
* <p>
* <pre>
* Fallback(RetryPolicy(CircuitBreaker(Supplier)))
Expand Down Expand Up @@ -65,10 +66,11 @@ public static <R, P extends Policy<R>> FailsafeExecutor<R> with(P outerPolicy, P
* the last policy being applied first. For example, consider:
* <p>
* <pre>
* Failsafe.with(fallback, retryPolicy, circuitBreaker).get(supplier);
* Failsafe.with(Arrays.asList(fallback, retryPolicy, circuitBreaker)).get(supplier);
* </pre>
* </p>
* This results in the following internal composition when executing the {@code supplier} and handling its result:
* This results in the following internal composition when executing a {@code runnable} or {@code supplier} and
* handling its result:
* <p>
* <pre>
* Fallback(RetryPolicy(CircuitBreaker(Supplier)))
Expand Down
9 changes: 6 additions & 3 deletions src/main/java/net/jodah/failsafe/FailurePolicy.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@
/**
* A Policy that captures conditions to determine whether an execution is a failure.
* <p>
* If no handlers are configured, the execution is considered a failure if an Exception was thrown.
* By default, if no handlers are configured, the execution is considered a failure if an Exception was thrown. If
* multuple handlers are configured, they are logically OR'ed.
* </p>
*
* @param <S> self type
Expand Down Expand Up @@ -84,9 +85,10 @@ public S handle(List<Class<? extends Throwable>> failures) {
/**
* Specifies that a failure has occurred if the {@code failurePredicate} matches the failure.
*
* @param <T> failure type
* @throws NullPointerException if {@code failurePredicate} is null
*/
public S handleIf(Predicate<? extends Throwable> failurePredicate) {
public <T extends Throwable> S handleIf(Predicate<T> failurePredicate) {
Assert.notNull(failurePredicate, "failurePredicate");
failuresChecked = true;
failureConditions.add(failurePredicateFor(failurePredicate));
Expand All @@ -96,10 +98,11 @@ public S handleIf(Predicate<? extends Throwable> failurePredicate) {
/**
* Specifies that a failure has occurred if the {@code resultPredicate} matches the execution result.
*
* @param <T> failure type
* @throws NullPointerException if {@code resultPredicate} is null
*/
@SuppressWarnings("unchecked")
public S handleIf(BiPredicate<R, ? extends Throwable> resultPredicate) {
public <T extends Throwable> S handleIf(BiPredicate<R, T> resultPredicate) {
Assert.notNull(resultPredicate, "resultPredicate");
failuresChecked = true;
failureConditions.add((BiPredicate<R, Throwable>) resultPredicate);
Expand Down
48 changes: 33 additions & 15 deletions src/test/java/net/jodah/failsafe/RetryPolicyTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,22 @@

@Test
public class RetryPolicyTest {
static class FooException extends Exception {
String bar;

FooException(String bar) {
this.bar = bar;
}
}

public void testIsFailureNull() {
RetryPolicy<Object> policy = new RetryPolicy<>();
assertFalse(policy.isFailure(null, null));
}

public void testIsFailureCompletionPredicate() {
RetryPolicy<Object> policy = new RetryPolicy<>()
.handleIf((result, failure) -> result == "test" || failure instanceof IllegalArgumentException);
RetryPolicy<Object> policy = new RetryPolicy<>().handleIf(
(result, failure) -> result == "test" || failure instanceof IllegalArgumentException);
assertTrue(policy.isFailure("test", null));
// No retries needed for successful result
assertFalse(policy.isFailure(0, null));
Expand All @@ -48,6 +56,12 @@ public void testIsFailureFailurePredicate() {
assertFalse(policy.isFailure(null, new IllegalStateException()));
}

public void testIsFailureTypedFailurePredicate() {
RetryPolicy<Boolean> policy = new RetryPolicy<Boolean>().<FooException>handleIf((result, failure) -> failure.bar.equals("bar"));
assertTrue(policy.isFailure(null, new FooException("bar")));
assertFalse(policy.isFailure(null, new IllegalStateException()));
}

public void testIsFailureResultPredicate() {
RetryPolicy<Integer> policy = new RetryPolicy<Integer>().handleResultIf(result -> result > 100);
assertTrue(policy.isFailure(110, null));
Expand Down Expand Up @@ -93,8 +107,8 @@ public void testIsAbortableNull() {
}

public void testIsAbortableCompletionPredicate() {
RetryPolicy<Object> policy = new RetryPolicy<>()
.abortIf((result, failure) -> result == "test" || failure instanceof IllegalArgumentException);
RetryPolicy<Object> policy = new RetryPolicy<>().abortIf(
(result, failure) -> result == "test" || failure instanceof IllegalArgumentException);
assertTrue(policy.isAbortable("test", null));
assertFalse(policy.isAbortable(0, null));
assertTrue(policy.isAbortable(null, new IllegalArgumentException()));
Expand Down Expand Up @@ -142,19 +156,23 @@ public void testIsAbortableResult() {
public void shouldRequireValidBackoff() {
Asserts.assertThrows(() -> new RetryPolicy().withBackoff(0, 0, null), NullPointerException.class);
Asserts.assertThrows(
() -> new RetryPolicy().withMaxDuration(Duration.ofMillis(1)).withBackoff(100, 120, ChronoUnit.MILLIS),
IllegalStateException.class);
Asserts.assertThrows(() -> new RetryPolicy().withBackoff(-3, 10, ChronoUnit.MILLIS), IllegalArgumentException.class);
Asserts.assertThrows(() -> new RetryPolicy().withBackoff(100, 10, ChronoUnit.MILLIS), IllegalArgumentException.class);
Asserts.assertThrows(() -> new RetryPolicy().withBackoff(5, 10, ChronoUnit.MILLIS, .5), IllegalArgumentException.class);
() -> new RetryPolicy().withMaxDuration(Duration.ofMillis(1)).withBackoff(100, 120, ChronoUnit.MILLIS),
IllegalStateException.class);
Asserts.assertThrows(() -> new RetryPolicy().withBackoff(-3, 10, ChronoUnit.MILLIS),
IllegalArgumentException.class);
Asserts.assertThrows(() -> new RetryPolicy().withBackoff(100, 10, ChronoUnit.MILLIS),
IllegalArgumentException.class);
Asserts.assertThrows(() -> new RetryPolicy().withBackoff(5, 10, ChronoUnit.MILLIS, .5),
IllegalArgumentException.class);
}

public void shouldRequireValidDelay() {
Asserts.assertThrows(() -> new RetryPolicy().withDelay((Duration)null), NullPointerException.class);
Asserts.assertThrows(() -> new RetryPolicy().withMaxDuration(Duration.ofMillis(1)).withDelay(Duration.ofMillis(100)),
IllegalStateException.class);
Asserts.assertThrows(() -> new RetryPolicy().withDelay((Duration) null), NullPointerException.class);
Asserts.assertThrows(
() -> new RetryPolicy().withMaxDuration(Duration.ofMillis(1)).withDelay(Duration.ofMillis(100)),
IllegalStateException.class);
Asserts.assertThrows(() -> new RetryPolicy().withBackoff(1, 2, ChronoUnit.MILLIS).withDelay(Duration.ofMillis(100)),
IllegalStateException.class);
IllegalStateException.class);
Asserts.assertThrows(() -> new RetryPolicy().withDelay(Duration.ofMillis(-1)), IllegalArgumentException.class);
}

Expand All @@ -164,8 +182,8 @@ public void shouldRequireValidMaxRetries() {

public void shouldRequireValidMaxDuration() {
Asserts.assertThrows(
() -> new RetryPolicy().withDelay(Duration.ofMillis(100)).withMaxDuration(Duration.ofMillis(100)),
IllegalStateException.class);
() -> new RetryPolicy().withDelay(Duration.ofMillis(100)).withMaxDuration(Duration.ofMillis(100)),
IllegalStateException.class);
}

public void testGetMaxAttempts() {
Expand Down
6 changes: 3 additions & 3 deletions src/test/java/net/jodah/failsafe/examples/VertxExample.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ public class VertxExample {
static Vertx vertx = Vertx.vertx();

/** Create RetryPolicy to handle Vert.x failures */
static RetryPolicy<Object> retryPolicy = new RetryPolicy<>().handleIf(
(ReplyException failure) -> ReplyFailure.RECIPIENT_FAILURE.equals(failure.failureType())
|| ReplyFailure.TIMEOUT.equals(failure.failureType()));
static RetryPolicy<Object> retryPolicy = new RetryPolicy<>().<ReplyException>handleIf(
failure -> ReplyFailure.RECIPIENT_FAILURE.equals(failure.failureType()) || ReplyFailure.TIMEOUT.equals(
failure.failureType()));

/** Adapt Vert.x timer to a Failsafe Scheduler */
static Scheduler scheduler = (callable, delay, unit) -> {
Expand Down

0 comments on commit 052d55f

Please sign in to comment.