Repository: open-telemetry/opentelemetry-java
File: sdk/common/src/main/java/io/opentelemetry/sdk/common/export/RetryPolicy.java (Java)

Code before:

    /**
     * Set the maximum backoff. Must be greater than 0. Defaults to {@value
     * DEFAULT_MAX_BACKOFF_SECONDS} seconds.
     */
    public abstract RetryPolicyBuilder setMaxBackoff(Duration maxBackoff);

    /**
     * Set the backoff multiplier. Must be greater than 0.0. Defaults to {@value
     * DEFAULT_BACKOFF_MULTIPLIER}.
     */
    public abstract RetryPolicyBuilder setBackoffMultiplier(double backoffMultiplier);

    abstract RetryPolicy autoBuild();

    /** Build and return a {@link RetryPolicy} with the values of this builder. */
    public RetryPolicy build() {
      RetryPolicy retryPolicy = autoBuild();
      checkArgument(
          retryPolicy.getMaxAttempts() > 1 && retryPolicy.getMaxAttempts() < 6,
          "maxAttempts must be greater than 1 and less than 6");
      checkArgument(
          retryPolicy.getInitialBackoff().toNanos() > 0, "initialBackoff must be greater than 0");
      checkArgument(retryPolicy.getMaxBackoff().toNanos() > 0, "maxBackoff must be greater than 0");
      checkArgument(
          retryPolicy.getBackoffMultiplier() > 0, "backoffMultiplier must be greater than 0");

      return retryPolicy;
    }
  }
}


Review comment (refactor):
did you consider a customizer instead, to allow choice of either replacing or enhancing the default predicate?

I realize it's not the friendliest API, but we've found the pattern really useful in [AutoConfigurationCustomizer](https://github.com/open-telemetry/opentelemetry-java/blob/main/sdk-extensions/autoconfigure-spi/src/main/java/io/opentelemetry/sdk/autoconfigure/spi/AutoConfigurationCustomizer.java)

```suggestion
    public abstract RetryPolicyBuilder setRetryExceptionPredicateCustomizer(
        Fuction<Predicate<IOException>, Predicate<IOException>> retryExceptionCustomizer);
```

Code after:
     * Set the maximum number of attempts, including the original request. Must be greater than 1
     * and less than 6. Defaults to {@value DEFAULT_MAX_ATTEMPTS}.
     */
    public abstract RetryPolicyBuilder setMaxAttempts(int maxAttempts);

    /**
     * Set the initial backoff. Must be greater than 0. Defaults to {@value
     * DEFAULT_INITIAL_BACKOFF_SECONDS} seconds.
     */
    public abstract RetryPolicyBuilder setInitialBackoff(Duration initialBackoff);

    /**
     * Set the maximum backoff. Must be greater than 0. Defaults to {@value
     * DEFAULT_MAX_BACKOFF_SECONDS} seconds.
     */
    public abstract RetryPolicyBuilder setMaxBackoff(Duration maxBackoff);

    /**
     * Set the backoff multiplier. Must be greater than 0.0. Defaults to {@value
     * DEFAULT_BACKOFF_MULTIPLIER}.
     */
    public abstract RetryPolicyBuilder setBackoffMultiplier(double backoffMultiplier);

    /** Set the predicate to determine if retry should happen based on exception. */
    public abstract RetryPolicyBuilder setRetryExceptionPredicate(
        Predicate<IOException> retryExceptionPredicate);

    abstract RetryPolicy autoBuild();

    /** Build and return a {@link RetryPolicy} with the values of this builder. */
    public RetryPolicy build() {
      RetryPolicy retryPolicy = autoBuild();
      checkArgument(
          retryPolicy.getMaxAttempts() > 1 && retryPolicy.getMaxAttempts() < 6,
          "maxAttempts must be greater than 1 and less than 6");
      checkArgument(
          retryPolicy.getInitialBackoff().toNanos() > 0, "initialBackoff must be greater than 0");
      checkArgument(retryPolicy.getMaxBackoff().toNanos() > 0, "maxBackoff must be greater than 0");
      checkArgument(
          retryPolicy.getBackoffMultiplier() > 0, "backoffMultiplier must be greater than 0");

      return retryPolicy;
    }
  }
}