Skip to content

Commit 43d3e6b

Browse files
authored
Add missing CopyableBuilder interfaces and fixed buggy ones. (#3267)
* Add CopyableBuilder and ToCopyableBuilder interfaces to the credential providers. * Add spotbugs rule validating that all CopyableBuilder fields are copied when ToCopyableBuilder.toBuilder is invoked. Also fixed any violations that rule found.
1 parent eb475d0 commit 43d3e6b

File tree

39 files changed

+912
-83
lines changed

39 files changed

+912
-83
lines changed

build-tools/src/main/java/software/amazon/awssdk/buildtools/findbugs/ToBuilderIsCorrect.java

Lines changed: 456 additions & 0 deletions
Large diffs are not rendered by default.

build-tools/src/main/resources/findbugs.xml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,8 @@
1515

1616
<FindbugsPlugin>
1717
<Detector class="software.amazon.awssdk.buildtools.findbugs.DisallowMethodCall" speed="fast" />
18+
<Detector class="software.amazon.awssdk.buildtools.findbugs.ToBuilderIsCorrect" speed="fast" />
19+
1820
<BugPattern abbrev="BM" type="SDK_BAD_METHOD_CALL" category="PERFORMANCE" />
19-
</FindbugsPlugin>
21+
<BugPattern abbrev="BTB" type="BAD_TO_BUILDER" category="BUG" />
22+
</FindbugsPlugin>

build-tools/src/main/resources/messages.xml

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,12 @@
1414
-->
1515

1616
<MessageCollection>
17-
1817
<Detector class="software.amazon.awssdk.buildtools.findbugs.DisallowMethodCall" >
1918
<Details>This detector checks for method calls that are not allowed for use.</Details>
2019
</Detector>
20+
<Detector class="software.amazon.awssdk.buildtools.findbugs.ToBuilderIsCorrect" >
21+
<Details>This detector checks for correct CopyableBuilder definition.</Details>
22+
</Detector>
2123

2224
<BugPattern type="SDK_BAD_METHOD_CALL">
2325
<ShortDescription>Bad method call</ShortDescription>
@@ -41,6 +43,11 @@
4143
]]>
4244
</Details>
4345
</BugPattern>
46+
<BugPattern type="BAD_TO_BUILDER">
47+
<ShortDescription>Bad toBuilder implementation</ShortDescription>
48+
<LongDescription>Bad toBuilder implementation. See the SpotBugs logs for problem details.</LongDescription>
49+
<Details>Bad toBuilder implementation. See the SpotBugs logs for problem details.</Details>
50+
</BugPattern>
4451

45-
<BugCode abbrev="BM">Bad method</BugCode>
52+
<BugCode abbrev="BTB">Bad toBuilder implementation</BugCode>
4653
</MessageCollection>
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* A copy of the License is located at
7+
*
8+
* http://aws.amazon.com/apache2.0
9+
*
10+
* or in the "license" file accompanying this file. This file is distributed
11+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
* express or implied. See the License for the specific language governing
13+
* permissions and limitations under the License.
14+
*/
15+
16+
package software.amazon.awssdk.annotations;
17+
18+
import java.lang.annotation.ElementType;
19+
import java.lang.annotation.Retention;
20+
import java.lang.annotation.RetentionPolicy;
21+
import java.lang.annotation.Target;
22+
23+
/**
24+
* Used to suppress certain fields from being considered in the spot-bugs rule for toBuilder(). This annotation must be
25+
* attached to the toBuilder() method to function.
26+
*/
27+
@Target(ElementType.METHOD)
28+
@Retention(RetentionPolicy.CLASS)
29+
@SdkProtectedApi
30+
public @interface ToBuilderIgnoreField {
31+
/**
32+
* Specify which fields to ignore in the to-builder spotbugs rule.
33+
*/
34+
String[] value();
35+
}

core/auth/src/main/java/software/amazon/awssdk/auth/credentials/AwsCredentialsProviderChain.java

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
import software.amazon.awssdk.utils.SdkAutoCloseable;
2828
import software.amazon.awssdk.utils.ToString;
2929
import software.amazon.awssdk.utils.Validate;
30+
import software.amazon.awssdk.utils.builder.CopyableBuilder;
31+
import software.amazon.awssdk.utils.builder.ToCopyableBuilder;
3032

3133
/**
3234
* {@link AwsCredentialsProvider} implementation that chains together multiple credentials providers.
@@ -44,7 +46,10 @@
4446
* providers in the chain that need to be closed.</p>
4547
*/
4648
@SdkPublicApi
47-
public final class AwsCredentialsProviderChain implements AwsCredentialsProvider, SdkAutoCloseable {
49+
public final class AwsCredentialsProviderChain
50+
implements AwsCredentialsProvider,
51+
SdkAutoCloseable,
52+
ToCopyableBuilder<AwsCredentialsProviderChain.Builder, AwsCredentialsProviderChain> {
4853
private static final Logger log = Logger.loggerFor(AwsCredentialsProviderChain.class);
4954

5055
private final List<AwsCredentialsProvider> credentialsProviders;
@@ -124,10 +129,15 @@ public String toString() {
124129
.build();
125130
}
126131

132+
@Override
133+
public Builder toBuilder() {
134+
return new BuilderImpl(this);
135+
}
136+
127137
/**
128138
* A builder for a {@link AwsCredentialsProviderChain} that allows controlling its behavior.
129139
*/
130-
public interface Builder {
140+
public interface Builder extends CopyableBuilder<Builder, AwsCredentialsProviderChain> {
131141

132142
/**
133143
* Controls whether the chain should reuse the last successful credentials provider in the chain. Reusing the last
@@ -163,6 +173,11 @@ private static final class BuilderImpl implements Builder {
163173
private BuilderImpl() {
164174
}
165175

176+
private BuilderImpl(AwsCredentialsProviderChain provider) {
177+
this.reuseLastProviderEnabled = provider.reuseLastProviderEnabled;
178+
this.credentialsProviders = provider.credentialsProviders;
179+
}
180+
166181
@Override
167182
public Builder reuseLastProviderEnabled(Boolean reuseLastProviderEnabled) {
168183
this.reuseLastProviderEnabled = reuseLastProviderEnabled;

core/auth/src/main/java/software/amazon/awssdk/auth/credentials/ContainerCredentialsProvider.java

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@
3939
import software.amazon.awssdk.utils.StringUtils;
4040
import software.amazon.awssdk.utils.ToString;
4141
import software.amazon.awssdk.utils.Validate;
42+
import software.amazon.awssdk.utils.builder.CopyableBuilder;
43+
import software.amazon.awssdk.utils.builder.ToCopyableBuilder;
4244
import software.amazon.awssdk.utils.cache.CachedSupplier;
4345
import software.amazon.awssdk.utils.cache.NonBlocking;
4446
import software.amazon.awssdk.utils.cache.RefreshResult;
@@ -60,18 +62,26 @@
6062
* Service (ECS)</a>
6163
*/
6264
@SdkPublicApi
63-
public final class ContainerCredentialsProvider implements HttpCredentialsProvider {
65+
public final class ContainerCredentialsProvider
66+
implements HttpCredentialsProvider,
67+
ToCopyableBuilder<ContainerCredentialsProvider.Builder, ContainerCredentialsProvider> {
6468
private static final Set<String> ALLOWED_HOSTS = unmodifiableSet(new HashSet<>(Arrays.asList("localhost", "127.0.0.1")));
6569

6670
private final String endpoint;
6771
private final HttpCredentialsLoader httpCredentialsLoader;
6872
private final CachedSupplier<AwsCredentials> credentialsCache;
6973

74+
private final Boolean asyncCredentialUpdateEnabled;
75+
76+
private final String asyncThreadName;
77+
7078
/**
7179
* @see #builder()
7280
*/
7381
private ContainerCredentialsProvider(BuilderImpl builder) {
7482
this.endpoint = builder.endpoint;
83+
this.asyncCredentialUpdateEnabled = builder.asyncCredentialUpdateEnabled;
84+
this.asyncThreadName = builder.asyncThreadName;
7585
this.httpCredentialsLoader = HttpCredentialsLoader.create();
7686

7787
if (Boolean.TRUE.equals(builder.asyncCredentialUpdateEnabled)) {
@@ -137,6 +147,11 @@ public void close() {
137147
credentialsCache.close();
138148
}
139149

150+
@Override
151+
public Builder toBuilder() {
152+
return new BuilderImpl(this);
153+
}
154+
140155
static final class ContainerCredentialsEndpointProvider implements ResourcesEndpointProvider {
141156
private final String endpoint;
142157

@@ -209,18 +224,25 @@ private URI createGenericContainerUrl() {
209224
/**
210225
* A builder for creating a custom a {@link ContainerCredentialsProvider}.
211226
*/
212-
public interface Builder extends HttpCredentialsProvider.Builder<ContainerCredentialsProvider, Builder> {
227+
public interface Builder extends HttpCredentialsProvider.Builder<ContainerCredentialsProvider, Builder>,
228+
CopyableBuilder<Builder, ContainerCredentialsProvider> {
213229
}
214230

215231
private static final class BuilderImpl implements Builder {
216232
private String endpoint;
217233
private Boolean asyncCredentialUpdateEnabled;
218234
private String asyncThreadName;
219235

220-
BuilderImpl() {
236+
private BuilderImpl() {
221237
asyncThreadName("container-credentials-provider");
222238
}
223239

240+
private BuilderImpl(ContainerCredentialsProvider credentialsProvider) {
241+
this.endpoint = credentialsProvider.endpoint;
242+
this.asyncCredentialUpdateEnabled = credentialsProvider.asyncCredentialUpdateEnabled;
243+
this.asyncThreadName = credentialsProvider.asyncThreadName;
244+
}
245+
224246
@Override
225247
public Builder endpoint(String endpoint) {
226248
this.endpoint = endpoint;

core/auth/src/main/java/software/amazon/awssdk/auth/credentials/DefaultCredentialsProvider.java

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
import software.amazon.awssdk.profiles.ProfileFile;
2121
import software.amazon.awssdk.utils.SdkAutoCloseable;
2222
import software.amazon.awssdk.utils.ToString;
23+
import software.amazon.awssdk.utils.builder.CopyableBuilder;
24+
import software.amazon.awssdk.utils.builder.ToCopyableBuilder;
2325

2426
/**
2527
* AWS credentials provider chain that looks for credentials in this order:
@@ -41,16 +43,30 @@
4143
* @see InstanceProfileCredentialsProvider
4244
*/
4345
@SdkPublicApi
44-
public final class DefaultCredentialsProvider implements AwsCredentialsProvider, SdkAutoCloseable {
46+
public final class DefaultCredentialsProvider
47+
implements AwsCredentialsProvider, SdkAutoCloseable,
48+
ToCopyableBuilder<DefaultCredentialsProvider.Builder, DefaultCredentialsProvider> {
4549

4650
private static final DefaultCredentialsProvider DEFAULT_CREDENTIALS_PROVIDER = new DefaultCredentialsProvider(builder());
4751

4852
private final LazyAwsCredentialsProvider providerChain;
4953

54+
private final ProfileFile profileFile;
55+
56+
private final String profileName;
57+
58+
private final Boolean reuseLastProviderEnabled;
59+
60+
private final Boolean asyncCredentialUpdateEnabled;
61+
5062
/**
5163
* @see #builder()
5264
*/
5365
private DefaultCredentialsProvider(Builder builder) {
66+
this.profileFile = builder.profileFile;
67+
this.profileName = builder.profileName;
68+
this.reuseLastProviderEnabled = builder.reuseLastProviderEnabled;
69+
this.asyncCredentialUpdateEnabled = builder.asyncCredentialUpdateEnabled;
5470
this.providerChain = createChain(builder);
5571
}
5672

@@ -119,10 +135,15 @@ public String toString() {
119135
.build();
120136
}
121137

138+
@Override
139+
public Builder toBuilder() {
140+
return new Builder(this);
141+
}
142+
122143
/**
123144
* Configuration that defines the {@link DefaultCredentialsProvider}'s behavior.
124145
*/
125-
public static final class Builder {
146+
public static final class Builder implements CopyableBuilder<Builder, DefaultCredentialsProvider> {
126147
private ProfileFile profileFile;
127148
private String profileName;
128149
private Boolean reuseLastProviderEnabled = true;
@@ -134,6 +155,13 @@ public static final class Builder {
134155
private Builder() {
135156
}
136157

158+
private Builder(DefaultCredentialsProvider credentialsProvider) {
159+
this.profileFile = credentialsProvider.profileFile;
160+
this.profileName = credentialsProvider.profileName;
161+
this.reuseLastProviderEnabled = credentialsProvider.reuseLastProviderEnabled;
162+
this.asyncCredentialUpdateEnabled = credentialsProvider.asyncCredentialUpdateEnabled;
163+
}
164+
137165
public Builder profileFile(ProfileFile profileFile) {
138166
this.profileFile = profileFile;
139167
return this;

core/auth/src/main/java/software/amazon/awssdk/auth/credentials/InstanceProfileCredentialsProvider.java

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@
4242
import software.amazon.awssdk.utils.Logger;
4343
import software.amazon.awssdk.utils.ToString;
4444
import software.amazon.awssdk.utils.Validate;
45+
import software.amazon.awssdk.utils.builder.CopyableBuilder;
46+
import software.amazon.awssdk.utils.builder.ToCopyableBuilder;
4547
import software.amazon.awssdk.utils.cache.CachedSupplier;
4648
import software.amazon.awssdk.utils.cache.NonBlocking;
4749
import software.amazon.awssdk.utils.cache.RefreshResult;
@@ -54,7 +56,9 @@
5456
* credentials from EC2 metadata service and will return null.
5557
*/
5658
@SdkPublicApi
57-
public final class InstanceProfileCredentialsProvider implements HttpCredentialsProvider {
59+
public final class InstanceProfileCredentialsProvider
60+
implements HttpCredentialsProvider,
61+
ToCopyableBuilder<InstanceProfileCredentialsProvider.Builder, InstanceProfileCredentialsProvider> {
5862
private static final Logger log = Logger.loggerFor(InstanceProfileCredentialsProvider.class);
5963
private static final String EC2_METADATA_TOKEN_HEADER = "x-aws-ec2-metadata-token";
6064

@@ -69,6 +73,14 @@ public final class InstanceProfileCredentialsProvider implements HttpCredentials
6973
private final HttpCredentialsLoader httpCredentialsLoader;
7074
private final CachedSupplier<AwsCredentials> credentialsCache;
7175

76+
private final Boolean asyncCredentialUpdateEnabled;
77+
78+
private final String asyncThreadName;
79+
80+
private final ProfileFile profileFile;
81+
82+
private final String profileName;
83+
7284
private volatile LoadedCredentials cachedCredentials;
7385

7486
/**
@@ -77,6 +89,11 @@ public final class InstanceProfileCredentialsProvider implements HttpCredentials
7789
private InstanceProfileCredentialsProvider(BuilderImpl builder) {
7890
this.clock = builder.clock;
7991
this.endpoint = builder.endpoint;
92+
this.asyncCredentialUpdateEnabled = builder.asyncCredentialUpdateEnabled;
93+
this.asyncThreadName = builder.asyncThreadName;
94+
this.profileFile = builder.profileFile;
95+
this.profileName = builder.profileName;
96+
8097
this.httpCredentialsLoader = HttpCredentialsLoader.create();
8198
this.configProvider =
8299
Ec2MetadataConfigProvider.builder()
@@ -275,10 +292,16 @@ private Map<String, String> getTokenHeaders(String metadataToken) {
275292
return Collections.singletonMap(EC2_METADATA_TOKEN_HEADER, metadataToken);
276293
}
277294

295+
@Override
296+
public Builder toBuilder() {
297+
return new BuilderImpl(this);
298+
}
299+
278300
/**
279301
* A builder for creating a custom a {@link InstanceProfileCredentialsProvider}.
280302
*/
281-
public interface Builder extends HttpCredentialsProvider.Builder<InstanceProfileCredentialsProvider, Builder> {
303+
public interface Builder extends HttpCredentialsProvider.Builder<InstanceProfileCredentialsProvider, Builder>,
304+
CopyableBuilder<Builder, InstanceProfileCredentialsProvider> {
282305
/**
283306
* Configure the profile file used for loading IMDS-related configuration, like the endpoint mode (IPv4 vs IPv6).
284307
*
@@ -312,6 +335,15 @@ private BuilderImpl() {
312335
asyncThreadName("instance-profile-credentials-provider");
313336
}
314337

338+
private BuilderImpl(InstanceProfileCredentialsProvider provider) {
339+
this.clock = provider.clock;
340+
this.endpoint = provider.endpoint;
341+
this.asyncCredentialUpdateEnabled = provider.asyncCredentialUpdateEnabled;
342+
this.asyncThreadName = provider.asyncThreadName;
343+
this.profileFile = provider.profileFile;
344+
this.profileName = provider.profileName;
345+
}
346+
315347
Builder clock(Clock clock) {
316348
this.clock = clock;
317349
return this;

0 commit comments

Comments
 (0)