Browse Source

Implement toString() in RetryPolicy and RetryExecution implementations

Closes gh-35029
pull/35037/head
Sam Brannen 7 months ago
parent
commit
bfd3dc2676
  1. 26
      spring-core/src/main/java/org/springframework/core/retry/support/MaxRetryAttemptsPolicy.java
  2. 32
      spring-core/src/main/java/org/springframework/core/retry/support/MaxRetryDurationPolicy.java
  3. 27
      spring-core/src/main/java/org/springframework/core/retry/support/PredicateRetryPolicy.java
  4. 59
      spring-core/src/test/java/org/springframework/core/retry/support/MaxRetryAttemptsPolicyTests.java
  5. 21
      spring-core/src/test/java/org/springframework/core/retry/support/MaxRetryDurationPolicyTests.java
  6. 38
      spring-core/src/test/java/org/springframework/core/retry/support/PredicateRetryPolicyTests.java

26
spring-core/src/main/java/org/springframework/core/retry/support/MaxRetryAttemptsPolicy.java

@ -21,10 +21,10 @@ import org.springframework.core.retry.RetryPolicy;
import org.springframework.util.Assert; import org.springframework.util.Assert;
/** /**
* A {@link RetryPolicy} based on a number of attempts that should not exceed a * A {@link RetryPolicy} based on a maximum number of retry attempts.
* configured maximum number.
* *
* @author Mahmoud Ben Hassine * @author Mahmoud Ben Hassine
* @author Sam Brannen
* @since 7.0 * @since 7.0
*/ */
public class MaxRetryAttemptsPolicy implements RetryPolicy { public class MaxRetryAttemptsPolicy implements RetryPolicy {
@ -56,11 +56,6 @@ public class MaxRetryAttemptsPolicy implements RetryPolicy {
setMaxRetryAttempts(maxRetryAttempts); setMaxRetryAttempts(maxRetryAttempts);
} }
@Override
public RetryExecution start() {
return new MaxRetryAttemptsPolicyExecution();
}
/** /**
* Set the maximum number of retry attempts. * Set the maximum number of retry attempts.
* @param maxRetryAttempts the maximum number of retry attempts; must be greater * @param maxRetryAttempts the maximum number of retry attempts; must be greater
@ -71,6 +66,16 @@ public class MaxRetryAttemptsPolicy implements RetryPolicy {
this.maxRetryAttempts = maxRetryAttempts; this.maxRetryAttempts = maxRetryAttempts;
} }
@Override
public RetryExecution start() {
return new MaxRetryAttemptsPolicyExecution();
}
@Override
public String toString() {
return "MaxRetryAttemptsPolicy[maxRetryAttempts=%d]".formatted(this.maxRetryAttempts);
}
/** /**
* A {@link RetryExecution} based on a maximum number of retry attempts. * A {@link RetryExecution} based on a maximum number of retry attempts.
@ -83,6 +88,13 @@ public class MaxRetryAttemptsPolicy implements RetryPolicy {
public boolean shouldRetry(Throwable throwable) { public boolean shouldRetry(Throwable throwable) {
return (this.retryAttempts++ < MaxRetryAttemptsPolicy.this.maxRetryAttempts); return (this.retryAttempts++ < MaxRetryAttemptsPolicy.this.maxRetryAttempts);
} }
@Override
public String toString() {
return "MaxRetryAttemptsPolicyExecution[retryAttempts=%d, maxRetryAttempts=%d]"
.formatted(this.retryAttempts, MaxRetryAttemptsPolicy.this.maxRetryAttempts);
}
} }
} }

32
spring-core/src/main/java/org/springframework/core/retry/support/MaxRetryDurationPolicy.java

@ -24,9 +24,10 @@ import org.springframework.core.retry.RetryPolicy;
import org.springframework.util.Assert; import org.springframework.util.Assert;
/** /**
* A {@link RetryPolicy} based on a maximum retry duration. * A {@link RetryPolicy} based on a maximum retry {@link Duration}.
* *
* @author Mahmoud Ben Hassine * @author Mahmoud Ben Hassine
* @author Sam Brannen
* @since 7.0 * @since 7.0
*/ */
public class MaxRetryDurationPolicy implements RetryPolicy { public class MaxRetryDurationPolicy implements RetryPolicy {
@ -42,7 +43,7 @@ public class MaxRetryDurationPolicy implements RetryPolicy {
/** /**
* Create a new {@code MaxRetryDurationPolicy} with the default maximum retry * Create a new {@code MaxRetryDurationPolicy} with the default maximum retry
* duration. * {@link Duration}.
* @see #DEFAULT_MAX_RETRY_DURATION * @see #DEFAULT_MAX_RETRY_DURATION
*/ */
public MaxRetryDurationPolicy() { public MaxRetryDurationPolicy() {
@ -50,20 +51,15 @@ public class MaxRetryDurationPolicy implements RetryPolicy {
/** /**
* Create a new {@code MaxRetryDurationPolicy} with the specified maximum retry * Create a new {@code MaxRetryDurationPolicy} with the specified maximum retry
* duration. * {@link Duration}.
* @param maxRetryDuration the maximum retry duration; must be positive * @param maxRetryDuration the maximum retry duration; must be positive
*/ */
public MaxRetryDurationPolicy(Duration maxRetryDuration) { public MaxRetryDurationPolicy(Duration maxRetryDuration) {
setMaxRetryDuration(maxRetryDuration); setMaxRetryDuration(maxRetryDuration);
} }
@Override
public RetryExecution start() {
return new MaxRetryDurationPolicyExecution();
}
/** /**
* Set the maximum retry duration. * Set the maximum retry {@link Duration}.
* @param maxRetryDuration the maximum retry duration; must be positive * @param maxRetryDuration the maximum retry duration; must be positive
*/ */
public void setMaxRetryDuration(Duration maxRetryDuration) { public void setMaxRetryDuration(Duration maxRetryDuration) {
@ -72,6 +68,17 @@ public class MaxRetryDurationPolicy implements RetryPolicy {
this.maxRetryDuration = maxRetryDuration; this.maxRetryDuration = maxRetryDuration;
} }
@Override
public RetryExecution start() {
return new MaxRetryDurationPolicyExecution();
}
@Override
public String toString() {
return "MaxRetryDurationPolicy[maxRetryDuration=%dms]".formatted(this.maxRetryDuration.toMillis());
}
/** /**
* A {@link RetryExecution} based on a maximum retry duration. * A {@link RetryExecution} based on a maximum retry duration.
*/ */
@ -84,6 +91,13 @@ public class MaxRetryDurationPolicy implements RetryPolicy {
Duration currentRetryDuration = Duration.between(this.retryStartTime, LocalDateTime.now()); Duration currentRetryDuration = Duration.between(this.retryStartTime, LocalDateTime.now());
return currentRetryDuration.compareTo(MaxRetryDurationPolicy.this.maxRetryDuration) <= 0; return currentRetryDuration.compareTo(MaxRetryDurationPolicy.this.maxRetryDuration) <= 0;
} }
@Override
public String toString() {
return "MaxRetryDurationPolicyExecution[retryStartTime=%s, maxRetryDuration=%dms]"
.formatted(this.retryStartTime, MaxRetryDurationPolicy.this.maxRetryDuration.toMillis());
}
} }
} }

27
spring-core/src/main/java/org/springframework/core/retry/support/PredicateRetryPolicy.java

@ -25,6 +25,7 @@ import org.springframework.core.retry.RetryPolicy;
* A {@link RetryPolicy} based on a {@link Predicate}. * A {@link RetryPolicy} based on a {@link Predicate}.
* *
* @author Mahmoud Ben Hassine * @author Mahmoud Ben Hassine
* @author Sam Brannen
* @since 7.0 * @since 7.0
*/ */
public class PredicateRetryPolicy implements RetryPolicy { public class PredicateRetryPolicy implements RetryPolicy {
@ -44,7 +45,31 @@ public class PredicateRetryPolicy implements RetryPolicy {
@Override @Override
public RetryExecution start() { public RetryExecution start() {
return this.predicate::test; return new PredicateRetryPolicyExecution();
}
@Override
public String toString() {
return "PredicateRetryPolicy[predicate=%s]".formatted(this.predicate.getClass().getSimpleName());
}
/**
* A {@link RetryExecution} based on a {@link Predicate}.
*/
private class PredicateRetryPolicyExecution implements RetryExecution {
@Override
public boolean shouldRetry(Throwable throwable) {
return PredicateRetryPolicy.this.predicate.test(throwable);
}
@Override
public String toString() {
return "PredicateRetryPolicyExecution[predicate=%s]"
.formatted(PredicateRetryPolicy.this.predicate.getClass().getSimpleName());
}
} }
} }

59
spring-core/src/test/java/org/springframework/core/retry/support/MaxRetryAttemptsPolicyTests.java

@ -25,9 +25,11 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
/** /**
* Tests for {@link MaxRetryAttemptsPolicy}. * Tests for {@link MaxRetryAttemptsPolicy} and its {@link RetryExecution}.
* *
* @author Mahmoud Ben Hassine * @author Mahmoud Ben Hassine
* @author Sam Brannen
* @since 7.0
*/ */
class MaxRetryAttemptsPolicyTests { class MaxRetryAttemptsPolicyTests {
@ -44,14 +46,69 @@ class MaxRetryAttemptsPolicyTests {
assertThat(retryExecution.shouldRetry(throwable)).isTrue(); assertThat(retryExecution.shouldRetry(throwable)).isTrue();
assertThat(retryExecution.shouldRetry(throwable)).isTrue(); assertThat(retryExecution.shouldRetry(throwable)).isTrue();
assertThat(retryExecution.shouldRetry(throwable)).isTrue(); assertThat(retryExecution.shouldRetry(throwable)).isTrue();
assertThat(retryExecution.shouldRetry(throwable)).isFalse();
assertThat(retryExecution.shouldRetry(throwable)).isFalse();
}
@Test
void customMaxRetryAttempts() {
// given
MaxRetryAttemptsPolicy retryPolicy = new MaxRetryAttemptsPolicy(2);
Throwable throwable = mock();
// when
RetryExecution retryExecution = retryPolicy.start();
// then
assertThat(retryExecution.shouldRetry(throwable)).isTrue();
assertThat(retryExecution.shouldRetry(throwable)).isTrue();
assertThat(retryExecution.shouldRetry(throwable)).isFalse();
assertThat(retryExecution.shouldRetry(throwable)).isFalse(); assertThat(retryExecution.shouldRetry(throwable)).isFalse();
} }
@Test @Test
void invalidMaxRetryAttempts() { void invalidMaxRetryAttempts() {
assertThatIllegalArgumentException()
.isThrownBy(() -> new MaxRetryAttemptsPolicy(0))
.withMessage("Max retry attempts must be greater than zero");
assertThatIllegalArgumentException() assertThatIllegalArgumentException()
.isThrownBy(() -> new MaxRetryAttemptsPolicy(-1)) .isThrownBy(() -> new MaxRetryAttemptsPolicy(-1))
.withMessage("Max retry attempts must be greater than zero"); .withMessage("Max retry attempts must be greater than zero");
} }
@Test
void toStringImplementations() {
MaxRetryAttemptsPolicy policy1 = new MaxRetryAttemptsPolicy();
MaxRetryAttemptsPolicy policy2 = new MaxRetryAttemptsPolicy(1);
assertThat(policy1).asString().isEqualTo("MaxRetryAttemptsPolicy[maxRetryAttempts=3]");
assertThat(policy2).asString().isEqualTo("MaxRetryAttemptsPolicy[maxRetryAttempts=1]");
RetryExecution retryExecution = policy1.start();
assertThat(retryExecution).asString()
.isEqualTo("MaxRetryAttemptsPolicyExecution[retryAttempts=0, maxRetryAttempts=3]");
assertThat(retryExecution.shouldRetry(mock())).isTrue();
assertThat(retryExecution).asString()
.isEqualTo("MaxRetryAttemptsPolicyExecution[retryAttempts=1, maxRetryAttempts=3]");
assertThat(retryExecution.shouldRetry(mock())).isTrue();
assertThat(retryExecution).asString()
.isEqualTo("MaxRetryAttemptsPolicyExecution[retryAttempts=2, maxRetryAttempts=3]");
assertThat(retryExecution.shouldRetry(mock())).isTrue();
assertThat(retryExecution).asString()
.isEqualTo("MaxRetryAttemptsPolicyExecution[retryAttempts=3, maxRetryAttempts=3]");
assertThat(retryExecution.shouldRetry(mock())).isFalse();
assertThat(retryExecution).asString()
.isEqualTo("MaxRetryAttemptsPolicyExecution[retryAttempts=4, maxRetryAttempts=3]");
assertThat(retryExecution.shouldRetry(mock())).isFalse();
assertThat(retryExecution).asString()
.isEqualTo("MaxRetryAttemptsPolicyExecution[retryAttempts=5, maxRetryAttempts=3]");
}
} }

21
spring-core/src/test/java/org/springframework/core/retry/support/MaxRetryDurationPolicyTests.java

@ -20,12 +20,17 @@ import java.time.Duration;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.core.retry.RetryExecution;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
/** /**
* Tests for {@link MaxRetryDurationPolicy}. * Tests for {@link MaxRetryDurationPolicy} and its {@link RetryExecution}.
* *
* @author Mahmoud Ben Hassine * @author Mahmoud Ben Hassine
* @author Sam Brannen
* @since 7.0
*/ */
class MaxRetryDurationPolicyTests { class MaxRetryDurationPolicyTests {
@ -36,4 +41,18 @@ class MaxRetryDurationPolicyTests {
.withMessage("Max retry duration must be positive"); .withMessage("Max retry duration must be positive");
} }
@Test
void toStringImplementations() {
MaxRetryDurationPolicy policy1 = new MaxRetryDurationPolicy();
MaxRetryDurationPolicy policy2 = new MaxRetryDurationPolicy(Duration.ofSeconds(1));
assertThat(policy1).asString().isEqualTo("MaxRetryDurationPolicy[maxRetryDuration=3000ms]");
assertThat(policy2).asString().isEqualTo("MaxRetryDurationPolicy[maxRetryDuration=1000ms]");
assertThat(policy1.start()).asString()
.matches("MaxRetryDurationPolicyExecution\\[retryStartTime=.+, maxRetryDuration=3000ms\\]");
assertThat(policy2.start()).asString()
.matches("MaxRetryDurationPolicyExecution\\[retryStartTime=.+, maxRetryDuration=1000ms\\]");
}
} }

38
spring-core/src/test/java/org/springframework/core/retry/support/PredicateRetryPolicyTests.java

@ -25,28 +25,46 @@ import org.springframework.core.retry.RetryExecution;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
/** /**
* Tests for {@link PredicateRetryPolicy}. * Tests for {@link PredicateRetryPolicy} and its {@link RetryExecution}.
* *
* @author Mahmoud Ben Hassine * @author Mahmoud Ben Hassine
* @author Sam Brannen
* @since 7.0
*/ */
class PredicateRetryPolicyTests { class PredicateRetryPolicyTests {
@Test @Test
void predicateRetryPolicy() { void predicateRetryPolicy() {
// given Predicate<Throwable> predicate = NumberFormatException.class::isInstance;
class MyException extends Exception {
@java.io.Serial
private static final long serialVersionUID = 1L;
}
Predicate<Throwable> predicate = MyException.class::isInstance;
PredicateRetryPolicy retryPolicy = new PredicateRetryPolicy(predicate); PredicateRetryPolicy retryPolicy = new PredicateRetryPolicy(predicate);
// when
RetryExecution retryExecution = retryPolicy.start(); RetryExecution retryExecution = retryPolicy.start();
// then assertThat(retryExecution.shouldRetry(new NumberFormatException())).isTrue();
assertThat(retryExecution.shouldRetry(new MyException())).isTrue();
assertThat(retryExecution.shouldRetry(new IllegalStateException())).isFalse(); assertThat(retryExecution.shouldRetry(new IllegalStateException())).isFalse();
} }
@Test
void toStringImplementations() {
PredicateRetryPolicy policy1 = new PredicateRetryPolicy(NumberFormatException.class::isInstance);
PredicateRetryPolicy policy2 = new PredicateRetryPolicy(new NumberFormatExceptionMatcher());
assertThat(policy1).asString().matches("PredicateRetryPolicy\\[predicate=PredicateRetryPolicyTests.+?Lambda.+?\\]");
assertThat(policy2).asString().isEqualTo("PredicateRetryPolicy[predicate=NumberFormatExceptionMatcher]");
assertThat(policy1.start()).asString()
.matches("PredicateRetryPolicyExecution\\[predicate=PredicateRetryPolicyTests.+?Lambda.+?\\]");
assertThat(policy2.start()).asString()
.isEqualTo("PredicateRetryPolicyExecution[predicate=NumberFormatExceptionMatcher]");
}
private static class NumberFormatExceptionMatcher implements Predicate<Throwable> {
@Override
public boolean test(Throwable throwable) {
return (throwable instanceof NumberFormatException);
}
}
} }

Loading…
Cancel
Save