Skip to content

Commit bfd3dc2

Browse files
committed
Implement toString() in RetryPolicy and RetryExecution implementations
Closes gh-35029
1 parent bc96784 commit bfd3dc2

File tree

6 files changed

+174
-29
lines changed

6 files changed

+174
-29
lines changed

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

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@
2121
import org.springframework.util.Assert;
2222

2323
/**
24-
* A {@link RetryPolicy} based on a number of attempts that should not exceed a
25-
* configured maximum number.
24+
* A {@link RetryPolicy} based on a maximum number of retry attempts.
2625
*
2726
* @author Mahmoud Ben Hassine
27+
* @author Sam Brannen
2828
* @since 7.0
2929
*/
3030
public class MaxRetryAttemptsPolicy implements RetryPolicy {
@@ -56,11 +56,6 @@ public MaxRetryAttemptsPolicy(int maxRetryAttempts) {
5656
setMaxRetryAttempts(maxRetryAttempts);
5757
}
5858

59-
@Override
60-
public RetryExecution start() {
61-
return new MaxRetryAttemptsPolicyExecution();
62-
}
63-
6459
/**
6560
* Set the maximum number of retry attempts.
6661
* @param maxRetryAttempts the maximum number of retry attempts; must be greater
@@ -71,6 +66,16 @@ public void setMaxRetryAttempts(int maxRetryAttempts) {
7166
this.maxRetryAttempts = maxRetryAttempts;
7267
}
7368

69+
@Override
70+
public RetryExecution start() {
71+
return new MaxRetryAttemptsPolicyExecution();
72+
}
73+
74+
@Override
75+
public String toString() {
76+
return "MaxRetryAttemptsPolicy[maxRetryAttempts=%d]".formatted(this.maxRetryAttempts);
77+
}
78+
7479

7580
/**
7681
* A {@link RetryExecution} based on a maximum number of retry attempts.
@@ -83,6 +88,13 @@ private class MaxRetryAttemptsPolicyExecution implements RetryExecution {
8388
public boolean shouldRetry(Throwable throwable) {
8489
return (this.retryAttempts++ < MaxRetryAttemptsPolicy.this.maxRetryAttempts);
8590
}
91+
92+
@Override
93+
public String toString() {
94+
return "MaxRetryAttemptsPolicyExecution[retryAttempts=%d, maxRetryAttempts=%d]"
95+
.formatted(this.retryAttempts, MaxRetryAttemptsPolicy.this.maxRetryAttempts);
96+
}
97+
8698
}
8799

88100
}

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

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,10 @@
2424
import org.springframework.util.Assert;
2525

2626
/**
27-
* A {@link RetryPolicy} based on a maximum retry duration.
27+
* A {@link RetryPolicy} based on a maximum retry {@link Duration}.
2828
*
2929
* @author Mahmoud Ben Hassine
30+
* @author Sam Brannen
3031
* @since 7.0
3132
*/
3233
public class MaxRetryDurationPolicy implements RetryPolicy {
@@ -42,28 +43,23 @@ public class MaxRetryDurationPolicy implements RetryPolicy {
4243

4344
/**
4445
* Create a new {@code MaxRetryDurationPolicy} with the default maximum retry
45-
* duration.
46+
* {@link Duration}.
4647
* @see #DEFAULT_MAX_RETRY_DURATION
4748
*/
4849
public MaxRetryDurationPolicy() {
4950
}
5051

5152
/**
5253
* Create a new {@code MaxRetryDurationPolicy} with the specified maximum retry
53-
* duration.
54+
* {@link Duration}.
5455
* @param maxRetryDuration the maximum retry duration; must be positive
5556
*/
5657
public MaxRetryDurationPolicy(Duration maxRetryDuration) {
5758
setMaxRetryDuration(maxRetryDuration);
5859
}
5960

60-
@Override
61-
public RetryExecution start() {
62-
return new MaxRetryDurationPolicyExecution();
63-
}
64-
6561
/**
66-
* Set the maximum retry duration.
62+
* Set the maximum retry {@link Duration}.
6763
* @param maxRetryDuration the maximum retry duration; must be positive
6864
*/
6965
public void setMaxRetryDuration(Duration maxRetryDuration) {
@@ -72,6 +68,17 @@ public void setMaxRetryDuration(Duration maxRetryDuration) {
7268
this.maxRetryDuration = maxRetryDuration;
7369
}
7470

71+
@Override
72+
public RetryExecution start() {
73+
return new MaxRetryDurationPolicyExecution();
74+
}
75+
76+
@Override
77+
public String toString() {
78+
return "MaxRetryDurationPolicy[maxRetryDuration=%dms]".formatted(this.maxRetryDuration.toMillis());
79+
}
80+
81+
7582
/**
7683
* A {@link RetryExecution} based on a maximum retry duration.
7784
*/
@@ -84,6 +91,13 @@ public boolean shouldRetry(Throwable throwable) {
8491
Duration currentRetryDuration = Duration.between(this.retryStartTime, LocalDateTime.now());
8592
return currentRetryDuration.compareTo(MaxRetryDurationPolicy.this.maxRetryDuration) <= 0;
8693
}
94+
95+
@Override
96+
public String toString() {
97+
return "MaxRetryDurationPolicyExecution[retryStartTime=%s, maxRetryDuration=%dms]"
98+
.formatted(this.retryStartTime, MaxRetryDurationPolicy.this.maxRetryDuration.toMillis());
99+
}
100+
87101
}
88102

89103
}

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

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
* A {@link RetryPolicy} based on a {@link Predicate}.
2626
*
2727
* @author Mahmoud Ben Hassine
28+
* @author Sam Brannen
2829
* @since 7.0
2930
*/
3031
public class PredicateRetryPolicy implements RetryPolicy {
@@ -44,7 +45,31 @@ public PredicateRetryPolicy(Predicate<Throwable> predicate) {
4445

4546
@Override
4647
public RetryExecution start() {
47-
return this.predicate::test;
48+
return new PredicateRetryPolicyExecution();
49+
}
50+
51+
@Override
52+
public String toString() {
53+
return "PredicateRetryPolicy[predicate=%s]".formatted(this.predicate.getClass().getSimpleName());
54+
}
55+
56+
57+
/**
58+
* A {@link RetryExecution} based on a {@link Predicate}.
59+
*/
60+
private class PredicateRetryPolicyExecution implements RetryExecution {
61+
62+
@Override
63+
public boolean shouldRetry(Throwable throwable) {
64+
return PredicateRetryPolicy.this.predicate.test(throwable);
65+
}
66+
67+
@Override
68+
public String toString() {
69+
return "PredicateRetryPolicyExecution[predicate=%s]"
70+
.formatted(PredicateRetryPolicy.this.predicate.getClass().getSimpleName());
71+
}
72+
4873
}
4974

5075
}

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

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,11 @@
2525
import static org.mockito.Mockito.mock;
2626

2727
/**
28-
* Tests for {@link MaxRetryAttemptsPolicy}.
28+
* Tests for {@link MaxRetryAttemptsPolicy} and its {@link RetryExecution}.
2929
*
3030
* @author Mahmoud Ben Hassine
31+
* @author Sam Brannen
32+
* @since 7.0
3133
*/
3234
class MaxRetryAttemptsPolicyTests {
3335

@@ -44,14 +46,69 @@ void defaultMaxRetryAttempts() {
4446
assertThat(retryExecution.shouldRetry(throwable)).isTrue();
4547
assertThat(retryExecution.shouldRetry(throwable)).isTrue();
4648
assertThat(retryExecution.shouldRetry(throwable)).isTrue();
49+
50+
assertThat(retryExecution.shouldRetry(throwable)).isFalse();
51+
assertThat(retryExecution.shouldRetry(throwable)).isFalse();
52+
}
53+
54+
@Test
55+
void customMaxRetryAttempts() {
56+
// given
57+
MaxRetryAttemptsPolicy retryPolicy = new MaxRetryAttemptsPolicy(2);
58+
Throwable throwable = mock();
59+
60+
// when
61+
RetryExecution retryExecution = retryPolicy.start();
62+
63+
// then
64+
assertThat(retryExecution.shouldRetry(throwable)).isTrue();
65+
assertThat(retryExecution.shouldRetry(throwable)).isTrue();
66+
67+
assertThat(retryExecution.shouldRetry(throwable)).isFalse();
4768
assertThat(retryExecution.shouldRetry(throwable)).isFalse();
4869
}
4970

5071
@Test
5172
void invalidMaxRetryAttempts() {
73+
assertThatIllegalArgumentException()
74+
.isThrownBy(() -> new MaxRetryAttemptsPolicy(0))
75+
.withMessage("Max retry attempts must be greater than zero");
5276
assertThatIllegalArgumentException()
5377
.isThrownBy(() -> new MaxRetryAttemptsPolicy(-1))
5478
.withMessage("Max retry attempts must be greater than zero");
5579
}
5680

81+
@Test
82+
void toStringImplementations() {
83+
MaxRetryAttemptsPolicy policy1 = new MaxRetryAttemptsPolicy();
84+
MaxRetryAttemptsPolicy policy2 = new MaxRetryAttemptsPolicy(1);
85+
86+
assertThat(policy1).asString().isEqualTo("MaxRetryAttemptsPolicy[maxRetryAttempts=3]");
87+
assertThat(policy2).asString().isEqualTo("MaxRetryAttemptsPolicy[maxRetryAttempts=1]");
88+
89+
RetryExecution retryExecution = policy1.start();
90+
assertThat(retryExecution).asString()
91+
.isEqualTo("MaxRetryAttemptsPolicyExecution[retryAttempts=0, maxRetryAttempts=3]");
92+
93+
assertThat(retryExecution.shouldRetry(mock())).isTrue();
94+
assertThat(retryExecution).asString()
95+
.isEqualTo("MaxRetryAttemptsPolicyExecution[retryAttempts=1, maxRetryAttempts=3]");
96+
97+
assertThat(retryExecution.shouldRetry(mock())).isTrue();
98+
assertThat(retryExecution).asString()
99+
.isEqualTo("MaxRetryAttemptsPolicyExecution[retryAttempts=2, maxRetryAttempts=3]");
100+
101+
assertThat(retryExecution.shouldRetry(mock())).isTrue();
102+
assertThat(retryExecution).asString()
103+
.isEqualTo("MaxRetryAttemptsPolicyExecution[retryAttempts=3, maxRetryAttempts=3]");
104+
105+
assertThat(retryExecution.shouldRetry(mock())).isFalse();
106+
assertThat(retryExecution).asString()
107+
.isEqualTo("MaxRetryAttemptsPolicyExecution[retryAttempts=4, maxRetryAttempts=3]");
108+
109+
assertThat(retryExecution.shouldRetry(mock())).isFalse();
110+
assertThat(retryExecution).asString()
111+
.isEqualTo("MaxRetryAttemptsPolicyExecution[retryAttempts=5, maxRetryAttempts=3]");
112+
}
113+
57114
}

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

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,17 @@
2020

2121
import org.junit.jupiter.api.Test;
2222

23+
import org.springframework.core.retry.RetryExecution;
24+
25+
import static org.assertj.core.api.Assertions.assertThat;
2326
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
2427

2528
/**
26-
* Tests for {@link MaxRetryDurationPolicy}.
29+
* Tests for {@link MaxRetryDurationPolicy} and its {@link RetryExecution}.
2730
*
2831
* @author Mahmoud Ben Hassine
32+
* @author Sam Brannen
33+
* @since 7.0
2934
*/
3035
class MaxRetryDurationPolicyTests {
3136

@@ -36,4 +41,18 @@ void invalidMaxRetryDuration() {
3641
.withMessage("Max retry duration must be positive");
3742
}
3843

44+
@Test
45+
void toStringImplementations() {
46+
MaxRetryDurationPolicy policy1 = new MaxRetryDurationPolicy();
47+
MaxRetryDurationPolicy policy2 = new MaxRetryDurationPolicy(Duration.ofSeconds(1));
48+
49+
assertThat(policy1).asString().isEqualTo("MaxRetryDurationPolicy[maxRetryDuration=3000ms]");
50+
assertThat(policy2).asString().isEqualTo("MaxRetryDurationPolicy[maxRetryDuration=1000ms]");
51+
52+
assertThat(policy1.start()).asString()
53+
.matches("MaxRetryDurationPolicyExecution\\[retryStartTime=.+, maxRetryDuration=3000ms\\]");
54+
assertThat(policy2.start()).asString()
55+
.matches("MaxRetryDurationPolicyExecution\\[retryStartTime=.+, maxRetryDuration=1000ms\\]");
56+
}
57+
3958
}

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

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,28 +25,46 @@
2525
import static org.assertj.core.api.Assertions.assertThat;
2626

2727
/**
28-
* Tests for {@link PredicateRetryPolicy}.
28+
* Tests for {@link PredicateRetryPolicy} and its {@link RetryExecution}.
2929
*
3030
* @author Mahmoud Ben Hassine
31+
* @author Sam Brannen
32+
* @since 7.0
3133
*/
3234
class PredicateRetryPolicyTests {
3335

3436
@Test
3537
void predicateRetryPolicy() {
36-
// given
37-
class MyException extends Exception {
38-
@java.io.Serial
39-
private static final long serialVersionUID = 1L;
40-
}
41-
Predicate<Throwable> predicate = MyException.class::isInstance;
38+
Predicate<Throwable> predicate = NumberFormatException.class::isInstance;
4239
PredicateRetryPolicy retryPolicy = new PredicateRetryPolicy(predicate);
4340

44-
// when
4541
RetryExecution retryExecution = retryPolicy.start();
4642

47-
// then
48-
assertThat(retryExecution.shouldRetry(new MyException())).isTrue();
43+
assertThat(retryExecution.shouldRetry(new NumberFormatException())).isTrue();
4944
assertThat(retryExecution.shouldRetry(new IllegalStateException())).isFalse();
5045
}
5146

47+
@Test
48+
void toStringImplementations() {
49+
PredicateRetryPolicy policy1 = new PredicateRetryPolicy(NumberFormatException.class::isInstance);
50+
PredicateRetryPolicy policy2 = new PredicateRetryPolicy(new NumberFormatExceptionMatcher());
51+
52+
assertThat(policy1).asString().matches("PredicateRetryPolicy\\[predicate=PredicateRetryPolicyTests.+?Lambda.+?\\]");
53+
assertThat(policy2).asString().isEqualTo("PredicateRetryPolicy[predicate=NumberFormatExceptionMatcher]");
54+
55+
assertThat(policy1.start()).asString()
56+
.matches("PredicateRetryPolicyExecution\\[predicate=PredicateRetryPolicyTests.+?Lambda.+?\\]");
57+
assertThat(policy2.start()).asString()
58+
.isEqualTo("PredicateRetryPolicyExecution[predicate=NumberFormatExceptionMatcher]");
59+
}
60+
61+
62+
private static class NumberFormatExceptionMatcher implements Predicate<Throwable> {
63+
64+
@Override
65+
public boolean test(Throwable throwable) {
66+
return (throwable instanceof NumberFormatException);
67+
}
68+
}
69+
5270
}

0 commit comments

Comments
 (0)