| **Design:** Convention, **Status:** [Accepted](README.md) |
| |
| ## Client Configuration |
| |
| This page describes the structure and conventions used for client configuration objects. Client configuration objects are any objects used to configure an AWS client builder. |
| |
| #### Example |
| |
| This section walks through an example configuration class structure and describes each of its components at a high level. |
| |
| ```Java |
| /** |
| * Configuration Description // (1) |
| */ |
| @Immutable |
| @ThreadSafe // (2) |
| public final class SdkConfiguration // (3) |
| implements ToCopyableBuilder<SdkConfiguration.Builder, SdkConfiguration> { // (4) |
| private final String option; // (5) |
| |
| /** |
| * @see #builder() // (6) |
| */ |
| private SdkClientConfiguration(DefaultSdkConfigurationBuilder builder) { |
| this.option = builder.option; |
| } |
| |
| public static Builder builder() { |
| return new DefaultSdkConfigurationBuilder(); |
| } |
| |
| /** |
| * @see #Builder#option(String) // (7) |
| */ |
| public String option() { |
| return this.option; |
| } |
| |
| @Override |
| public ClientHttpConfiguration.Builder toBuilder() { |
| return builder().option(option); |
| } |
| |
| @NotThreadSafe |
| public interface Builder extends CopyableBuilder<Builder, SdkConfiguration> { // (8) |
| /** |
| * Configuration Option Description // (9) |
| */ |
| Builder option(String option); |
| } |
| |
| private static final class DefaultSdkConfigurationBuilder implements Builder { // (10) |
| private String option; |
| |
| @Override |
| public Builder option(String option) { // (11) |
| this.option = option; |
| return this; |
| } |
| |
| public void setOption(String option) { // (12) |
| this.option = option; |
| } |
| |
| @Override |
| public SdkConfiguration build() { |
| return new SdkConfiguration(this); |
| } |
| } |
| } |
| ``` |
| |
| 1. A detailed description should be given of what types of options the user might find in this object. |
| 2. Configuration objects should be `@Immutable`, and therefore `@ThreadSafe`. |
| 3. Configuration classes should be defined as `final` to prevent extension. |
| 4. Configuration classes should extend `ToCopyableBuilder` to ensure they can be converted back to a builder object. |
| 5. All configuration fields should be defined as `private final` to prevent reassignment. |
| 6. Configuration constructors should be `private` to enforce creation by the `Builder` and refer curious eyes to the `builder()` method for creating the object. |
| 7. One "get" method should be created for each configuration field. This method's name should exactly match the name of the field it is retrieving. |
| 8. Each builder should have its own interface. This allows hiding certain public methods from auto-complete (see below). |
| 9. A detailed description of each option should be given, including what it does, and **why** a user could want to change its default value. |
| 10. A `private static final` implementation of the `Builder` interface should be created that is not exposed outside of the scope of the configuration class. |
| 11. One "set" method should be created for each option to mutate the value in this builder. This method's name should exactly match the name of the field it is setting. |
| 12. Each option should have a bean-style setter to allow configuring the object reflectively using `Inspector`-based frameworks, like spring XML. |
| |
| #### Configuration Fields |
| |
| This section details the semantics of configuration fields. |
| |
| 1. Configuration fields must be **immutable**. |
| 1. Fields must be marked as `final`. |
| 2. Mutable types, like `List` and `Set` should be wrapped in a type that prevents their modification (eg. `Collections.unmodifiableList`) when referenced through the "get" method. |
| 3. Mutable types, like `List` and `Set` should be copied in the "set" method to prevent their modification by mutating the original object. |
| 2. Configuration fields must be **reference types**. Primitive types like `boolean` or `int` should not be used because they can not convey the absence of configuration. |
| 3. Configuration field names should **not start with a verb** (eg. `config.enableRedirect()` should instead be `config.redirectEnabled()`). This is to avoid confusing their "get" methods for a mutating action. |
| |
| Special notes for collection types, like `List`, `Set`, and `Map`: |
| |
| 1. Collection type field names must be plural. |
| 2. There should be two methods provided to modify the collection. |
| - method with plural field name which permits adding a collection. It should override any values currently configured in the builder. |
| - method that permits adding one item to the collection. |
| - If the collection is a list, the method name should use `add` prefix, eg: `addApiName` |
| - If the collection is a map, the method name should use `put` prefix, eg: `putHeader` |
| |
| ```Java |
| public interface Builder { |
| |
| /** |
| * Sets options. |
| * |
| * <p> |
| * This overrides any option values already configured in the builder. |
| */ |
| Builder options(List<String> options); |
| |
| /** |
| * Add a single option to the collection. |
| */ |
| Builder addOption(String option); |
| |
| /** |
| * Sets headers to be set on the HTTP request. |
| * |
| * <p> |
| * This overrides any header values already configured in the builder. |
| */ |
| Builder headers(Map<String, String> headers); |
| |
| /** |
| * Add a single header to be set on the HTTP request. |
| * |
| * <p> |
| * This overrides any values already configured with this header name in the builder. |
| */ |
| Builder putHeader(String key, String value); |
| } |
| ``` |