Overhaul Javadoc of RestTemplateBuilder

Fix typos in the `RestTemplateBuilder` Javadocs, some confusing explanations, a lack of descriptions of error conditions
This commit is contained in:
Andreas Ahlenstorf
2023-06-07 15:05:57 +02:00
committed by GitHub
parent 41b7df83bb
commit 1c7fab8319
2 changed files with 146 additions and 134 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2006-2022 the original author or authors.
* Copyright 2006-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -37,11 +37,21 @@ import org.springframework.retry.policy.TimeoutRetryPolicy;
import org.springframework.util.Assert;
/**
* Fluent API to configure new instance of RetryTemplate. For detailed description of each
* builder method - see it's doc.
* Builder that provides a fluent API to configure new instances of {@link RetryTemplate}.
*
* <p>
* Examples: <pre>{@code
* By default, the builder configures a {@link BinaryExceptionClassifier} that acts upon
* {@link Exception} and its subclasses without traversing causes, a
* {@link NoBackOffPolicy} and a {@link MaxAttemptsRetryPolicy} that attempts actions
* {@link MaxAttemptsRetryPolicy#DEFAULT_MAX_ATTEMPTS} times.
*
* <p>
* The builder is not thread-safe.
*
* <p>
* Example usage:
*
* <pre>{@code
* RetryTemplate.builder()
* .maxAttempts(10)
* .exponentialBackoff(100, 2, 10000)
@@ -61,26 +71,6 @@ import org.springframework.util.Assert;
* .build();
* }</pre>
*
* <p>
* The builder provides the following defaults:
* <ul>
* <li>retry policy: max attempts = 3 (initial + 2 retries)</li>
* <li>backoff policy: no backoff (retry immediately)</li>
* <li>exception classification: retry only on {@link Exception} and it's subclasses,
* without traversing of causes</li>
* </ul>
*
* <p>
* The builder supports only widely used properties of {@link RetryTemplate}. More
* specific properties can be configured directly (after building).
*
* <p>
* Not thread safe. Building should be performed in a single thread. Also, there is no
* guarantee that all constructors of all fields are thread safe in-depth (means employing
* only volatile and final writes), so, in concurrent environment, it is recommended to
* ensure presence of happens-before between publication and any usage. (e.g. publication
* via volatile write, or other safe publication technique)
*
* @author Aleksandr Shamukov
* @author Artem Bilan
* @author Kim In Hoi
@@ -100,13 +90,12 @@ public class RetryTemplateBuilder {
/* ---------------- Configure retry policy -------------- */
/**
* Limits maximum number of attempts to provided value.
* <p>
* Invocation of this method does not discard default exception classification rule,
* that is "retry only on {@link Exception} and it's subclasses".
* @param maxAttempts includes initial attempt and all retries. E.g: maxAttempts = 3
* means one initial attempt and two retries.
* Attempt an action no more than {@code maxAttempts} times.
* @param maxAttempts how many times an action should be attempted. A value of 3 would
* result in an initial attempt and two retries.
* @return this
* @throws IllegalArgumentException if {@code maxAttempts} is 0 or less, or if another
* retry policy has already been selected.
* @see MaxAttemptsRetryPolicy
*/
public RetryTemplateBuilder maxAttempts(int maxAttempts) {
@@ -117,12 +106,11 @@ public class RetryTemplateBuilder {
}
/**
* Allows retry if there is no more than {@code timeout} millis since first attempt.
* <p>
* Invocation of this method does not discard default exception classification rule,
* that is "retry only on {@link Exception} and it's subclasses".
* @param timeout whole execution timeout in milliseconds
* Retry until {@code timeout} has passed since the initial attempt.
* @param timeout timeout in milliseconds
* @return this
* @throws IllegalArgumentException if timeout is {@literal <=} 0 or if another retry
* policy has already been selected.
* @see TimeoutRetryPolicy
* @deprecated Use {@link #withTimeout(long)} instead.
*/
@@ -132,13 +120,13 @@ public class RetryTemplateBuilder {
}
/**
* Retry until {@code timeout} has passed since the initial attempt.
* Retry until {@code timeoutMillis} has passed since the initial attempt.
* @param timeoutMillis timeout in milliseconds
* @return this
* @see TimeoutRetryPolicy
* @throws IllegalArgumentException if timeout is {@literal <=} 0 or if another retry
* policy has already been configured.
* policy has already been selected.
* @since 2.0.2
* @see TimeoutRetryPolicy
*/
public RetryTemplateBuilder withTimeout(long timeoutMillis) {
Assert.isTrue(timeoutMillis > 0, "timeoutMillis should be greater than 0");
@@ -151,10 +139,10 @@ public class RetryTemplateBuilder {
* Retry until {@code timeout} has passed since the initial attempt.
* @param timeout duration for how long retries should be attempted
* @return this
* @see TimeoutRetryPolicy
* @throws IllegalArgumentException if timeout is {@code null} or 0, or if another
* retry policy has already been configured.
* retry policy has already been selected.
* @since 2.0.2
* @see TimeoutRetryPolicy
*/
public RetryTemplateBuilder withTimeout(Duration timeout) {
Assert.notNull(timeout, "timeout must not be null");
@@ -162,12 +150,10 @@ public class RetryTemplateBuilder {
}
/**
* Allows infinite retry, do not limit attempts by number or time.
* <p>
* Invocation of this method does not discard default exception classification rule,
* that is "retry only on {@link Exception} and it's subclasses".
* Retry actions infinitely.
* @return this
* @see TimeoutRetryPolicy
* @throws IllegalArgumentException if another retry policy has already been selected.
* @see AlwaysRetryPolicy
*/
public RetryTemplateBuilder infiniteRetry() {
Assert.isNull(this.baseRetryPolicy, "You have already selected another retry policy");
@@ -176,13 +162,12 @@ public class RetryTemplateBuilder {
}
/**
* If flexibility of this builder is not enough for you, you can provide your own
* {@link RetryPolicy} via this method.
* <p>
* Invocation of this method does not discard default exception classification rule,
* that is "retry only on {@link Exception} and it's subclasses".
* @param policy will be directly set to resulting {@link RetryTemplate}
* Use the provided {@link RetryPolicy}.
* @param policy {@link RetryPolicy} to use
* @return this
* @throws IllegalArgumentException if another backoff policy has already been
* selected, if any argument is {@code null}, or if another retry policy has already
* been selected.
*/
public RetryTemplateBuilder customPolicy(RetryPolicy policy) {
Assert.notNull(policy, "Policy should not be null");
@@ -194,15 +179,18 @@ public class RetryTemplateBuilder {
/* ---------------- Configure backoff policy -------------- */
/**
* Use exponential backoff policy. The formula of backoff period:
* Use an exponential backoff policy. The formula for the backoff period is:
* <p>
* {@code currentInterval = Math.min(initialInterval * Math.pow(multiplier, retryNum), maxInterval)}
* <p>
* (for first attempt retryNum = 0)
* @param initialInterval in milliseconds
* @param multiplier see the formula above
* @param maxInterval in milliseconds
* For the first attempt, {@code retryNum = 0}.
* @param initialInterval initial sleep duration in milliseconds
* @param multiplier backoff interval multiplier
* @param maxInterval maximum backoff duration in milliseconds
* @return this
* @throws IllegalArgumentException if another backoff policy has already been
* selected, if {@code initialInterval} is {@literal <} 1, if {@code multiplier} is
* {@literal <=} 1, or if {@code maxInterval} {@literal <=} {@code initialInterval}.
* @see ExponentialBackOffPolicy
*/
public RetryTemplateBuilder exponentialBackoff(long initialInterval, double multiplier, long maxInterval) {
@@ -210,19 +198,21 @@ public class RetryTemplateBuilder {
}
/**
* Use exponential backoff policy. The formula of backoff period:
* Use an exponential backoff policy. The formula for the backoff period is:
* <p>
* {@code currentInterval = Math.min(initialInterval * Math.pow(multiplier, retryNum), maxInterval)}
* <p>
* (for first attempt retryNum = 0)
* For the first attempt, {@code retryNum = 0}.
* @param initialInterval initial sleep duration
* @param multiplier backoff interval multiplier
* @param maxInterval maximum backoff duration
* @return this
* @see ExponentialBackOffPolicy
* @throws IllegalArgumentException if initialInterval is {@code null}, multiplier is
* {@literal <=} 1, or if maxInterval is {@code null}
* @throws IllegalArgumentException if another backoff policy has already been
* selected, if {@code initialInterval} is {@code null} or less than 1 millisecond,
* multiplier is {@literal <=} 1, or if {@code maxInterval} is {@code null} or
* {@literal <=} {@code initialInterval}.
* @since 2.0.2
* @see ExponentialBackOffPolicy
*/
public RetryTemplateBuilder exponentialBackoff(Duration initialInterval, double multiplier, Duration maxInterval) {
Assert.notNull(initialInterval, "initialInterval must not be null");
@@ -231,17 +221,21 @@ public class RetryTemplateBuilder {
}
/**
* Use exponential backoff policy. The formula of backoff period (without randomness):
* Use an exponential backoff policy. The formula for the backoff period is (without
* randomness):
* <p>
* {@code currentInterval = Math.min(initialInterval * Math.pow(multiplier, retryNum), maxInterval)}
* <p>
* (for first attempt retryNum = 0)
* @param initialInterval in milliseconds
* @param multiplier see the formula above
* @param maxInterval in milliseconds
* @param withRandom adds some randomness to backoff intervals. For details, see
* {@link ExponentialRandomBackOffPolicy}
* For the first attempt, {@code retryNum = 0}.
* @param initialInterval initial sleep duration in milliseconds
* @param multiplier backoff interval multiplier
* @param maxInterval maximum backoff duration in milliseconds
* @param withRandom whether to use a {@link ExponentialRandomBackOffPolicy} (if
* {@code true}) or not
* @return this
* @throws IllegalArgumentException if another backoff policy has already been
* selected, if {@code initialInterval} is {@literal <} 1, if {@code multiplier} is
* {@literal <=} 1, or if {@code maxInterval} {@literal <=} {@code initialInterval}.
* @see ExponentialBackOffPolicy
* @see ExponentialRandomBackOffPolicy
*/
@@ -261,22 +255,25 @@ public class RetryTemplateBuilder {
}
/**
* Use exponential backoff policy. The formula of backoff period (without randomness):
* Use an exponential backoff policy. The formula for the backoff period is (without
* randomness):
* <p>
* {@code currentInterval = Math.min(initialInterval * Math.pow(multiplier, retryNum), maxInterval)}
* <p>
* (for first attempt retryNum = 0)
* For the first attempt, {@code retryNum = 0}.
* @param initialInterval initial sleep duration
* @param multiplier backoff interval multiplier
* @param maxInterval maximum backoff duration
* @param withRandom adds some randomness to backoff intervals. For details, see
* {@link ExponentialRandomBackOffPolicy}
* @param withRandom whether to use a {@link ExponentialRandomBackOffPolicy} (if
* {@code true}) or not
* @return this
* @throws IllegalArgumentException if another backoff policy has already been
* selected, if {@code initialInterval} is {@code null} or less than 1 millisecond, if
* {@code multiplier} is {@literal <=} 1, or if {@code maxInterval} is {@code null} or
* {@literal <=} {@code initialInterval}.
* @since 2.0.2
* @see ExponentialBackOffPolicy
* @see ExponentialRandomBackOffPolicy
* @throws IllegalArgumentException if initialInterval is {@code null}, multiplier is
* {@literal <=} 1, or maxInterval is {@code null}
* @since 2.0.2
*/
public RetryTemplateBuilder exponentialBackoff(Duration initialInterval, double multiplier, Duration maxInterval,
boolean withRandom) {
@@ -286,9 +283,11 @@ public class RetryTemplateBuilder {
}
/**
* Perform each retry after fixed amount of time.
* Perform each retry after a fixed amount of time.
* @param interval fixed interval in milliseconds
* @return this
* @throws IllegalArgumentException if another backoff policy has already been
* selected, or if {@code interval} is {@literal <} 1.
* @see FixedBackOffPolicy
*/
public RetryTemplateBuilder fixedBackoff(long interval) {
@@ -304,10 +303,10 @@ public class RetryTemplateBuilder {
* Perform each retry after fixed amount of time.
* @param interval fixed backoff duration
* @return this
* @see FixedBackOffPolicy
* @throws IllegalArgumentException if another backoff policy has already been
* configured, interval is {@code null} or less than 1 millisecond
* selected, or if {@code interval} is {@code null} or less than 1 millisecond
* @since 2.0.2
* @see FixedBackOffPolicy
*/
public RetryTemplateBuilder fixedBackoff(Duration interval) {
Assert.notNull(interval, "interval must not be null");
@@ -319,10 +318,13 @@ public class RetryTemplateBuilder {
}
/**
* Use {@link UniformRandomBackOffPolicy}, see it's doc for details.
* @param minInterval in milliseconds
* @param maxInterval in milliseconds
* Use {@link UniformRandomBackOffPolicy}.
* @param minInterval minimal interval in milliseconds
* @param maxInterval maximal interval in milliseconds
* @return this
* @throws IllegalArgumentException if another backoff policy has already been
* selected, if {@code minInterval} is {@literal <} 1, {@code maxInterval} is
* {@literal <} 1, or if {@code maxInterval} is {@literal <=} {@code minInterval}.
* @see UniformRandomBackOffPolicy
*/
public RetryTemplateBuilder uniformRandomBackoff(long minInterval, long maxInterval) {
@@ -342,11 +344,12 @@ public class RetryTemplateBuilder {
* @param minInterval minimum backoff duration
* @param maxInterval maximum backoff duration
* @return this
* @see UniformRandomBackOffPolicy
* @throws IllegalArgumentException if minInterval is {@code null} or {@literal <} 1,
* maxInterval is {@code null} or {@literal <} 1, maxInterval {@literal >=}
* minInterval or if another backoff policy has already been configured.
* @throws IllegalArgumentException if another backoff policy has already been
* selected, if {@code minInterval} is {@code null} or {@literal <} 1,
* {@code maxInterval} is {@code null} or less than 1 millisecond, or if
* {@code maxInterval} {@literal <=} {@code minInterval}.
* @since 2.0.2
* @see UniformRandomBackOffPolicy
*/
public RetryTemplateBuilder uniformRandomBackoff(Duration minInterval, Duration maxInterval) {
Assert.notNull(minInterval, "minInterval must not be null");
@@ -355,8 +358,10 @@ public class RetryTemplateBuilder {
}
/**
* Do not pause between attempts, retry immediately.
* Retry immediately without pausing between attempts.
* @return this
* @throws IllegalArgumentException if another backoff policy has already been
* selected.
* @see NoBackOffPolicy
*/
public RetryTemplateBuilder noBackoff() {
@@ -366,9 +371,11 @@ public class RetryTemplateBuilder {
}
/**
* You can provide your own {@link BackOffPolicy} via this method.
* @param backOffPolicy will be directly set to resulting {@link RetryTemplate}
* Use the provided {@link BackOffPolicy}.
* @param backOffPolicy {@link BackOffPolicy} to use
* @return this
* @throws IllegalArgumentException if {@code backOffPolicy} is null or if another
* backoff policy has already been selected.
*/
public RetryTemplateBuilder customBackoff(BackOffPolicy backOffPolicy) {
Assert.isNull(this.backOffPolicy, "You have already selected backoff policy");
@@ -380,16 +387,15 @@ public class RetryTemplateBuilder {
/* ---------------- Configure exception classifier -------------- */
/**
* Add a throwable to the while list of retryable exceptions.
* Add the {@link Throwable} and its subclasses to the list of exceptions that cause a
* retry.
* <p>
* Warn: touching this method drops default {@code retryOn(Exception.class)} and you
* should configure whole classifier from scratch.
* <p>
* You should select the way you want to configure exception classifier: white list or
* black list. If you choose white list - use this method, if black - use
* {@link #notRetryOn(Class)} or {@link #notRetryOn(List)}
* @param throwable to be retryable (with it's subclasses)
* {@code retryOn()} and {@code notRetryOn()} are mutually exclusive. Trying to use
* both causes an {@link IllegalArgumentException}.
* @param throwable that causes a retry
* @return this
* @throws IllegalArgumentException if {@code throwable} is {@code null}, or if
* {@link #notRetryOn} has already been used.
* @see BinaryExceptionClassifierBuilder#retryOn
* @see BinaryExceptionClassifier
*/
@@ -399,16 +405,15 @@ public class RetryTemplateBuilder {
}
/**
* Add a throwable to the black list of retryable exceptions.
* Add the {@link Throwable} and its subclasses to the list of exceptions that do not
* cause a retry.
* <p>
* Warn: touching this method drops default {@code retryOn(Exception.class)} and you
* should configure whole classifier from scratch.
* <p>
* You should select the way you want to configure exception classifier: white list or
* black list. If you choose black list - use this method, if white - use
* {@link #retryOn(Class)} or {@link #retryOn(List)}
* @param throwable to be not retryable (with it's subclasses)
* {@code retryOn()} and {@code notRetryOn()} are mutually exclusive. Trying to use
* both causes an {@link IllegalArgumentException}.
* @param throwable that does not cause a retry
* @return this
* @throws IllegalArgumentException if {@code throwable} is {@code null}, or if
* {@link #retryOn} has already been used.
* @see BinaryExceptionClassifierBuilder#notRetryOn
* @see BinaryExceptionClassifier
*/
@@ -418,16 +423,14 @@ public class RetryTemplateBuilder {
}
/**
* Add all throwables to the while list of retryable exceptions.
* Add the list of {@link Throwable} classes and their subclasses to the list of
* exceptions that cause a retry.
* <p>
* Warn: touching this method drops default {@code retryOn(Exception.class)} and you
* should configure whole classifier from scratch.
* <p>
* You should select the way you want to configure exception classifier: white list or
* black list. If you choose white list - use this method, if black - use
* {@link #notRetryOn(Class)} or {@link #notRetryOn(List)}
* @param throwables to be retryable (with it's subclasses)
* {@code retryOn()} and {@code notRetryOn()} are mutually exclusive. Trying to use
* both causes an {@link IllegalArgumentException}.
* @param throwables that cause a retry
* @return this
* @throws IllegalArgumentException if {@link #notRetryOn} has already been used.
* @since 1.3.2
* @see BinaryExceptionClassifierBuilder#retryOn
* @see BinaryExceptionClassifier
@@ -440,16 +443,14 @@ public class RetryTemplateBuilder {
}
/**
* Add all throwables to the black list of retryable exceptions.
* Add the list of {@link Throwable} classes and their subclasses to the list of
* exceptions that do not cause a retry.
* <p>
* Warn: touching this method drops default {@code retryOn(Exception.class)} and you
* should configure whole classifier from scratch.
* <p>
* You should select the way you want to configure exception classifier: white list or
* black list. If you choose black list - use this method, if white - use
* {@link #retryOn(Class)} or {@link #retryOn(List)}
* @param throwables to be not retryable (with it's subclasses)
* {@code retryOn()} and {@code notRetryOn()} are mutually exclusive. Trying to use
* both causes an {@link IllegalArgumentException}.
* @param throwables that do not cause a retry
* @return this
* @throws IllegalArgumentException if {@link #retryOn} has already been used.
* @since 1.3.2
* @see BinaryExceptionClassifierBuilder#notRetryOn
* @see BinaryExceptionClassifier
@@ -462,12 +463,20 @@ public class RetryTemplateBuilder {
}
/**
* Suppose throwing a {@code new MyLogicException(new IOException())}. This template
* will not retry on it: <pre>{@code
* Enable examining exception causes for {@link Throwable} instances that cause a
* retry.
* <p>
* Suppose the following {@code RetryTemplate}: <pre>{@code
* RetryTemplate.builder()
* .retryOn(IOException.class)
* .build()
* }</pre> but this will retry: <pre>{@code
* }</pre>
* <p>
* It will act on code that throws an {@link java.io.IOException}, for example,
* {@code throw new IOException()}. But it will not retry the action if the
* {@link java.io.IOException} is wrapped in another exception, for example,
* {@code throw new MyException(new IOException())}. However, this
* {@link RetryTemplate} will: <pre>{@code
* RetryTemplate.builder()
* .retryOn(IOException.class)
* .traversingCauses()
@@ -484,10 +493,10 @@ public class RetryTemplateBuilder {
/* ---------------- Add listeners -------------- */
/**
* Appends provided {@code listener} to {@link RetryTemplate}'s listener list.
* Append the provided {@code listener} to {@link RetryTemplate}'s list of listeners.
* @param listener to be appended
* @return this
* @see RetryTemplate
* @throws IllegalArgumentException if {@code listener} is {@code null}.
* @see RetryListener
*/
public RetryTemplateBuilder withListener(RetryListener listener) {
@@ -497,10 +506,10 @@ public class RetryTemplateBuilder {
}
/**
* Appends all provided {@code listeners} to {@link RetryTemplate}'s listener list.
* Append all provided {@code listeners} to {@link RetryTemplate}'s list of listeners.
* @param listeners to be appended
* @return this
* @see RetryTemplate
* @throws IllegalArgumentException if any of the {@code listeners} is {@code null}.
* @see RetryListener
*/
public RetryTemplateBuilder withListeners(List<RetryListener> listeners) {
@@ -514,12 +523,15 @@ public class RetryTemplateBuilder {
/* ---------------- Building -------------- */
/**
* Finish configuration and build resulting {@link RetryTemplate}. For default
* behaviour and concurrency note see class-level doc of {@link RetryTemplateBuilder}.
* The {@code retryPolicy} of the returned {@link RetryTemplate} is always an instance
* of {@link CompositeRetryPolicy}, that consists of one base policy, and of
* {@link BinaryExceptionClassifierRetryPolicy}. The motivation is: whatever base
* policy we use, exception classification is extremely recommended.
* Build a new {@link RetryTemplate}.
* <p>
* Supports building multiple instances. However, it is not possible to change the
* configuration between multiple {@code build()} calls.
* <p>
* The {@code retryPolicy} of the returned {@link RetryTemplate} is always a
* {@link CompositeRetryPolicy} that consists of one base policy and of
* {@link BinaryExceptionClassifierRetryPolicy} to enable exception classification
* regardless of the base policy.
* @return new instance of {@link RetryTemplate}
*/
public RetryTemplate build() {

View File

@@ -308,7 +308,7 @@ public class RetryTemplateBuilderTests {
}
@Test
public void testValidateMeaninglessMultipier() {
public void testValidateMeaninglessMultiplier() {
assertThatIllegalArgumentException()
.isThrownBy(() -> RetryTemplate.builder().exponentialBackoff(100, 1, 200).build());
}