From 9b024ef773c018821f84b11b2ce734cdae5fd9bb Mon Sep 17 00:00:00 2001 From: JordonPhillips Date: Fri, 15 Aug 2025 13:32:58 +0200 Subject: [PATCH 1/2] Add sorted set and map methods to BuilderRef This adds static methods to BuilderRef for creating sorted maps and sets, including an optional custom comparator. --- .../amazon/smithy/utils/BuilderRef.java | 69 +++++++++++++++++++ .../amazon/smithy/utils/BuilderRefTest.java | 35 ++++++++++ 2 files changed, 104 insertions(+) diff --git a/smithy-utils/src/main/java/software/amazon/smithy/utils/BuilderRef.java b/smithy-utils/src/main/java/software/amazon/smithy/utils/BuilderRef.java index 59ec4aa7529..63ea5f7210c 100644 --- a/smithy-utils/src/main/java/software/amazon/smithy/utils/BuilderRef.java +++ b/smithy-utils/src/main/java/software/amazon/smithy/utils/BuilderRef.java @@ -6,6 +6,7 @@ import java.util.ArrayList; import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; @@ -13,6 +14,8 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.TreeMap; +import java.util.TreeSet; /** * Manages the creation, copying, and reuse of values created by builders. @@ -105,6 +108,40 @@ static BuilderRef> forOrderedMap() { Collections::emptyMap); } + /** + * Creates a builder reference to a sorted map. + * + * @param Type of key of the map. + * @param Type of value of the map. + * @return Returns the created map. + */ + static BuilderRef> forSortedMap() { + return new DefaultBuilderRef<>(TreeMap::new, + TreeMap::new, + Collections::unmodifiableMap, + Collections::emptyMap); + } + + /** + * Creates a builder reference to a sorted map with a custom comparator. + * + * @param Type of key of the map. + * @param Type of value of the map. + * @param comparator A comparator used to sort entries in the map. + * @return Returns the created map. + */ + static BuilderRef> forSortedMap(Comparator comparator) { + return new DefaultBuilderRef<>( + () -> new TreeMap<>(comparator), + source -> { + Map copy = new TreeMap<>(comparator); + copy.putAll(source); + return copy; + }, + Collections::unmodifiableMap, + Collections::emptyMap); + } + /** * Creates a builder reference to a list. * @@ -143,4 +180,36 @@ static BuilderRef> forOrderedSet() { Collections::unmodifiableSet, Collections::emptySet); } + + /** + * Creates a builder reference to a sorted set. + * + * @param Type of value in the set. + * @return Returns the created set. + */ + static BuilderRef> forSortedSet() { + return new DefaultBuilderRef<>(TreeSet::new, + TreeSet::new, + Collections::unmodifiableSet, + Collections::emptySet); + } + + /** + * Creates a builder reference to a sorted set. + * + * @param Type of value in the set. + * @param comparator A comparator used to sort items in the set. + * @return Returns the created set. + */ + static BuilderRef> forSortedSet(Comparator comparator) { + return new DefaultBuilderRef<>( + () -> new TreeSet<>(comparator), + source -> { + Set copy = new TreeSet<>(comparator); + copy.addAll(source); + return copy; + }, + Collections::unmodifiableSet, + Collections::emptySet); + } } diff --git a/smithy-utils/src/test/java/software/amazon/smithy/utils/BuilderRefTest.java b/smithy-utils/src/test/java/software/amazon/smithy/utils/BuilderRefTest.java index 256d61f15a4..5a62eb63f6d 100644 --- a/smithy-utils/src/test/java/software/amazon/smithy/utils/BuilderRefTest.java +++ b/smithy-utils/src/test/java/software/amazon/smithy/utils/BuilderRefTest.java @@ -6,10 +6,13 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.containsInRelativeOrder; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.not; import java.util.List; +import java.util.Map; +import java.util.Set; import org.junit.jupiter.api.Test; public class BuilderRefTest { @@ -85,4 +88,36 @@ public void tracksIfHasValue() { assertThat(strings.hasValue(), equalTo(false)); } + + @Test + public void createsSortedMaps() { + BuilderRef> sortedMap = BuilderRef.forSortedMap(); + sortedMap.get().put("c", "d"); + sortedMap.get().put("a", "b"); + assertThat(sortedMap.peek().keySet(), containsInRelativeOrder("a", "c")); + } + + @Test + public void createsSortedMapsWithCustomComparator() { + BuilderRef> sortedMap = BuilderRef.forSortedMap(String.CASE_INSENSITIVE_ORDER); + sortedMap.get().put("C", "d"); + sortedMap.get().put("a", "b"); + assertThat(sortedMap.peek().keySet(), containsInRelativeOrder("a", "C")); + } + + @Test + public void createsSortedSets() { + BuilderRef> sortedSet = BuilderRef.forSortedSet(); + sortedSet.get().add("b"); + sortedSet.get().add("a"); + assertThat(sortedSet.peek(), containsInRelativeOrder("a", "b")); + } + + @Test + public void createsSortedSetsWithCustomComparator() { + BuilderRef> sortedSet = BuilderRef.forSortedSet(String.CASE_INSENSITIVE_ORDER); + sortedSet.get().add("B"); + sortedSet.get().add("a"); + assertThat(sortedSet.peek(), containsInRelativeOrder("a", "B")); + } } From 26e3b2dcd5dc16100d1a853156912aa0d0cf03b5 Mon Sep 17 00:00:00 2001 From: JordonPhillips Date: Fri, 15 Aug 2025 15:22:28 +0200 Subject: [PATCH 2/2] Consistently use BuilderRef for collections This updates every map, set, or list in a builder to use BuilderRef. BuilderRef exists to minimize the number of copies we have to do as well as to make it harder to forget to make immutable copies of collections. In a few cases the underlying collection was changed to preserve or enforce order. --- .../apigateway/traits/AuthorizersTrait.java | 11 +- .../traits/IntegrationResponse.java | 23 ++-- .../apigateway/traits/IntegrationTrait.java | 45 +++---- .../traits/IntegrationTraitIndex.java | 4 +- .../traits/MockIntegrationTrait.java | 33 +++-- .../cloudformation/traits/CfnResource.java | 44 +++--- .../traits/CfnResourceProperty.java | 22 +-- .../traits/CfnResourceTrait.java | 11 +- .../cloudformation/schema/model/Handler.java | 11 +- .../cloudformation/schema/model/Property.java | 12 +- .../cloudformation/schema/model/Remote.java | 25 ++-- .../schema/model/ResourceSchema.java | 125 +++++++++--------- .../cloudformation/schema/model/Tagging.java | 11 +- .../iam/traits/DefineConditionKeysTrait.java | 11 +- .../amazon/smithy/build/PluginContext.java | 2 +- .../amazon/smithy/build/TransformContext.java | 2 +- .../codegen/core/MappedReservedWords.java | 17 ++- .../core/trace/ArtifactDefinitions.java | 23 ++-- .../smithy/codegen/core/trace/ShapeLink.java | 11 +- .../smithy/codegen/core/trace/TraceFile.java | 17 ++- .../jsonschema/JsonSchemaConverter.java | 11 +- .../amazon/smithy/jsonschema/Schema.java | 76 ++++++----- .../smithy/jsonschema/SchemaDocument.java | 9 +- .../amazon/smithy/jsonschema/SchemaTest.java | 19 +++ .../smithy/openapi/model/CallbackObject.java | 11 +- .../smithy/openapi/model/Component.java | 16 ++- .../openapi/model/ComponentsObject.java | 85 ++++++------ .../smithy/openapi/model/EncodingObject.java | 11 +- .../smithy/openapi/model/LinkObject.java | 9 +- .../smithy/openapi/model/MediaTypeObject.java | 21 +-- .../amazon/smithy/openapi/model/OpenApi.java | 29 ++-- .../smithy/openapi/model/OperationObject.java | 59 ++++----- .../smithy/openapi/model/ParameterObject.java | 19 ++- .../amazon/smithy/openapi/model/PathItem.java | 19 ++- .../openapi/model/RequestBodyObject.java | 11 +- .../smithy/openapi/model/ResponseObject.java | 27 ++-- .../smithy/openapi/model/ServerObject.java | 9 +- .../HttpMalformedRequestDefinition.java | 19 ++- .../traits/HttpMalformedRequestTestCase.java | 9 +- .../HttpMalformedResponseDefinition.java | 11 +- .../traits/HttpMessageTestCase.java | 31 ++--- .../traits/HttpRequestTestCase.java | 21 ++- ...meterizedHttpMalformedRequestTestCase.java | 14 +- .../syntax/parameters/Parameters.java | 8 +- .../smoketests/traits/SmokeTestCase.java | 9 +- 45 files changed, 519 insertions(+), 504 deletions(-) diff --git a/smithy-aws-apigateway-traits/src/main/java/software/amazon/smithy/aws/apigateway/traits/AuthorizersTrait.java b/smithy-aws-apigateway-traits/src/main/java/software/amazon/smithy/aws/apigateway/traits/AuthorizersTrait.java index 94286f2aaa1..a3747f532d6 100644 --- a/smithy-aws-apigateway-traits/src/main/java/software/amazon/smithy/aws/apigateway/traits/AuthorizersTrait.java +++ b/smithy-aws-apigateway-traits/src/main/java/software/amazon/smithy/aws/apigateway/traits/AuthorizersTrait.java @@ -5,7 +5,6 @@ package software.amazon.smithy.aws.apigateway.traits; import java.util.Comparator; -import java.util.HashMap; import java.util.Map; import java.util.Objects; import java.util.Optional; @@ -16,7 +15,7 @@ import software.amazon.smithy.model.traits.AbstractTrait; import software.amazon.smithy.model.traits.AbstractTraitBuilder; import software.amazon.smithy.model.traits.Trait; -import software.amazon.smithy.utils.MapUtils; +import software.amazon.smithy.utils.BuilderRef; import software.amazon.smithy.utils.ToSmithyBuilder; /** @@ -40,7 +39,7 @@ public final class AuthorizersTrait extends AbstractTrait implements ToSmithyBui private AuthorizersTrait(Builder builder) { super(ID, builder.getSourceLocation()); - authorizers = MapUtils.copyOf(builder.authorizers); + authorizers = builder.authorizers.copy(); } public static final class Provider extends AbstractTrait.Provider { @@ -110,7 +109,7 @@ protected Node createNode() { * Builds an {@link AuthorizersTrait}. */ public static final class Builder extends AbstractTraitBuilder { - private final Map authorizers = new HashMap<>(); + private final BuilderRef> authorizers = BuilderRef.forOrderedMap(); @Override public AuthorizersTrait build() { @@ -125,7 +124,7 @@ public AuthorizersTrait build() { * @return Returns the builder. */ public Builder putAuthorizer(String name, AuthorizerDefinition authorizer) { - authorizers.put(name, Objects.requireNonNull(authorizer)); + authorizers.get().put(name, Objects.requireNonNull(authorizer)); return this; } @@ -148,7 +147,7 @@ public Builder authorizers(Map authorizers) { * @return Returns the builder. */ public Builder removeAuthorizer(String name) { - authorizers.remove(name); + authorizers.get().remove(name); return this; } diff --git a/smithy-aws-apigateway-traits/src/main/java/software/amazon/smithy/aws/apigateway/traits/IntegrationResponse.java b/smithy-aws-apigateway-traits/src/main/java/software/amazon/smithy/aws/apigateway/traits/IntegrationResponse.java index 3b916df36b4..a61a7f602c9 100644 --- a/smithy-aws-apigateway-traits/src/main/java/software/amazon/smithy/aws/apigateway/traits/IntegrationResponse.java +++ b/smithy-aws-apigateway-traits/src/main/java/software/amazon/smithy/aws/apigateway/traits/IntegrationResponse.java @@ -4,14 +4,13 @@ */ package software.amazon.smithy.aws.apigateway.traits; -import java.util.HashMap; import java.util.Map; import java.util.Optional; import software.amazon.smithy.model.FromSourceLocation; import software.amazon.smithy.model.node.Node; import software.amazon.smithy.model.node.NodeMapper; import software.amazon.smithy.model.node.ToNode; -import software.amazon.smithy.utils.MapUtils; +import software.amazon.smithy.utils.BuilderRef; import software.amazon.smithy.utils.SmithyBuilder; import software.amazon.smithy.utils.ToSmithyBuilder; @@ -31,8 +30,8 @@ public final class IntegrationResponse implements ToNode, ToSmithyBuilder { private String statusCode; private String contentHandling; - private Map responseTemplates = new HashMap<>(); - private Map responseParameters = new HashMap<>(); + private final BuilderRef> responseTemplates = BuilderRef.forSortedMap(); + private final BuilderRef> responseParameters = BuilderRef.forSortedMap(); private FromSourceLocation sourceLocation; @Override @@ -193,7 +192,7 @@ public Builder contentHandling(String contentHandling) { */ public Builder responseTemplates(Map responseTemplates) { this.responseTemplates.clear(); - this.responseTemplates.putAll(responseTemplates); + responseTemplates.forEach(this::putResponseTemplate); return this; } @@ -206,7 +205,7 @@ public Builder responseTemplates(Map responseTemplates) { * @see IntegrationResponse#getResponseTemplates() */ public Builder putResponseTemplate(String mimeType, String template) { - responseTemplates.put(mimeType, template); + responseTemplates.get().put(mimeType, template); return this; } @@ -217,7 +216,7 @@ public Builder putResponseTemplate(String mimeType, String template) { * @return Returns the builder. */ public Builder removeResponseTemplate(String mimeType) { - responseTemplates.remove(mimeType); + responseTemplates.get().remove(mimeType); return this; } @@ -230,7 +229,7 @@ public Builder removeResponseTemplate(String mimeType) { */ public Builder responseParameters(Map responseParameters) { this.responseParameters.clear(); - this.responseParameters.putAll(responseParameters); + responseParameters.forEach(this::putResponseParameter); return this; } @@ -243,7 +242,7 @@ public Builder responseParameters(Map responseParameters) { * @see IntegrationResponse#getResponseParameters() */ public Builder putResponseParameter(String name, String value) { - responseParameters.put(name, value); + responseParameters.get().put(name, value); return this; } @@ -254,7 +253,7 @@ public Builder putResponseParameter(String name, String value) { * @return Returns the builder. */ public Builder removeResponseParameter(String name) { - responseParameters.remove(name); + responseParameters.get().remove(name); return this; } diff --git a/smithy-aws-apigateway-traits/src/main/java/software/amazon/smithy/aws/apigateway/traits/IntegrationTrait.java b/smithy-aws-apigateway-traits/src/main/java/software/amazon/smithy/aws/apigateway/traits/IntegrationTrait.java index 36606b90951..82e9bffa597 100644 --- a/smithy-aws-apigateway-traits/src/main/java/software/amazon/smithy/aws/apigateway/traits/IntegrationTrait.java +++ b/smithy-aws-apigateway-traits/src/main/java/software/amazon/smithy/aws/apigateway/traits/IntegrationTrait.java @@ -4,8 +4,6 @@ */ package software.amazon.smithy.aws.apigateway.traits; -import java.util.ArrayList; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; @@ -17,8 +15,7 @@ import software.amazon.smithy.model.traits.AbstractTrait; import software.amazon.smithy.model.traits.AbstractTraitBuilder; import software.amazon.smithy.model.traits.Trait; -import software.amazon.smithy.utils.ListUtils; -import software.amazon.smithy.utils.MapUtils; +import software.amazon.smithy.utils.BuilderRef; import software.amazon.smithy.utils.SmithyBuilder; import software.amazon.smithy.utils.ToSmithyBuilder; @@ -64,10 +61,10 @@ private IntegrationTrait(Builder builder) { connectionType = builder.connectionType; cacheNamespace = builder.cacheNamespace; payloadFormatVersion = builder.payloadFormatVersion; - cacheKeyParameters = ListUtils.copyOf(builder.cacheKeyParameters); - requestParameters = MapUtils.copyOf(builder.requestParameters); - requestTemplates = MapUtils.copyOf(builder.requestTemplates); - responses = MapUtils.copyOf(builder.responses); + cacheKeyParameters = builder.cacheKeyParameters.copy(); + requestParameters = builder.requestParameters.copy(); + requestTemplates = builder.requestTemplates.copy(); + responses = builder.responses.copy(); } public static final class Provider extends AbstractTrait.Provider { @@ -369,10 +366,10 @@ public static final class Builder extends AbstractTraitBuilder cacheKeyParameters = new ArrayList<>(); - private final Map requestParameters = new HashMap<>(); - private final Map requestTemplates = new HashMap<>(); - private final Map responses = new HashMap<>(); + private final BuilderRef> cacheKeyParameters = BuilderRef.forList(); + private final BuilderRef> requestParameters = BuilderRef.forOrderedMap(); + private final BuilderRef> requestTemplates = BuilderRef.forOrderedMap(); + private final BuilderRef> responses = BuilderRef.forOrderedMap(); @Override public IntegrationTrait build() { @@ -523,7 +520,7 @@ public Builder payloadFormatVersion(String payloadFormatVersion) { * @return Returns the builder. */ public Builder addCacheKeyParameter(String cacheKeyParameter) { - this.cacheKeyParameters.add(cacheKeyParameter); + this.cacheKeyParameters.get().add(cacheKeyParameter); return this; } @@ -535,7 +532,7 @@ public Builder addCacheKeyParameter(String cacheKeyParameter) { */ public Builder cacheKeyParameters(List cacheKeyParameters) { this.cacheKeyParameters.clear(); - this.cacheKeyParameters.addAll(cacheKeyParameters); + cacheKeyParameters.forEach(this::addCacheKeyParameter); return this; } @@ -546,7 +543,7 @@ public Builder cacheKeyParameters(List cacheKeyParameters) { * @return Returns the builder. */ public Builder removeCacheKeyParameter(String cacheKeyParameter) { - this.cacheKeyParameters.remove(cacheKeyParameter); + this.cacheKeyParameters.get().remove(cacheKeyParameter); return this; } @@ -569,7 +566,7 @@ public Builder clearCacheKeyParameters() { * @see IntegrationTrait#getRequestParameters() */ public Builder putRequestParameter(String input, String output) { - requestParameters.put(input, output); + requestParameters.get().put(input, output); return this; } @@ -582,7 +579,7 @@ public Builder putRequestParameter(String input, String output) { */ public Builder requestParameters(Map requestParameters) { this.requestParameters.clear(); - this.requestParameters.putAll(requestParameters); + requestParameters.forEach(this::putRequestParameter); return this; } @@ -593,7 +590,7 @@ public Builder requestParameters(Map requestParameters) { * @return Returns the builder. */ public Builder removeRequestParameter(String expression) { - requestParameters.remove(expression); + requestParameters.get().remove(expression); return this; } @@ -606,7 +603,7 @@ public Builder removeRequestParameter(String expression) { * @see IntegrationTrait#getRequestTemplates() */ public Builder putRequestTemplate(String mimeType, String template) { - requestTemplates.put(mimeType, template); + requestTemplates.get().put(mimeType, template); return this; } @@ -619,7 +616,7 @@ public Builder putRequestTemplate(String mimeType, String template) { */ public Builder requestTemplates(Map requestTemplates) { this.requestTemplates.clear(); - this.requestTemplates.putAll(requestTemplates); + requestTemplates.forEach(this::putRequestTemplate); return this; } @@ -630,7 +627,7 @@ public Builder requestTemplates(Map requestTemplates) { * @return Returns the builder. */ public Builder removeRequestTemplate(String mimeType) { - requestTemplates.remove(mimeType); + requestTemplates.get().remove(mimeType); return this; } @@ -643,7 +640,7 @@ public Builder removeRequestTemplate(String mimeType) { * @see IntegrationTrait#getResponses() */ public Builder putResponse(String statusCodeRegex, IntegrationResponse integrationResponse) { - responses.put(statusCodeRegex, integrationResponse); + responses.get().put(statusCodeRegex, integrationResponse); return this; } @@ -656,7 +653,7 @@ public Builder putResponse(String statusCodeRegex, IntegrationResponse integrati */ public Builder responses(Map responses) { this.responses.clear(); - this.responses.putAll(responses); + responses.forEach(this::putResponse); return this; } @@ -667,7 +664,7 @@ public Builder responses(Map responses) { * @return Returns the builder. */ public Builder removeResponse(String statusCodeRegex) { - responses.remove(statusCodeRegex); + responses.get().remove(statusCodeRegex); return this; } } diff --git a/smithy-aws-apigateway-traits/src/main/java/software/amazon/smithy/aws/apigateway/traits/IntegrationTraitIndex.java b/smithy-aws-apigateway-traits/src/main/java/software/amazon/smithy/aws/apigateway/traits/IntegrationTraitIndex.java index e6b865b5be0..a567ccf873c 100644 --- a/smithy-aws-apigateway-traits/src/main/java/software/amazon/smithy/aws/apigateway/traits/IntegrationTraitIndex.java +++ b/smithy-aws-apigateway-traits/src/main/java/software/amazon/smithy/aws/apigateway/traits/IntegrationTraitIndex.java @@ -4,6 +4,7 @@ */ package software.amazon.smithy.aws.apigateway.traits; +import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Optional; @@ -15,7 +16,6 @@ import software.amazon.smithy.model.shapes.ShapeId; import software.amazon.smithy.model.shapes.ToShapeId; import software.amazon.smithy.model.traits.Trait; -import software.amazon.smithy.utils.MapUtils; /** * Computes the API Gateway integration for each operation, @@ -48,7 +48,7 @@ public static IntegrationTraitIndex of(Model model) { * @return The integration trait or an empty optional if none set */ public Optional getIntegrationTrait(ToShapeId service, ToShapeId shape) { - return Optional.ofNullable(traits.getOrDefault(service.toShapeId(), MapUtils.of()) + return Optional.ofNullable(traits.getOrDefault(service.toShapeId(), Collections.emptyMap()) .get(shape.toShapeId())); } diff --git a/smithy-aws-apigateway-traits/src/main/java/software/amazon/smithy/aws/apigateway/traits/MockIntegrationTrait.java b/smithy-aws-apigateway-traits/src/main/java/software/amazon/smithy/aws/apigateway/traits/MockIntegrationTrait.java index 34a48b3c6f9..045bef6cbfa 100644 --- a/smithy-aws-apigateway-traits/src/main/java/software/amazon/smithy/aws/apigateway/traits/MockIntegrationTrait.java +++ b/smithy-aws-apigateway-traits/src/main/java/software/amazon/smithy/aws/apigateway/traits/MockIntegrationTrait.java @@ -4,7 +4,6 @@ */ package software.amazon.smithy.aws.apigateway.traits; -import java.util.HashMap; import java.util.Map; import java.util.Optional; import software.amazon.smithy.model.node.Node; @@ -14,7 +13,7 @@ import software.amazon.smithy.model.traits.AbstractTrait; import software.amazon.smithy.model.traits.AbstractTraitBuilder; import software.amazon.smithy.model.traits.Trait; -import software.amazon.smithy.utils.MapUtils; +import software.amazon.smithy.utils.BuilderRef; import software.amazon.smithy.utils.ToSmithyBuilder; /** @@ -33,9 +32,9 @@ private MockIntegrationTrait(Builder builder) { super(ID, builder.getSourceLocation()); passThroughBehavior = builder.passThroughBehavior; contentHandling = builder.contentHandling; - requestParameters = MapUtils.copyOf(builder.requestParameters); - requestTemplates = MapUtils.copyOf(builder.requestTemplates); - responses = MapUtils.copyOf(builder.responses); + requestParameters = builder.requestParameters.copy(); + requestTemplates = builder.requestTemplates.copy(); + responses = builder.responses.copy(); } public static final class Provider extends AbstractTrait.Provider { @@ -165,9 +164,9 @@ public Builder toBuilder() { public static final class Builder extends AbstractTraitBuilder { private String passThroughBehavior; private String contentHandling; - private final Map requestParameters = new HashMap<>(); - private final Map requestTemplates = new HashMap<>(); - private final Map responses = new HashMap<>(); + private final BuilderRef> requestParameters = BuilderRef.forOrderedMap(); + private final BuilderRef> requestTemplates = BuilderRef.forOrderedMap(); + private final BuilderRef> responses = BuilderRef.forOrderedMap(); @Override public MockIntegrationTrait build() { @@ -218,7 +217,7 @@ public Builder contentHandling(String contentHandling) { * @see IntegrationTrait#getRequestParameters() */ public Builder putRequestParameter(String input, String output) { - requestParameters.put(input, output); + requestParameters.get().put(input, output); return this; } @@ -231,7 +230,7 @@ public Builder putRequestParameter(String input, String output) { */ public Builder requestParameters(Map requestParameters) { this.requestParameters.clear(); - this.requestParameters.putAll(requestParameters); + requestParameters.forEach(this::putRequestParameter); return this; } @@ -242,7 +241,7 @@ public Builder requestParameters(Map requestParameters) { * @return Returns the builder. */ public Builder removeRequestParameter(String expression) { - requestParameters.remove(expression); + requestParameters.get().remove(expression); return this; } @@ -255,7 +254,7 @@ public Builder removeRequestParameter(String expression) { * @see IntegrationTrait#getRequestTemplates() */ public Builder putRequestTemplate(String mimeType, String template) { - requestTemplates.put(mimeType, template); + requestTemplates.get().put(mimeType, template); return this; } @@ -268,7 +267,7 @@ public Builder putRequestTemplate(String mimeType, String template) { */ public Builder requestTemplates(Map requestTemplates) { this.requestTemplates.clear(); - this.requestTemplates.putAll(requestTemplates); + requestTemplates.forEach(this::putRequestTemplate); return this; } @@ -279,7 +278,7 @@ public Builder requestTemplates(Map requestTemplates) { * @return Returns the builder. */ public Builder removeRequestTemplate(String mimeType) { - requestTemplates.remove(mimeType); + requestTemplates.get().remove(mimeType); return this; } @@ -292,7 +291,7 @@ public Builder removeRequestTemplate(String mimeType) { * @see IntegrationTrait#getResponses() */ public Builder putResponse(String statusCodeRegex, IntegrationResponse integrationResponse) { - responses.put(statusCodeRegex, integrationResponse); + responses.get().put(statusCodeRegex, integrationResponse); return this; } @@ -305,7 +304,7 @@ public Builder putResponse(String statusCodeRegex, IntegrationResponse integrati */ public Builder responses(Map responses) { this.responses.clear(); - this.responses.putAll(responses); + responses.forEach(this::putResponse); return this; } @@ -316,7 +315,7 @@ public Builder responses(Map responses) { * @return Returns the builder. */ public Builder removeResponse(String statusCodeRegex) { - responses.remove(statusCodeRegex); + responses.get().remove(statusCodeRegex); return this; } } diff --git a/smithy-aws-cloudformation-traits/src/main/java/software/amazon/smithy/aws/cloudformation/traits/CfnResource.java b/smithy-aws-cloudformation-traits/src/main/java/software/amazon/smithy/aws/cloudformation/traits/CfnResource.java index d1a055beb0b..7ff5468ffca 100644 --- a/smithy-aws-cloudformation-traits/src/main/java/software/amazon/smithy/aws/cloudformation/traits/CfnResource.java +++ b/smithy-aws-cloudformation-traits/src/main/java/software/amazon/smithy/aws/cloudformation/traits/CfnResource.java @@ -4,10 +4,8 @@ */ package software.amazon.smithy.aws.cloudformation.traits; -import java.util.ArrayList; import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Optional; @@ -16,6 +14,7 @@ import java.util.function.Predicate; import java.util.stream.Collectors; import software.amazon.smithy.model.shapes.ShapeId; +import software.amazon.smithy.utils.BuilderRef; import software.amazon.smithy.utils.SmithyBuilder; import software.amazon.smithy.utils.ToSmithyBuilder; @@ -30,11 +29,11 @@ public final class CfnResource implements ToSmithyBuilder { private final List> additionalIdentifiers; private CfnResource(Builder builder) { - Map propertyDefinitions = new HashMap<>(builder.propertyDefinitions); - Map availableProperties = new HashMap<>(); - this.excludedProperties = Collections.unmodifiableSet(builder.excludedProperties); - this.primaryIdentifiers = Collections.unmodifiableSet(builder.primaryIdentifiers); - this.additionalIdentifiers = Collections.unmodifiableList(builder.additionalIdentifiers); + Map propertyDefinitions = new LinkedHashMap<>(builder.propertyDefinitions.copy()); + Map availableProperties = new LinkedHashMap<>(); + this.excludedProperties = builder.excludedProperties.copy(); + this.primaryIdentifiers = builder.primaryIdentifiers.copy(); + this.additionalIdentifiers = builder.additionalIdentifiers.copy(); // Pre-compute the properties available, cleaning up any exclusions. for (Map.Entry propertyDefinition : propertyDefinitions.entrySet()) { @@ -56,6 +55,7 @@ private CfnResource(Builder builder) { availableProperties.put(propertyDefinition.getKey(), propertyDefinition.getValue()); } } + } this.propertyDefinitions = Collections.unmodifiableMap(propertyDefinitions); @@ -204,19 +204,19 @@ public Builder toBuilder() { } public static final class Builder implements SmithyBuilder { - private final Map propertyDefinitions = new HashMap<>(); - private final Set excludedProperties = new HashSet<>(); - private final Set primaryIdentifiers = new HashSet<>(); - private final List> additionalIdentifiers = new ArrayList<>(); + private final BuilderRef> propertyDefinitions = BuilderRef.forOrderedMap(); + private final BuilderRef> excludedProperties = BuilderRef.forOrderedSet(); + private final BuilderRef> primaryIdentifiers = BuilderRef.forOrderedSet(); + private final BuilderRef>> additionalIdentifiers = BuilderRef.forList(); private Builder() {} public boolean hasPropertyDefinition(String propertyName) { - return propertyDefinitions.containsKey(propertyName); + return propertyDefinitions.peek().containsKey(propertyName); } public Builder putPropertyDefinition(String propertyName, CfnResourceProperty definition) { - propertyDefinitions.put(propertyName, definition); + propertyDefinitions.get().put(propertyName, definition); return this; } @@ -224,7 +224,7 @@ public Builder updatePropertyDefinition( String propertyName, Function updater ) { - CfnResourceProperty definition = propertyDefinitions.get(propertyName); + CfnResourceProperty definition = propertyDefinitions.get().get(propertyName); // Don't update if we don't have a property or it's already locked. if (definition == null || definition.hasExplicitMutability()) { @@ -236,40 +236,40 @@ public Builder updatePropertyDefinition( public Builder propertyDefinitions(Map propertyDefinitions) { this.propertyDefinitions.clear(); - this.propertyDefinitions.putAll(propertyDefinitions); + propertyDefinitions.forEach(this::putPropertyDefinition); return this; } public Builder addExcludedProperty(ShapeId excludedProperty) { - this.excludedProperties.add(excludedProperty); + this.excludedProperties.get().add(excludedProperty); return this; } public Builder excludedProperties(Set excludedProperties) { this.excludedProperties.clear(); - this.excludedProperties.addAll(excludedProperties); + excludedProperties.forEach(this::addExcludedProperty); return this; } public Builder addPrimaryIdentifier(String primaryIdentifier) { - this.primaryIdentifiers.add(primaryIdentifier); + this.primaryIdentifiers.get().add(primaryIdentifier); return this; } public Builder primaryIdentifiers(Set primaryIdentifiers) { this.primaryIdentifiers.clear(); - this.primaryIdentifiers.addAll(primaryIdentifiers); + primaryIdentifiers.forEach(this::addPrimaryIdentifier); return this; } public Builder addAdditionalIdentifier(Set additionalIdentifier) { - this.additionalIdentifiers.add(additionalIdentifier); + this.additionalIdentifiers.get().add(additionalIdentifier); return this; } public Builder additionalIdentifiers(List> additionalIdentifiers) { this.additionalIdentifiers.clear(); - this.additionalIdentifiers.addAll(additionalIdentifiers); + additionalIdentifiers.forEach(this::addAdditionalIdentifier); return this; } diff --git a/smithy-aws-cloudformation-traits/src/main/java/software/amazon/smithy/aws/cloudformation/traits/CfnResourceProperty.java b/smithy-aws-cloudformation-traits/src/main/java/software/amazon/smithy/aws/cloudformation/traits/CfnResourceProperty.java index e7ac6174182..4563e696a78 100644 --- a/smithy-aws-cloudformation-traits/src/main/java/software/amazon/smithy/aws/cloudformation/traits/CfnResourceProperty.java +++ b/smithy-aws-cloudformation-traits/src/main/java/software/amazon/smithy/aws/cloudformation/traits/CfnResourceProperty.java @@ -4,12 +4,11 @@ */ package software.amazon.smithy.aws.cloudformation.traits; -import java.util.HashSet; import java.util.Set; import java.util.TreeSet; import software.amazon.smithy.aws.cloudformation.traits.CfnResourceIndex.Mutability; import software.amazon.smithy.model.shapes.ShapeId; -import software.amazon.smithy.utils.SetUtils; +import software.amazon.smithy.utils.BuilderRef; import software.amazon.smithy.utils.SmithyBuilder; import software.amazon.smithy.utils.ToSmithyBuilder; @@ -17,13 +16,13 @@ * Contains extracted resource property information. */ public final class CfnResourceProperty implements ToSmithyBuilder { - private final Set shapeIds = new TreeSet<>(); + private final Set shapeIds; private final Set mutabilities; private final boolean hasExplicitMutability; private CfnResourceProperty(Builder builder) { - shapeIds.addAll(builder.shapeIds); - mutabilities = SetUtils.copyOf(builder.mutabilities); + shapeIds = new TreeSet<>(builder.shapeIds.peek()); + mutabilities = builder.mutabilities.copy(); hasExplicitMutability = builder.hasExplicitMutability; } @@ -84,8 +83,8 @@ public Builder toBuilder() { } public static final class Builder implements SmithyBuilder { - private final Set shapeIds = new TreeSet<>(); - private Set mutabilities = new HashSet<>(); + private final BuilderRef> shapeIds = BuilderRef.forSortedSet(); + private final BuilderRef> mutabilities = BuilderRef.forUnorderedSet(); private boolean hasExplicitMutability = false; @Override @@ -94,23 +93,24 @@ public CfnResourceProperty build() { } public Builder addShapeId(ShapeId shapeId) { - this.shapeIds.add(shapeId); + this.shapeIds.get().add(shapeId); return this; } public Builder removeShapeId(ShapeId shapeId) { - this.shapeIds.remove(shapeId); + this.shapeIds.get().remove(shapeId); return this; } public Builder shapeIds(Set shapeIds) { this.shapeIds.clear(); - this.shapeIds.addAll(shapeIds); + shapeIds.forEach(this::addShapeId); return this; } public Builder mutabilities(Set mutabilities) { - this.mutabilities = mutabilities; + this.mutabilities.clear(); + this.mutabilities.get().addAll(mutabilities); return this; } diff --git a/smithy-aws-cloudformation-traits/src/main/java/software/amazon/smithy/aws/cloudformation/traits/CfnResourceTrait.java b/smithy-aws-cloudformation-traits/src/main/java/software/amazon/smithy/aws/cloudformation/traits/CfnResourceTrait.java index 952396530d4..2065029e149 100644 --- a/smithy-aws-cloudformation-traits/src/main/java/software/amazon/smithy/aws/cloudformation/traits/CfnResourceTrait.java +++ b/smithy-aws-cloudformation-traits/src/main/java/software/amazon/smithy/aws/cloudformation/traits/CfnResourceTrait.java @@ -4,7 +4,6 @@ */ package software.amazon.smithy.aws.cloudformation.traits; -import java.util.ArrayList; import java.util.List; import java.util.Optional; import software.amazon.smithy.model.node.Node; @@ -13,7 +12,7 @@ import software.amazon.smithy.model.traits.AbstractTrait; import software.amazon.smithy.model.traits.AbstractTraitBuilder; import software.amazon.smithy.model.traits.Trait; -import software.amazon.smithy.utils.ListUtils; +import software.amazon.smithy.utils.BuilderRef; import software.amazon.smithy.utils.ToSmithyBuilder; /** @@ -30,7 +29,7 @@ public final class CfnResourceTrait extends AbstractTrait private CfnResourceTrait(Builder builder) { super(ID, builder.getSourceLocation()); name = builder.name; - additionalSchemas = ListUtils.copyOf(builder.additionalSchemas); + additionalSchemas = builder.additionalSchemas.copy(); primaryIdentifier = builder.primaryIdentifier; } @@ -93,7 +92,7 @@ public Trait createTrait(ShapeId target, Node value) { public static final class Builder extends AbstractTraitBuilder { private String name; - private final List additionalSchemas = new ArrayList<>(); + private final BuilderRef> additionalSchemas = BuilderRef.forList(); private String primaryIdentifier; private Builder() {} @@ -109,13 +108,13 @@ public Builder name(String name) { } public Builder addAdditionalSchema(ShapeId additionalSchema) { - this.additionalSchemas.add(additionalSchema); + this.additionalSchemas.get().add(additionalSchema); return this; } public Builder additionalSchemas(List additionalSchemas) { this.additionalSchemas.clear(); - this.additionalSchemas.addAll(additionalSchemas); + additionalSchemas.forEach(this::addAdditionalSchema); return this; } diff --git a/smithy-aws-cloudformation/src/main/java/software/amazon/smithy/aws/cloudformation/schema/model/Handler.java b/smithy-aws-cloudformation/src/main/java/software/amazon/smithy/aws/cloudformation/schema/model/Handler.java index 17756bb5e3b..f90bcda8766 100644 --- a/smithy-aws-cloudformation/src/main/java/software/amazon/smithy/aws/cloudformation/schema/model/Handler.java +++ b/smithy-aws-cloudformation/src/main/java/software/amazon/smithy/aws/cloudformation/schema/model/Handler.java @@ -7,12 +7,11 @@ import java.util.Collection; import java.util.Map; import java.util.Set; -import java.util.TreeSet; import software.amazon.smithy.model.node.Node; import software.amazon.smithy.model.node.NodeMapper; import software.amazon.smithy.model.node.ToNode; +import software.amazon.smithy.utils.BuilderRef; import software.amazon.smithy.utils.MapUtils; -import software.amazon.smithy.utils.SetUtils; import software.amazon.smithy.utils.SmithyBuilder; import software.amazon.smithy.utils.ToSmithyBuilder; @@ -43,7 +42,7 @@ public final class Handler implements ToNode, ToSmithyBuilder { private final Set permissions; private Handler(Builder builder) { - this.permissions = SetUtils.orderedCopyOf(builder.permissions); + this.permissions = builder.permissions.copy(); } @Override @@ -73,7 +72,7 @@ public static Integer getHandlerNameOrder(String name) { } public static final class Builder implements SmithyBuilder { - private final Set permissions = new TreeSet<>(); + private final BuilderRef> permissions = BuilderRef.forSortedSet(); private Builder() {} @@ -84,12 +83,12 @@ public Handler build() { public Builder permissions(Collection permissions) { this.permissions.clear(); - this.permissions.addAll(permissions); + permissions.forEach(this::addPermission); return this; } public Builder addPermission(String permission) { - this.permissions.add(permission); + this.permissions.get().add(permission); return this; } diff --git a/smithy-aws-cloudformation/src/main/java/software/amazon/smithy/aws/cloudformation/schema/model/Property.java b/smithy-aws-cloudformation/src/main/java/software/amazon/smithy/aws/cloudformation/schema/model/Property.java index 72ae541c31d..b35b2fe25a3 100644 --- a/smithy-aws-cloudformation/src/main/java/software/amazon/smithy/aws/cloudformation/schema/model/Property.java +++ b/smithy-aws-cloudformation/src/main/java/software/amazon/smithy/aws/cloudformation/schema/model/Property.java @@ -4,7 +4,6 @@ */ package software.amazon.smithy.aws.cloudformation.schema.model; -import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Optional; @@ -13,6 +12,7 @@ import software.amazon.smithy.model.node.ObjectNode; import software.amazon.smithy.model.node.StringNode; import software.amazon.smithy.model.node.ToNode; +import software.amazon.smithy.utils.BuilderRef; import software.amazon.smithy.utils.SmithyBuilder; import software.amazon.smithy.utils.ToSmithyBuilder; @@ -42,8 +42,8 @@ private Property(Builder builder) { schemaBuilder.putExtension("insertionOrder", Node.from(true)); } - if (!builder.dependencies.isEmpty()) { - schemaBuilder.putExtension("dependencies", Node.fromStrings(builder.dependencies)); + if (!builder.dependencies.peek().isEmpty()) { + schemaBuilder.putExtension("dependencies", Node.fromStrings(builder.dependencies.peek())); } this.schema = schemaBuilder.build(); @@ -95,7 +95,7 @@ public Schema getSchema() { public static final class Builder implements SmithyBuilder { private boolean insertionOrder = false; - private final List dependencies = new ArrayList<>(); + private final BuilderRef> dependencies = BuilderRef.forList(); private Schema schema; private Builder() {} @@ -112,12 +112,12 @@ public Builder insertionOrder(boolean insertionOrder) { public Builder dependencies(List dependencies) { this.dependencies.clear(); - this.dependencies.addAll(dependencies); + dependencies.forEach(this::addDependency); return this; } public Builder addDependency(String dependency) { - this.dependencies.add(dependency); + this.dependencies.get().add(dependency); return this; } diff --git a/smithy-aws-cloudformation/src/main/java/software/amazon/smithy/aws/cloudformation/schema/model/Remote.java b/smithy-aws-cloudformation/src/main/java/software/amazon/smithy/aws/cloudformation/schema/model/Remote.java index c5b53b5e9ef..3510cc48085 100644 --- a/smithy-aws-cloudformation/src/main/java/software/amazon/smithy/aws/cloudformation/schema/model/Remote.java +++ b/smithy-aws-cloudformation/src/main/java/software/amazon/smithy/aws/cloudformation/schema/model/Remote.java @@ -11,6 +11,7 @@ import software.amazon.smithy.model.node.NodeMapper; import software.amazon.smithy.model.node.ObjectNode; import software.amazon.smithy.model.node.ToNode; +import software.amazon.smithy.utils.BuilderRef; import software.amazon.smithy.utils.SmithyBuilder; import software.amazon.smithy.utils.ToSmithyBuilder; @@ -21,12 +22,12 @@ * @see Resource Type Remote JSON Schema */ public final class Remote implements ToNode, ToSmithyBuilder { - private final Map definitions = new TreeMap<>(); - private final Map properties = new TreeMap<>(); + private final Map definitions; + private final Map properties; private Remote(Builder builder) { - properties.putAll(builder.properties); - definitions.putAll(builder.definitions); + definitions = new TreeMap<>(builder.definitions.copy()); + properties = new TreeMap<>(builder.properties.copy()); } @Override @@ -65,8 +66,8 @@ public Map getProperties() { } public static final class Builder implements SmithyBuilder { - private final Map definitions = new TreeMap<>(); - private final Map properties = new TreeMap<>(); + private final BuilderRef> definitions = BuilderRef.forSortedMap(); + private final BuilderRef> properties = BuilderRef.forSortedMap(); private Builder() {} @@ -77,17 +78,17 @@ public Remote build() { public Builder definitions(Map definitions) { this.definitions.clear(); - this.definitions.putAll(definitions); + definitions.forEach(this::addDefinition); return this; } public Builder addDefinition(String name, Schema definition) { - this.definitions.put(name, definition); + this.definitions.get().put(name, definition); return this; } public Builder removeDefinition(String name) { - this.definitions.remove(name); + this.definitions.get().remove(name); return this; } @@ -98,17 +99,17 @@ public Builder clearDefinitions() { public Builder properties(Map properties) { this.properties.clear(); - this.properties.putAll(properties); + properties.forEach(this::addProperty); return this; } public Builder addProperty(String name, Property property) { - this.properties.put(name, property); + this.properties.get().put(name, property); return this; } public Builder removeProperty(String name) { - this.properties.remove(name); + this.properties.get().remove(name); return this; } diff --git a/smithy-aws-cloudformation/src/main/java/software/amazon/smithy/aws/cloudformation/schema/model/ResourceSchema.java b/smithy-aws-cloudformation/src/main/java/software/amazon/smithy/aws/cloudformation/schema/model/ResourceSchema.java index cef86775b73..8d9eb174f86 100644 --- a/smithy-aws-cloudformation/src/main/java/software/amazon/smithy/aws/cloudformation/schema/model/ResourceSchema.java +++ b/smithy-aws-cloudformation/src/main/java/software/amazon/smithy/aws/cloudformation/schema/model/ResourceSchema.java @@ -6,7 +6,6 @@ import static java.lang.String.format; -import java.util.ArrayList; import java.util.Collection; import java.util.Comparator; import java.util.List; @@ -21,7 +20,7 @@ import software.amazon.smithy.model.node.NodeMapper; import software.amazon.smithy.model.node.ObjectNode; import software.amazon.smithy.model.node.ToNode; -import software.amazon.smithy.utils.ListUtils; +import software.amazon.smithy.utils.BuilderRef; import software.amazon.smithy.utils.SmithyBuilder; import software.amazon.smithy.utils.ToSmithyBuilder; @@ -36,18 +35,17 @@ public final class ResourceSchema implements ToNode, ToSmithyBuilder definitions = new TreeMap<>(); - private final Map properties = new TreeMap<>(); - private final Set required = new TreeSet<>(); - private final Set readOnlyProperties = new TreeSet<>(); - private final Set writeOnlyProperties = new TreeSet<>(); - private final Set primaryIdentifier = new TreeSet<>(); - private final Set createOnlyProperties = new TreeSet<>(); - private final Set deprecatedProperties = new TreeSet<>(); + private final Map definitions; + private final Map properties; + private final Set required; + private final Set readOnlyProperties; + private final Set writeOnlyProperties; + private final Set primaryIdentifier; + private final Set createOnlyProperties; + private final Set deprecatedProperties; private final List> additionalIdentifiers; - // Use a custom comparator to keep the Handler outputs in CRUDL order. - private final Map handlers = new TreeMap<>(Comparator.comparing(Handler::getHandlerNameOrder)); - private final Map remotes = new TreeMap<>(); + private final Map handlers; + private final Map remotes; private final Tagging tagging; private final Schema additionalProperties; @@ -55,24 +53,24 @@ private ResourceSchema(Builder builder) { typeName = SmithyBuilder.requiredState("typeName", builder.typeName); description = SmithyBuilder.requiredState("description", builder.description); - if (builder.properties.isEmpty()) { + if (builder.properties.peek().isEmpty()) { throw new CfnException(format("Expected CloudFormation resource %s to have properties, " + "found none", typeName)); } - properties.putAll(builder.properties); + properties = new TreeMap<>(builder.properties.peek()); - required.addAll(builder.required); + required = new TreeSet<>(builder.required.copy()); sourceUrl = builder.sourceUrl; documentationUrl = builder.documentationUrl; - definitions.putAll(builder.definitions); - readOnlyProperties.addAll(builder.readOnlyProperties); - writeOnlyProperties.addAll(builder.writeOnlyProperties); - primaryIdentifier.addAll(builder.primaryIdentifier); - createOnlyProperties.addAll(builder.createOnlyProperties); - deprecatedProperties.addAll(builder.deprecatedProperties); - additionalIdentifiers = ListUtils.copyOf(builder.additionalIdentifiers); - handlers.putAll(builder.handlers); - remotes.putAll(builder.remotes); + definitions = new TreeMap<>(builder.definitions.peek()); + readOnlyProperties = new TreeSet<>(builder.readOnlyProperties.peek()); + writeOnlyProperties = new TreeSet<>(builder.writeOnlyProperties.peek()); + primaryIdentifier = new TreeSet<>(builder.primaryIdentifier.peek()); + createOnlyProperties = new TreeSet<>(builder.createOnlyProperties.peek()); + deprecatedProperties = new TreeSet<>(builder.deprecatedProperties.peek()); + additionalIdentifiers = builder.additionalIdentifiers.copy(); + handlers = new TreeMap<>(builder.handlers.peek()); + remotes = new TreeMap<>(builder.remotes.peek()); tagging = builder.tagging; additionalProperties = builder.additionalProperties; } @@ -237,17 +235,20 @@ public static final class Builder implements SmithyBuilder { private String description; private String sourceUrl; private String documentationUrl; - private final Map definitions = new TreeMap<>(); - private final Map properties = new TreeMap<>(); - private final Set required = new TreeSet<>(); - private final Set readOnlyProperties = new TreeSet<>(); - private final Set writeOnlyProperties = new TreeSet<>(); - private final Set primaryIdentifier = new TreeSet<>(); - private final Set createOnlyProperties = new TreeSet<>(); - private final Set deprecatedProperties = new TreeSet<>(); - private final List> additionalIdentifiers = new ArrayList<>(); - private final Map handlers = new TreeMap<>(); - private final Map remotes = new TreeMap<>(); + private final BuilderRef> definitions = BuilderRef.forSortedMap(); + private final BuilderRef> properties = BuilderRef.forSortedMap(); + private final BuilderRef> required = BuilderRef.forSortedSet(); + private final BuilderRef> readOnlyProperties = BuilderRef.forSortedSet(); + private final BuilderRef> writeOnlyProperties = BuilderRef.forSortedSet(); + private final BuilderRef> primaryIdentifier = BuilderRef.forSortedSet(); + private final BuilderRef> createOnlyProperties = BuilderRef.forSortedSet(); + private final BuilderRef> deprecatedProperties = BuilderRef.forSortedSet(); + private final BuilderRef>> additionalIdentifiers = BuilderRef.forList(); + + // Use a custom comparator to keep the Handler outputs in CRUDL order. + private final BuilderRef> handlers = BuilderRef.forSortedMap( + Comparator.comparing(Handler::getHandlerNameOrder)); + private final BuilderRef> remotes = BuilderRef.forSortedMap(); private Tagging tagging; private Schema additionalProperties; @@ -280,17 +281,17 @@ public Builder documentationUrl(String documentationUrl) { public Builder definitions(Map definitions) { this.definitions.clear(); - this.definitions.putAll(definitions); + definitions.forEach(this::addDefinition); return this; } public Builder addDefinition(String name, Schema definition) { - this.definitions.put(name, definition); + this.definitions.get().put(name, definition); return this; } public Builder removeDefinition(String name) { - this.definitions.remove(name); + this.definitions.get().remove(name); return this; } @@ -301,17 +302,17 @@ public Builder clearDefinitions() { public Builder properties(Map properties) { this.properties.clear(); - this.properties.putAll(properties); + properties.forEach(this::addProperty); return this; } public Builder addProperty(String name, Property property) { - this.properties.put(name, property); + this.properties.get().put(name, property); return this; } public Builder removeProperty(String name) { - this.properties.remove(name); + this.properties.get().remove(name); return this; } @@ -322,17 +323,17 @@ public Builder clearProperties() { public Builder required(Collection required) { this.required.clear(); - this.required.addAll(required); + required.forEach(this::addRequired); return this; } public Builder addRequired(String required) { - this.required.add(required); + this.required.get().add(required); return this; } public Builder removeRequired(String required) { - this.required.remove(required); + this.required.get().remove(required); return this; } @@ -342,13 +343,13 @@ public Builder clearRequired() { } public Builder addReadOnlyProperty(String propertyRef) { - this.readOnlyProperties.add(propertyRef); + this.readOnlyProperties.get().add(propertyRef); return this; } public Builder readOnlyProperties(Collection readOnlyProperties) { this.readOnlyProperties.clear(); - this.readOnlyProperties.addAll(readOnlyProperties); + readOnlyProperties.forEach(this::addReadOnlyProperty); return this; } @@ -358,13 +359,13 @@ public Builder clearReadOnlyProperties() { } public Builder addWriteOnlyProperty(String propertyRef) { - this.writeOnlyProperties.add(propertyRef); + this.writeOnlyProperties.get().add(propertyRef); return this; } public Builder writeOnlyProperties(Collection writeOnlyProperties) { this.writeOnlyProperties.clear(); - this.writeOnlyProperties.addAll(writeOnlyProperties); + writeOnlyProperties.forEach(this::addWriteOnlyProperty); return this; } @@ -375,7 +376,7 @@ public Builder clearWriteOnlyProperties() { public Builder primaryIdentifier(Collection primaryIdentifier) { this.primaryIdentifier.clear(); - this.primaryIdentifier.addAll(primaryIdentifier); + this.primaryIdentifier.get().addAll(primaryIdentifier); return this; } @@ -385,13 +386,13 @@ public Builder clearPrimaryIdentifier() { } public Builder addCreateOnlyProperty(String propertyRef) { - this.createOnlyProperties.add(propertyRef); + this.createOnlyProperties.get().add(propertyRef); return this; } public Builder createOnlyProperties(Collection createOnlyProperties) { this.createOnlyProperties.clear(); - this.createOnlyProperties.addAll(createOnlyProperties); + createOnlyProperties.forEach(this::addCreateOnlyProperty); return this; } @@ -401,13 +402,13 @@ public Builder clearCreateOnlyProperties() { } public Builder addDeprecatedProperty(String propertyRef) { - this.deprecatedProperties.add(propertyRef); + this.deprecatedProperties.get().add(propertyRef); return this; } public Builder deprecatedProperties(Collection deprecatedProperties) { this.deprecatedProperties.clear(); - this.deprecatedProperties.addAll(deprecatedProperties); + deprecatedProperties.forEach(this::addDeprecatedProperty); return this; } @@ -417,13 +418,13 @@ public Builder clearDeprecatedProperties() { } public Builder addAdditionalIdentifier(List additionalIdentifier) { - this.additionalIdentifiers.add(additionalIdentifier); + this.additionalIdentifiers.get().add(additionalIdentifier); return this; } public Builder additionalIdentifiers(List> additionalIdentifiers) { this.additionalIdentifiers.clear(); - this.additionalIdentifiers.addAll(additionalIdentifiers); + additionalIdentifiers.forEach(this::addAdditionalIdentifier); return this; } @@ -434,17 +435,17 @@ public Builder clearAdditionalIdentifiers() { public Builder handlers(Map handlers) { this.handlers.clear(); - this.handlers.putAll(handlers); + handlers.forEach(this::addHandler); return this; } public Builder addHandler(String name, Handler handler) { - this.handlers.put(name, handler); + this.handlers.get().put(name, handler); return this; } public Builder removeHandler(String name) { - this.handlers.remove(name); + this.handlers.get().remove(name); return this; } @@ -455,7 +456,7 @@ public Builder clearHandlers() { public Builder remotes(Map remotes) { this.remotes.clear(); - this.remotes.putAll(remotes); + remotes.forEach(this::addRemote); return this; } @@ -465,12 +466,12 @@ public Builder tagging(Tagging tagging) { } public Builder addRemote(String name, Remote remote) { - this.remotes.put(name, remote); + this.remotes.get().put(name, remote); return this; } public Builder removeRemote(String name) { - this.remotes.remove(name); + this.remotes.get().remove(name); return this; } diff --git a/smithy-aws-cloudformation/src/main/java/software/amazon/smithy/aws/cloudformation/schema/model/Tagging.java b/smithy-aws-cloudformation/src/main/java/software/amazon/smithy/aws/cloudformation/schema/model/Tagging.java index 195ac77d540..623e01fd016 100644 --- a/smithy-aws-cloudformation/src/main/java/software/amazon/smithy/aws/cloudformation/schema/model/Tagging.java +++ b/smithy-aws-cloudformation/src/main/java/software/amazon/smithy/aws/cloudformation/schema/model/Tagging.java @@ -6,8 +6,7 @@ import java.util.Collection; import java.util.Set; -import java.util.TreeSet; -import software.amazon.smithy.utils.SetUtils; +import software.amazon.smithy.utils.BuilderRef; import software.amazon.smithy.utils.SmithyBuilder; import software.amazon.smithy.utils.ToSmithyBuilder; @@ -28,7 +27,7 @@ private Tagging(Builder builder) { tagUpdatable = builder.tagUpdatable; cloudFormationSystemTags = builder.cloudFormationSystemTags; tagProperty = builder.tagProperty; - this.permissions = SetUtils.orderedCopyOf(builder.permissions); + this.permissions = builder.permissions.copy(); } public static Builder builder() { @@ -106,7 +105,7 @@ public static final class Builder implements SmithyBuilder { private boolean tagUpdatable; private boolean cloudFormationSystemTags; private String tagProperty; - private final Set permissions = new TreeSet<>(); + private final BuilderRef> permissions = BuilderRef.forSortedSet(); @Override public Tagging build() { @@ -140,7 +139,7 @@ public Builder tagProperty(String tagProperty) { public Builder permissions(Collection permissions) { this.permissions.clear(); - this.permissions.addAll(permissions); + permissions.forEach(this::addPermission); return this; } @@ -152,7 +151,7 @@ public Builder addPermissions(Collection permissions) { } public Builder addPermission(String permission) { - this.permissions.add(permission); + this.permissions.get().add(permission); return this; } diff --git a/smithy-aws-iam-traits/src/main/java/software/amazon/smithy/aws/iam/traits/DefineConditionKeysTrait.java b/smithy-aws-iam-traits/src/main/java/software/amazon/smithy/aws/iam/traits/DefineConditionKeysTrait.java index 1e7398d30d6..9b1841e0cdc 100644 --- a/smithy-aws-iam-traits/src/main/java/software/amazon/smithy/aws/iam/traits/DefineConditionKeysTrait.java +++ b/smithy-aws-iam-traits/src/main/java/software/amazon/smithy/aws/iam/traits/DefineConditionKeysTrait.java @@ -4,7 +4,6 @@ */ package software.amazon.smithy.aws.iam.traits; -import java.util.HashMap; import java.util.Map; import java.util.Optional; import software.amazon.smithy.model.node.Node; @@ -14,7 +13,7 @@ import software.amazon.smithy.model.traits.AbstractTrait; import software.amazon.smithy.model.traits.AbstractTraitBuilder; import software.amazon.smithy.model.traits.Trait; -import software.amazon.smithy.utils.MapUtils; +import software.amazon.smithy.utils.BuilderRef; import software.amazon.smithy.utils.ToSmithyBuilder; /** @@ -27,7 +26,7 @@ public final class DefineConditionKeysTrait extends AbstractTrait implements ToS private DefineConditionKeysTrait(Builder builder) { super(ID, builder.getSourceLocation()); - conditionKeys = MapUtils.copyOf(builder.conditionKeys); + conditionKeys = builder.conditionKeys.copy(); } public static Builder builder() { @@ -89,7 +88,7 @@ public Builder toBuilder() { } public static final class Builder extends AbstractTraitBuilder { - private final Map conditionKeys = new HashMap<>(); + private final BuilderRef> conditionKeys = BuilderRef.forOrderedMap(); private Builder() {} @@ -99,12 +98,12 @@ public DefineConditionKeysTrait build() { } public Builder putConditionKey(String name, ConditionKeyDefinition definition) { - conditionKeys.put(name, definition); + conditionKeys.get().put(name, definition); return this; } public Builder removeConditionKey(String name) { - conditionKeys.remove(name); + conditionKeys.get().remove(name); return this; } } diff --git a/smithy-build/src/main/java/software/amazon/smithy/build/PluginContext.java b/smithy-build/src/main/java/software/amazon/smithy/build/PluginContext.java index c6d10dd0e49..0497197692e 100644 --- a/smithy-build/src/main/java/software/amazon/smithy/build/PluginContext.java +++ b/smithy-build/src/main/java/software/amazon/smithy/build/PluginContext.java @@ -268,7 +268,7 @@ public static final class Builder implements SmithyBuilder { private ObjectNode settings = Node.objectNode(); private FileManifest fileManifest; private ClassLoader pluginClassLoader; - private BuilderRef> sources = BuilderRef.forOrderedSet(); + private final BuilderRef> sources = BuilderRef.forOrderedSet(); private String artifactName; private Builder() {} diff --git a/smithy-build/src/main/java/software/amazon/smithy/build/TransformContext.java b/smithy-build/src/main/java/software/amazon/smithy/build/TransformContext.java index cd992c119de..1acf6c90e87 100644 --- a/smithy-build/src/main/java/software/amazon/smithy/build/TransformContext.java +++ b/smithy-build/src/main/java/software/amazon/smithy/build/TransformContext.java @@ -144,7 +144,7 @@ public static final class Builder implements SmithyBuilder { private ObjectNode settings = Node.objectNode(); private Model model; private Model originalModel; - private BuilderRef> sources = BuilderRef.forOrderedSet(); + private final BuilderRef> sources = BuilderRef.forOrderedSet(); private String projectionName = "source"; private ModelTransformer transformer; private final BuilderRef> originalModelValidationEvents = BuilderRef.forList(); diff --git a/smithy-codegen-core/src/main/java/software/amazon/smithy/codegen/core/MappedReservedWords.java b/smithy-codegen-core/src/main/java/software/amazon/smithy/codegen/core/MappedReservedWords.java index b7e969dca8f..d6fb6dc9726 100644 --- a/smithy-codegen-core/src/main/java/software/amazon/smithy/codegen/core/MappedReservedWords.java +++ b/smithy-codegen-core/src/main/java/software/amazon/smithy/codegen/core/MappedReservedWords.java @@ -4,9 +4,9 @@ */ package software.amazon.smithy.codegen.core; -import java.util.HashMap; import java.util.Locale; import java.util.Map; +import software.amazon.smithy.utils.BuilderRef; import software.amazon.smithy.utils.MapUtils; import software.amazon.smithy.utils.SmithyBuilder; @@ -56,6 +56,11 @@ public MappedReservedWords(Map mappings, Map cas this.caseInsensitiveMappings = MapUtils.copyOf(caseInsensitiveMappings); } + private MappedReservedWords(Builder builder) { + this.mappings = builder.mappings.copy(); + this.caseInsensitiveMappings = builder.caseInsensitiveMappings.copy(); + } + /** * @return Creates a new Builder. */ @@ -87,8 +92,8 @@ public boolean isReserved(String word) { * Builder to create a new {@link MappedReservedWords} instance. */ public static final class Builder implements SmithyBuilder { - private final Map mappings = new HashMap<>(); - private final Map caseInsensitiveMappings = new HashMap<>(); + private final BuilderRef> mappings = BuilderRef.forUnorderedMap(); + private final BuilderRef> caseInsensitiveMappings = BuilderRef.forUnorderedMap(); private Builder() {} @@ -100,7 +105,7 @@ private Builder() {} * @return Returns the builder. */ public Builder put(String reservedWord, String conversion) { - mappings.put(reservedWord, conversion); + mappings.get().put(reservedWord, conversion); return this; } @@ -118,7 +123,7 @@ public Builder put(String reservedWord, String conversion) { * @return Returns the builder. */ public Builder putCaseInsensitive(String reservedWord, String conversion) { - caseInsensitiveMappings.put(reservedWord.toLowerCase(Locale.US), conversion); + caseInsensitiveMappings.get().put(reservedWord.toLowerCase(Locale.US), conversion); return this; } @@ -129,7 +134,7 @@ public Builder putCaseInsensitive(String reservedWord, String conversion) { */ @Override public ReservedWords build() { - return new MappedReservedWords(mappings, caseInsensitiveMappings); + return new MappedReservedWords(this); } } } diff --git a/smithy-codegen-core/src/main/java/software/amazon/smithy/codegen/core/trace/ArtifactDefinitions.java b/smithy-codegen-core/src/main/java/software/amazon/smithy/codegen/core/trace/ArtifactDefinitions.java index ef3a7db3fc8..12ab3d8ea98 100644 --- a/smithy-codegen-core/src/main/java/software/amazon/smithy/codegen/core/trace/ArtifactDefinitions.java +++ b/smithy-codegen-core/src/main/java/software/amazon/smithy/codegen/core/trace/ArtifactDefinitions.java @@ -4,13 +4,12 @@ */ package software.amazon.smithy.codegen.core.trace; -import java.util.HashMap; import java.util.Map; import software.amazon.smithy.model.node.Node; import software.amazon.smithy.model.node.NodeMapper; import software.amazon.smithy.model.node.ObjectNode; import software.amazon.smithy.model.node.ToNode; -import software.amazon.smithy.utils.MapUtils; +import software.amazon.smithy.utils.BuilderRef; import software.amazon.smithy.utils.SmithyBuilder; import software.amazon.smithy.utils.ToSmithyBuilder; @@ -25,14 +24,14 @@ public final class ArtifactDefinitions implements ToNode, ToSmithyBuilder types; private ArtifactDefinitions(Builder builder) { - if (builder.tags.isEmpty()) { + if (builder.tags.peek().isEmpty()) { throw new IllegalStateException("ArtifactDefinition's Tags field must not be empty."); } - if (builder.types.isEmpty()) { + if (builder.types.peek().isEmpty()) { throw new IllegalStateException("ArtifactDefinition's Types field must not be empty."); } - tags = MapUtils.copyOf(builder.tags); - types = MapUtils.copyOf(builder.types); + tags = builder.tags.copy(); + types = builder.types.copy(); } /** @@ -108,8 +107,8 @@ public Builder toBuilder() { } public static final class Builder implements SmithyBuilder { - private final Map tags = new HashMap<>(); - private final Map types = new HashMap<>(); + private final BuilderRef> tags = BuilderRef.forUnorderedMap(); + private final BuilderRef> types = BuilderRef.forUnorderedMap(); /** * @return Definitions object from this builder. @@ -120,13 +119,13 @@ public ArtifactDefinitions build() { public Builder tags(Map tags) { this.tags.clear(); - this.tags.putAll(tags); + tags.forEach(this::addTag); return this; } public Builder types(Map types) { this.types.clear(); - this.types.putAll(types); + types.forEach(this::addType); return this; } @@ -138,7 +137,7 @@ public Builder types(Map types) { * @return This builder. */ public Builder addTag(String name, String description) { - this.tags.put(name, description); + this.tags.get().put(name, description); return this; } @@ -150,7 +149,7 @@ public Builder addTag(String name, String description) { * @return This builder. */ public Builder addType(String name, String description) { - this.types.put(name, description); + this.types.get().put(name, description); return this; } diff --git a/smithy-codegen-core/src/main/java/software/amazon/smithy/codegen/core/trace/ShapeLink.java b/smithy-codegen-core/src/main/java/software/amazon/smithy/codegen/core/trace/ShapeLink.java index cbf1eb8d18e..2695e64aec7 100644 --- a/smithy-codegen-core/src/main/java/software/amazon/smithy/codegen/core/trace/ShapeLink.java +++ b/smithy-codegen-core/src/main/java/software/amazon/smithy/codegen/core/trace/ShapeLink.java @@ -4,14 +4,13 @@ */ package software.amazon.smithy.codegen.core.trace; -import java.util.ArrayList; import java.util.List; import java.util.Optional; import software.amazon.smithy.model.node.Node; import software.amazon.smithy.model.node.NodeMapper; import software.amazon.smithy.model.node.ObjectNode; import software.amazon.smithy.model.node.ToNode; -import software.amazon.smithy.utils.ListUtils; +import software.amazon.smithy.utils.BuilderRef; import software.amazon.smithy.utils.SmithyBuilder; import software.amazon.smithy.utils.ToSmithyBuilder; @@ -37,7 +36,7 @@ public final class ShapeLink implements ToNode, ToSmithyBuilder { private ShapeLink(Builder builder) { type = SmithyBuilder.requiredState(TYPE_TEXT, builder.type); id = SmithyBuilder.requiredState(ID_TEXT, builder.id); - tags = ListUtils.copyOf(builder.tags); + tags = builder.tags.copy(); file = builder.file; line = builder.line; column = builder.column; @@ -165,7 +164,7 @@ public Builder toBuilder() { } public static final class Builder implements SmithyBuilder { - private final List tags = new ArrayList<>(); + private final BuilderRef> tags = BuilderRef.forList(); private String type; private String id; private String file; @@ -194,7 +193,7 @@ public Builder id(String id) { */ public Builder tags(List tags) { this.tags.clear(); - this.tags.addAll(tags); + tags.forEach(this::addTag); return this; } @@ -205,7 +204,7 @@ public Builder tags(List tags) { * @return This builder. */ public Builder addTag(String tag) { - this.tags.add(tag); + this.tags.get().add(tag); return this; } diff --git a/smithy-codegen-core/src/main/java/software/amazon/smithy/codegen/core/trace/TraceFile.java b/smithy-codegen-core/src/main/java/software/amazon/smithy/codegen/core/trace/TraceFile.java index 2acd7dca856..2ba4960f7d6 100644 --- a/smithy-codegen-core/src/main/java/software/amazon/smithy/codegen/core/trace/TraceFile.java +++ b/smithy-codegen-core/src/main/java/software/amazon/smithy/codegen/core/trace/TraceFile.java @@ -5,7 +5,6 @@ package software.amazon.smithy.codegen.core.trace; import java.util.ArrayList; -import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -23,7 +22,7 @@ import software.amazon.smithy.model.node.ToNode; import software.amazon.smithy.model.shapes.Shape; import software.amazon.smithy.model.shapes.ShapeId; -import software.amazon.smithy.utils.MapUtils; +import software.amazon.smithy.utils.BuilderRef; import software.amazon.smithy.utils.SmithyBuilder; import software.amazon.smithy.utils.ToSmithyBuilder; @@ -49,10 +48,10 @@ public final class TraceFile implements ToNode, ToSmithyBuilder { private TraceFile(Builder builder) { smithyTrace = SmithyBuilder.requiredState(SMITHY_TRACE_TEXT, builder.smithyTrace); metadata = SmithyBuilder.requiredState(METADATA_TEXT, builder.metadata); - if (builder.shapes.isEmpty()) { + if (builder.shapes.peek().isEmpty()) { throw new IllegalStateException("TraceFile's shapes field must not be empty to build it."); } - shapes = MapUtils.copyOf(builder.shapes); + shapes = builder.shapes.copy(); artifactDefinitions = builder.artifactDefinitions; //validate we received a TraceFile where ShapeLink types and tags match definitions @@ -263,7 +262,7 @@ public Builder toBuilder() { */ public static final class Builder implements SmithyBuilder { - private final Map> shapes = new HashMap<>(); + private final BuilderRef>> shapes = BuilderRef.forUnorderedMap(); private String smithyTrace = SMITHY_TRACE_VERSION; private ArtifactDefinitions artifactDefinitions; private TraceMetadata metadata; @@ -310,9 +309,9 @@ public Builder metadata(TraceMetadata metadata) { * @return This builder. */ public Builder addShapeLink(ShapeId id, ShapeLink link) { - List list = this.shapes.getOrDefault(id, new ArrayList<>()); + List list = this.shapes.get().getOrDefault(id, new ArrayList<>()); list.add(link); - this.shapes.put(id, list); + this.shapes.get().put(id, list); return this; } @@ -335,7 +334,7 @@ public Builder addShapeLink(String idString, ShapeLink link) { * @return This builder. */ public Builder addShapeLinks(ShapeId id, List linkList) { - this.shapes.put(id, linkList); + this.shapes.get().put(id, linkList); return this; } @@ -356,7 +355,7 @@ public Builder addShapeLinks(String idString, List linkList) { */ public Builder shapes(Map> shapes) { this.shapes.clear(); - this.shapes.putAll(shapes); + shapes.forEach(this::addShapeLinks); return this; } diff --git a/smithy-jsonschema/src/main/java/software/amazon/smithy/jsonschema/JsonSchemaConverter.java b/smithy-jsonschema/src/main/java/software/amazon/smithy/jsonschema/JsonSchemaConverter.java index 8b6b360d116..ce3ebe3bccc 100644 --- a/smithy-jsonschema/src/main/java/software/amazon/smithy/jsonschema/JsonSchemaConverter.java +++ b/smithy-jsonschema/src/main/java/software/amazon/smithy/jsonschema/JsonSchemaConverter.java @@ -25,6 +25,7 @@ import software.amazon.smithy.model.shapes.UnionShape; import software.amazon.smithy.model.traits.UnitTypeTrait; import software.amazon.smithy.model.transform.ModelTransformer; +import software.amazon.smithy.utils.BuilderRef; import software.amazon.smithy.utils.FunctionalUtils; import software.amazon.smithy.utils.Pair; import software.amazon.smithy.utils.SmithyBuilder; @@ -41,7 +42,7 @@ public final class JsonSchemaConverter implements ToSmithyBuilder mappers = new ArrayList<>(); + private final List mappers; private final Model model; private final PropertyNamingStrategy propertyNamingStrategy; @@ -58,7 +59,7 @@ public final class JsonSchemaConverter implements ToSmithyBuilder(builder.mappers.peek()); config = SmithyBuilder.requiredState("config", builder.config); propertyNamingStrategy = SmithyBuilder.requiredState("propertyNamingStrategy", builder.propertyNamingStrategy); @@ -325,7 +326,7 @@ public static final class Builder implements SmithyBuilder private PropertyNamingStrategy propertyNamingStrategy = DEFAULT_PROPERTY_STRATEGY; private JsonSchemaConfig config = new JsonSchemaConfig(); private Predicate shapePredicate = shape -> true; - private final List mappers = new ArrayList<>(); + private final BuilderRef> mappers = BuilderRef.forList(); private Builder() {} @@ -402,7 +403,7 @@ public Builder propertyNamingStrategy(PropertyNamingStrategy propertyNamingStrat * @return Returns the converter. */ public Builder addMapper(JsonSchemaMapper jsonSchemaMapper) { - mappers.add(Objects.requireNonNull(jsonSchemaMapper)); + mappers.get().add(Objects.requireNonNull(jsonSchemaMapper)); return this; } @@ -414,7 +415,7 @@ public Builder addMapper(JsonSchemaMapper jsonSchemaMapper) { */ public Builder mappers(List jsonSchemaMappers) { mappers.clear(); - mappers.addAll(jsonSchemaMappers); + jsonSchemaMappers.forEach(this::addMapper); return this; } } diff --git a/smithy-jsonschema/src/main/java/software/amazon/smithy/jsonschema/Schema.java b/smithy-jsonschema/src/main/java/software/amazon/smithy/jsonschema/Schema.java index 322c453919c..6848efe677f 100644 --- a/smithy-jsonschema/src/main/java/software/amazon/smithy/jsonschema/Schema.java +++ b/smithy-jsonschema/src/main/java/software/amazon/smithy/jsonschema/Schema.java @@ -4,11 +4,9 @@ */ package software.amazon.smithy.jsonschema; -import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; -import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -21,8 +19,8 @@ import software.amazon.smithy.model.node.ObjectNode; import software.amazon.smithy.model.node.StringNode; import software.amazon.smithy.model.node.ToNode; +import software.amazon.smithy.utils.BuilderRef; import software.amazon.smithy.utils.ListUtils; -import software.amazon.smithy.utils.MapUtils; import software.amazon.smithy.utils.SmithyBuilder; import software.amazon.smithy.utils.ToSmithyBuilder; @@ -133,17 +131,17 @@ private Schema(Builder builder) { minItems = builder.minItems; uniqueItems = builder.uniqueItems; - properties = builder.properties; + properties = new LinkedHashMap<>(builder.properties.peek()); additionalProperties = builder.additionalProperties; - required = ListUtils.copyOf(builder.required); + required = builder.required.copy(); maxProperties = builder.maxProperties; minProperties = builder.minProperties; propertyNames = builder.propertyNames; - patternProperties = builder.patternProperties; + patternProperties = new LinkedHashMap<>(builder.patternProperties.peek()); - allOf = ListUtils.copyOf(builder.allOf); - oneOf = ListUtils.copyOf(builder.oneOf); - anyOf = ListUtils.copyOf(builder.anyOf); + allOf = builder.allOf.copy(); + oneOf = builder.oneOf.copy(); + anyOf = builder.anyOf.copy(); not = builder.not; title = builder.title; @@ -158,7 +156,7 @@ private Schema(Builder builder) { contentEncoding = builder.contentEncoding; contentMediaType = builder.contentMediaType; - extensions = MapUtils.copyOf(builder.extensions); + extensions = builder.extensions.copy(); } public static Builder builder() { @@ -623,15 +621,15 @@ public static final class Builder implements SmithyBuilder { private Integer maxProperties; private Integer minProperties; - private Collection required = new ArrayList<>(); - private Map properties = new LinkedHashMap<>(); + private final BuilderRef> required = BuilderRef.forList(); + private final BuilderRef> properties = BuilderRef.forOrderedMap(); private Schema additionalProperties; private Schema propertyNames; - private Map patternProperties = new LinkedHashMap<>(); + private final BuilderRef> patternProperties = BuilderRef.forOrderedMap(); - private List allOf = ListUtils.of(); - private List anyOf = ListUtils.of(); - private List oneOf = ListUtils.of(); + private final BuilderRef> allOf = BuilderRef.forList(); + private final BuilderRef> anyOf = BuilderRef.forList(); + private final BuilderRef> oneOf = BuilderRef.forList(); private Schema not; private String title; @@ -646,7 +644,7 @@ public static final class Builder implements SmithyBuilder { private String contentEncoding; private String contentMediaType; - private final Map extensions = new HashMap<>(); + private final BuilderRef> extensions = BuilderRef.forOrderedMap(); private Builder() {} @@ -761,10 +759,9 @@ public Builder minProperties(Integer minProperties) { } public Builder required(Collection required) { - if (required == null) { - this.required.clear(); - } else { - this.required = new ArrayList<>(required); + this.required.clear(); + if (required != null) { + this.required.get().addAll(required); } return this; } @@ -776,17 +773,23 @@ public Builder properties(Map properties) { properties.forEach(this::putProperty); } + for (String property : this.required.copy()) { + if (!this.properties.peek().containsKey(property)) { + this.required.get().remove(property); + } + } + return this; } public Builder putProperty(String key, Schema value) { - this.properties.put(key, value); + this.properties.get().put(key, value); return this; } public Builder removeProperty(String key) { - properties.remove(key); - required.remove(key); + properties.get().remove(key); + required.get().remove(key); return this; } @@ -811,27 +814,36 @@ public Builder patternProperties(Map patternProperties) { } public Builder putPatternProperty(String key, Schema value) { - this.patternProperties.put(key, value); + this.patternProperties.get().put(key, value); return this; } public Builder removePatternProperty(String key) { - patternProperties.remove(key); + patternProperties.get().remove(key); return this; } public Builder allOf(List allOf) { - this.allOf = allOf == null ? ListUtils.of() : allOf; + this.allOf.clear(); + if (allOf != null) { + this.allOf.get().addAll(allOf); + } return this; } public Builder anyOf(List anyOf) { - this.anyOf = anyOf == null ? ListUtils.of() : anyOf; + this.anyOf.clear(); + if (anyOf != null) { + this.anyOf.get().addAll(anyOf); + } return this; } public Builder oneOf(List oneOf) { - this.oneOf = oneOf == null ? ListUtils.of() : oneOf; + this.oneOf.clear(); + if (oneOf != null) { + this.oneOf.get().addAll(oneOf); + } return this; } @@ -896,17 +908,17 @@ public Builder deprecated(boolean deprecated) { public Builder extensions(Map extensions) { this.extensions.clear(); - this.extensions.putAll(extensions); + extensions.forEach(this::putExtension); return this; } public Builder putExtension(String key, ToNode value) { - extensions.put(key, value); + extensions.get().put(key, value); return this; } public Builder removeExtension(String key) { - extensions.remove(key); + extensions.get().remove(key); return this; } diff --git a/smithy-jsonschema/src/main/java/software/amazon/smithy/jsonschema/SchemaDocument.java b/smithy-jsonschema/src/main/java/software/amazon/smithy/jsonschema/SchemaDocument.java index dbc084de958..cd12004f2d5 100644 --- a/smithy-jsonschema/src/main/java/software/amazon/smithy/jsonschema/SchemaDocument.java +++ b/smithy-jsonschema/src/main/java/software/amazon/smithy/jsonschema/SchemaDocument.java @@ -14,6 +14,7 @@ import software.amazon.smithy.model.node.NodePointer; import software.amazon.smithy.model.node.ObjectNode; import software.amazon.smithy.model.node.ToNode; +import software.amazon.smithy.utils.BuilderRef; import software.amazon.smithy.utils.SmithyBuilder; import software.amazon.smithy.utils.ToSmithyBuilder; @@ -35,7 +36,7 @@ private SchemaDocument(Builder builder) { idKeyword = builder.idKeyword; schemaKeyword = builder.schemaKeyword; rootSchema = builder.rootSchema != null ? builder.rootSchema : Schema.builder().build(); - definitions = new LinkedHashMap<>(builder.definitions); + definitions = new LinkedHashMap<>(builder.definitions.copy()); extensions = builder.extensions; } @@ -224,7 +225,7 @@ public static final class Builder implements SmithyBuilder { private String schemaKeyword; private Schema rootSchema; private ObjectNode extensions = Node.objectNode(); - private final Map definitions = new LinkedHashMap<>(); + private final BuilderRef> definitions = BuilderRef.forOrderedMap(); private Builder() {} @@ -274,7 +275,7 @@ public Builder rootSchema(Schema rootSchema) { * @return Returns the builder. */ public Builder putDefinition(String name, Schema schema) { - definitions.put(name, schema); + definitions.get().put(name, schema); return this; } @@ -285,7 +286,7 @@ public Builder putDefinition(String name, Schema schema) { * @return Returns the builder. */ public Builder removeDefinition(String name) { - definitions.remove(name); + definitions.get().remove(name); return this; } diff --git a/smithy-jsonschema/src/test/java/software/amazon/smithy/jsonschema/SchemaTest.java b/smithy-jsonschema/src/test/java/software/amazon/smithy/jsonschema/SchemaTest.java index fae438ead06..f66270803c8 100644 --- a/smithy-jsonschema/src/test/java/software/amazon/smithy/jsonschema/SchemaTest.java +++ b/smithy-jsonschema/src/test/java/software/amazon/smithy/jsonschema/SchemaTest.java @@ -8,6 +8,7 @@ import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.not; import java.util.Collections; @@ -18,6 +19,7 @@ import software.amazon.smithy.model.node.ArrayNode; import software.amazon.smithy.model.node.Node; import software.amazon.smithy.utils.ListUtils; +import software.amazon.smithy.utils.MapUtils; import software.amazon.smithy.utils.SetUtils; public class SchemaTest { @@ -196,6 +198,23 @@ public void removingPropertiesRemovesRequiredPropertiesToo() { .build(); assertThat(schema.getProperties().keySet(), contains("bar")); + assertThat(schema.getRequired(), hasSize(1)); + assertThat(schema.getRequired(), contains("bar")); + } + + @Test + public void implicitlyRemovingPropertiesRemovesRequiredPropertiesToo() { + Schema schema = Schema.builder() + .removeProperty("notThere") + .required(null) + .putProperty("foo", Schema.builder().build()) + .putProperty("bar", Schema.builder().build()) + .required(ListUtils.of("foo", "bar")) + .properties(MapUtils.of("bar", Schema.builder().build())) + .build(); + + assertThat(schema.getProperties().keySet(), contains("bar")); + assertThat(schema.getRequired(), hasSize(1)); assertThat(schema.getRequired(), contains("bar")); } diff --git a/smithy-openapi/src/main/java/software/amazon/smithy/openapi/model/CallbackObject.java b/smithy-openapi/src/main/java/software/amazon/smithy/openapi/model/CallbackObject.java index f5ac113b501..4a3dc521d7d 100644 --- a/smithy-openapi/src/main/java/software/amazon/smithy/openapi/model/CallbackObject.java +++ b/smithy-openapi/src/main/java/software/amazon/smithy/openapi/model/CallbackObject.java @@ -4,11 +4,10 @@ */ package software.amazon.smithy.openapi.model; -import java.util.Collections; import java.util.Map; -import java.util.TreeMap; import software.amazon.smithy.model.node.Node; import software.amazon.smithy.model.node.ObjectNode; +import software.amazon.smithy.utils.BuilderRef; import software.amazon.smithy.utils.ToSmithyBuilder; public final class CallbackObject extends Component implements ToSmithyBuilder { @@ -16,7 +15,7 @@ public final class CallbackObject extends Component implements ToSmithyBuilder(builder.paths)); + paths = builder.paths.copy(); } public static Builder builder() { @@ -42,7 +41,7 @@ public Builder toBuilder() { } public static final class Builder extends Component.Builder { - private Map paths = new TreeMap<>(); + private final BuilderRef> paths = BuilderRef.forSortedMap(); private Builder() {} @@ -53,12 +52,12 @@ public CallbackObject build() { public Builder paths(Map paths) { this.paths.clear(); - this.paths.putAll(paths); + paths.forEach(this::putPath); return this; } public Builder putPath(String expression, PathItem pathItem) { - paths.put(expression, pathItem); + paths.get().put(expression, pathItem); return this; } } diff --git a/smithy-openapi/src/main/java/software/amazon/smithy/openapi/model/Component.java b/smithy-openapi/src/main/java/software/amazon/smithy/openapi/model/Component.java index ccf7752dabc..f482954d72f 100644 --- a/smithy-openapi/src/main/java/software/amazon/smithy/openapi/model/Component.java +++ b/smithy-openapi/src/main/java/software/amazon/smithy/openapi/model/Component.java @@ -10,6 +10,7 @@ import software.amazon.smithy.model.node.Node; import software.amazon.smithy.model.node.ObjectNode; import software.amazon.smithy.model.node.ToNode; +import software.amazon.smithy.utils.BuilderRef; import software.amazon.smithy.utils.SmithyBuilder; /** @@ -24,10 +25,11 @@ */ public abstract class Component implements ToNode { private Node node; - private final Map extensions = new TreeMap<>(); + private final Map extensions; protected Component(Builder builder) { - extensions.putAll(builder.getExtensions()); + // This wasn't made immutable from the start, so now it's mutable forever. + extensions = new TreeMap<>(builder.extensions.copy()); } public final Optional getExtension(String name) { @@ -70,16 +72,16 @@ public final int hashCode() { } public abstract static class Builder implements SmithyBuilder { - private final Map extensions = new TreeMap<>(); + private final BuilderRef> extensions = BuilderRef.forSortedMap(); public Map getExtensions() { - return extensions; + return extensions.get(); } @SuppressWarnings("unchecked") public B extensions(Map extensions) { this.extensions.clear(); - this.extensions.putAll(extensions); + extensions.forEach(this::putExtension); return (B) this; } @@ -89,7 +91,7 @@ public B extensions(ObjectNode extensions) { @SuppressWarnings("unchecked") public B putExtension(String key, Node value) { - extensions.put(key, value); + extensions.get().put(key, value); return (B) this; } @@ -107,7 +109,7 @@ public B putExtension(String key, Number value) { @SuppressWarnings("unchecked") public B removeExtension(String key) { - extensions.remove(key); + extensions.get().remove(key); return (B) this; } } diff --git a/smithy-openapi/src/main/java/software/amazon/smithy/openapi/model/ComponentsObject.java b/smithy-openapi/src/main/java/software/amazon/smithy/openapi/model/ComponentsObject.java index 75862c1eba4..61419a5811b 100644 --- a/smithy-openapi/src/main/java/software/amazon/smithy/openapi/model/ComponentsObject.java +++ b/smithy-openapi/src/main/java/software/amazon/smithy/openapi/model/ComponentsObject.java @@ -9,28 +9,29 @@ import software.amazon.smithy.jsonschema.Schema; import software.amazon.smithy.model.node.Node; import software.amazon.smithy.model.node.ObjectNode; +import software.amazon.smithy.utils.BuilderRef; import software.amazon.smithy.utils.ToSmithyBuilder; public final class ComponentsObject extends Component implements ToSmithyBuilder { - private final Map schemas = new TreeMap<>(); - private final Map responses = new TreeMap<>(); - private final Map parameters = new TreeMap<>(); - private final Map requestBodies = new TreeMap<>(); - private final Map headers = new TreeMap<>(); - private final Map securitySchemes = new TreeMap<>(); - private final Map links = new TreeMap<>(); - private final Map callbacks = new TreeMap<>(); + private final Map schemas; + private final Map responses; + private final Map parameters; + private final Map requestBodies; + private final Map headers; + private final Map securitySchemes; + private final Map links; + private final Map callbacks; private ComponentsObject(Builder builder) { super(builder); - schemas.putAll(builder.schemas); - responses.putAll(builder.responses); - parameters.putAll(builder.parameters); - requestBodies.putAll(builder.requestBodies); - headers.putAll(builder.headers); - securitySchemes.putAll(builder.securitySchemes); - links.putAll(builder.links); - callbacks.putAll(builder.callbacks); + schemas = new TreeMap<>(builder.schemas.peek()); + responses = new TreeMap<>(builder.responses.peek()); + parameters = new TreeMap<>(builder.parameters.peek()); + requestBodies = new TreeMap<>(builder.requestBodies.peek()); + headers = new TreeMap<>(builder.headers.peek()); + securitySchemes = new TreeMap<>(builder.securitySchemes.peek()); + links = new TreeMap<>(builder.links.peek()); + callbacks = new TreeMap<>(builder.callbacks.peek()); } public static Builder builder() { @@ -147,14 +148,14 @@ public Builder toBuilder() { } public static final class Builder extends Component.Builder { - private final Map schemas = new TreeMap<>(); - private final Map responses = new TreeMap<>(); - private final Map parameters = new TreeMap<>(); - private final Map requestBodies = new TreeMap<>(); - private final Map headers = new TreeMap<>(); - private final Map securitySchemes = new TreeMap<>(); - private final Map links = new TreeMap<>(); - private final Map callbacks = new TreeMap<>(); + private final BuilderRef> schemas = BuilderRef.forSortedMap(); + private final BuilderRef> responses = BuilderRef.forSortedMap(); + private final BuilderRef> parameters = BuilderRef.forSortedMap(); + private final BuilderRef> requestBodies = BuilderRef.forSortedMap(); + private final BuilderRef> headers = BuilderRef.forSortedMap(); + private final BuilderRef> securitySchemes = BuilderRef.forSortedMap(); + private final BuilderRef> links = BuilderRef.forSortedMap(); + private final BuilderRef> callbacks = BuilderRef.forSortedMap(); private Builder() {} @@ -165,99 +166,99 @@ public ComponentsObject build() { public Builder schemas(Map schemas) { this.schemas.clear(); - this.schemas.putAll(schemas); + schemas.forEach(this::putSchema); return this; } public Builder putSchema(String name, Schema schema) { - schemas.put(name, schema); + schemas.get().put(name, schema); return this; } public Builder removeSchema(String name) { - schemas.remove(name); + schemas.get().remove(name); return this; } public Builder responses(Map responses) { this.responses.clear(); - this.responses.putAll(responses); + responses.forEach(this::putResponse); return this; } public Builder putResponse(String name, ResponseObject response) { - responses.put(name, response); + responses.get().put(name, response); return this; } public Builder parameters(Map parameters) { this.parameters.clear(); - this.parameters.putAll(parameters); + parameters.forEach(this::putParameter); return this; } public Builder putParameter(String name, ParameterObject parameter) { - parameters.put(name, parameter); + parameters.get().put(name, parameter); return this; } public Builder requestBodies(Map requestBodies) { this.requestBodies.clear(); - this.requestBodies.putAll(requestBodies); + requestBodies.forEach(this::putRequestBodies); return this; } public Builder putRequestBodies(String name, RequestBodyObject requestBody) { - requestBodies.put(name, requestBody); + requestBodies.get().put(name, requestBody); return this; } public Builder headers(Map headers) { this.headers.clear(); - this.headers.putAll(headers); + headers.forEach(this::putHeader); return this; } public Builder putHeader(String name, ParameterObject header) { - headers.put(name, header); + headers.get().put(name, header); return this; } public Builder securitySchemes(Map securitySchemes) { this.securitySchemes.clear(); - this.securitySchemes.putAll(securitySchemes); + securitySchemes.forEach(this::putSecurityScheme); return this; } public Builder putSecurityScheme(String name, SecurityScheme securityScheme) { - securitySchemes.put(name, securityScheme); + securitySchemes.get().put(name, securityScheme); return this; } public Builder removeSecurityScheme(String name) { - securitySchemes.remove(name); + securitySchemes.get().remove(name); return this; } public Builder links(Map links) { this.links.clear(); - this.links.putAll(links); + links.forEach(this::putLink); return this; } public Builder putLink(String name, LinkObject link) { - links.put(name, link); + links.get().put(name, link); return this; } public Builder callbacks(Map callbacks) { this.callbacks.clear(); - this.callbacks.putAll(callbacks); + callbacks.forEach(this::putCallbacks); return this; } public Builder putCallbacks(String name, CallbackObject callback) { - callbacks.put(name, callback); + callbacks.get().put(name, callback); return this; } } diff --git a/smithy-openapi/src/main/java/software/amazon/smithy/openapi/model/EncodingObject.java b/smithy-openapi/src/main/java/software/amazon/smithy/openapi/model/EncodingObject.java index 1f4d736d5a0..a96f232860f 100644 --- a/smithy-openapi/src/main/java/software/amazon/smithy/openapi/model/EncodingObject.java +++ b/smithy-openapi/src/main/java/software/amazon/smithy/openapi/model/EncodingObject.java @@ -9,10 +9,11 @@ import java.util.TreeMap; import software.amazon.smithy.model.node.Node; import software.amazon.smithy.model.node.ObjectNode; +import software.amazon.smithy.utils.BuilderRef; import software.amazon.smithy.utils.ToSmithyBuilder; public final class EncodingObject extends Component implements ToSmithyBuilder { - private final Map headers = new TreeMap<>(); + private final Map headers; private final String contentType; private final String style; private final boolean explode; @@ -20,7 +21,7 @@ public final class EncodingObject extends Component implements ToSmithyBuilder(builder.headers.peek()); contentType = builder.contentType; style = builder.style; explode = builder.explode; @@ -87,7 +88,7 @@ public Builder toBuilder() { } public static final class Builder extends Component.Builder { - private final Map headers = new TreeMap<>(); + private final BuilderRef> headers = BuilderRef.forSortedMap(); private String contentType; private String style; private boolean explode; @@ -102,12 +103,12 @@ public EncodingObject build() { public Builder headers(Map headers) { this.headers.clear(); - this.headers.putAll(headers); + headers.forEach(this::putHeader); return this; } public Builder putHeader(String name, ParameterObject header) { - headers.put(name, header); + headers.get().put(name, header); return this; } diff --git a/smithy-openapi/src/main/java/software/amazon/smithy/openapi/model/LinkObject.java b/smithy-openapi/src/main/java/software/amazon/smithy/openapi/model/LinkObject.java index 5121397e834..63f1be102c4 100644 --- a/smithy-openapi/src/main/java/software/amazon/smithy/openapi/model/LinkObject.java +++ b/smithy-openapi/src/main/java/software/amazon/smithy/openapi/model/LinkObject.java @@ -9,10 +9,11 @@ import java.util.TreeMap; import software.amazon.smithy.model.node.Node; import software.amazon.smithy.model.node.ObjectNode; +import software.amazon.smithy.utils.BuilderRef; import software.amazon.smithy.utils.ToSmithyBuilder; public final class LinkObject extends Component implements ToSmithyBuilder { - private final Map parameters = new TreeMap<>(); + private final Map parameters; private final String operationRef; private final String operationId; private final Node requestBody; @@ -21,7 +22,7 @@ public final class LinkObject extends Component implements ToSmithyBuilder(builder.parameters.peek()); operationId = builder.operationId; operationRef = builder.operationRef; requestBody = builder.requestBody; @@ -89,7 +90,7 @@ public Builder toBuilder() { } public static final class Builder extends Component.Builder { - private final Map parameters = new TreeMap<>(); + private final BuilderRef> parameters = BuilderRef.forSortedMap(); private String operationRef; private String operationId; private Node requestBody; @@ -115,7 +116,7 @@ public Builder operationId(String operationId) { public Builder parameters(Map parameters) { this.parameters.clear(); - this.parameters.putAll(parameters); + this.parameters.get().putAll(parameters); return this; } diff --git a/smithy-openapi/src/main/java/software/amazon/smithy/openapi/model/MediaTypeObject.java b/smithy-openapi/src/main/java/software/amazon/smithy/openapi/model/MediaTypeObject.java index 2b42b436ea4..5f5a7e7ba26 100644 --- a/smithy-openapi/src/main/java/software/amazon/smithy/openapi/model/MediaTypeObject.java +++ b/smithy-openapi/src/main/java/software/amazon/smithy/openapi/model/MediaTypeObject.java @@ -10,20 +10,21 @@ import software.amazon.smithy.jsonschema.Schema; import software.amazon.smithy.model.node.Node; import software.amazon.smithy.model.node.ObjectNode; +import software.amazon.smithy.utils.BuilderRef; import software.amazon.smithy.utils.ToSmithyBuilder; public final class MediaTypeObject extends Component implements ToSmithyBuilder { private final Schema schema; private final ExampleObject example; - private final Map examples = new TreeMap<>(); - private final Map encoding = new TreeMap<>(); + private final Map examples; + private final Map encoding; private MediaTypeObject(Builder builder) { super(builder); schema = builder.schema; example = builder.example; - examples.putAll(builder.examples); - encoding.putAll(builder.encoding); + examples = new TreeMap<>(builder.examples.peek()); + encoding = new TreeMap<>(builder.encoding.peek()); } public static Builder builder() { @@ -87,8 +88,8 @@ public Builder toBuilder() { public static final class Builder extends Component.Builder { private Schema schema; private ExampleObject example; - private final Map examples = new TreeMap<>(); - private final Map encoding = new TreeMap<>(); + private final BuilderRef> examples = BuilderRef.forSortedMap(); + private final BuilderRef> encoding = BuilderRef.forSortedMap(); private Builder() {} @@ -110,24 +111,24 @@ public Builder example(Node example) { public Builder examples(Map examples) { this.examples.clear(); for (Map.Entry example : examples.entrySet()) { - this.examples.put(example.getKey(), ExampleObject.fromNode(example.getValue())); + this.examples.get().put(example.getKey(), ExampleObject.fromNode(example.getValue())); } return this; } public Builder putExample(String name, ExampleObject example) { - examples.put(name, example); + examples.get().put(name, example); return this; } public Builder encoding(Map encoding) { this.encoding.clear(); - this.encoding.putAll(encoding); + encoding.forEach(this::putEncoding); return this; } public Builder putEncoding(String name, EncodingObject encodingObject) { - encoding.put(name, encodingObject); + encoding.get().put(name, encodingObject); return this; } } diff --git a/smithy-openapi/src/main/java/software/amazon/smithy/openapi/model/OpenApi.java b/smithy-openapi/src/main/java/software/amazon/smithy/openapi/model/OpenApi.java index 5e39c00db0e..4716ed02f0d 100644 --- a/smithy-openapi/src/main/java/software/amazon/smithy/openapi/model/OpenApi.java +++ b/smithy-openapi/src/main/java/software/amazon/smithy/openapi/model/OpenApi.java @@ -7,7 +7,6 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Comparator; -import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Optional; @@ -16,6 +15,7 @@ import software.amazon.smithy.model.node.ArrayNode; import software.amazon.smithy.model.node.Node; import software.amazon.smithy.model.node.ObjectNode; +import software.amazon.smithy.utils.BuilderRef; import software.amazon.smithy.utils.ListUtils; import software.amazon.smithy.utils.SmithyBuilder; import software.amazon.smithy.utils.ToSmithyBuilder; @@ -24,7 +24,7 @@ public final class OpenApi extends Component implements ToSmithyBuilder private final String openapi; private final InfoObject info; private final List servers; - private final Map paths = new TreeMap<>(); + private final Map paths; private final ComponentsObject components; private final List>> security; private final List tags; @@ -34,10 +34,10 @@ private OpenApi(Builder builder) { super(builder); openapi = SmithyBuilder.requiredState("openapi", builder.openapi); info = SmithyBuilder.requiredState("info", builder.info); - servers = ListUtils.copyOf(builder.servers); - paths.putAll(builder.paths); + servers = builder.servers.copy(); + paths = new TreeMap<>(builder.paths.peek()); components = builder.components == null ? ComponentsObject.builder().build() : builder.components; - security = ListUtils.copyOf(builder.security); + security = ListUtils.copyOf(builder.security.peek()); tags = ListUtils.copyOf(builder.tags); externalDocs = builder.externalDocs; } @@ -138,12 +138,12 @@ protected ObjectNode.Builder createNodeBuilder() { public static final class Builder extends Component.Builder { private String openapi; private InfoObject info; - private final List servers = new ArrayList<>(); - private Map paths = new TreeMap<>(); + private final BuilderRef> servers = BuilderRef.forList(); + private final BuilderRef> paths = BuilderRef.forSortedMap(); private ComponentsObject components; // Use a set for security as duplicate entries are unnecessary (effectively // represent an "A or A" security posture) and can cause downstream issues. - private final Set>> security = new LinkedHashSet<>(); + private final BuilderRef>>> security = BuilderRef.forOrderedSet(); private final List tags = new ArrayList<>(); private ExternalDocumentation externalDocs; @@ -165,17 +165,18 @@ public Builder info(InfoObject info) { } public Builder paths(Map paths) { - this.paths = paths; + this.paths.clear(); + paths.forEach(this::putPath); return this; } public Builder putPath(String path, PathItem item) { - paths.put(path, item); + paths.get().put(path, item); return this; } public Builder removePath(String path) { - paths.remove(path); + paths.get().remove(path); return this; } @@ -190,7 +191,7 @@ public Builder externalDocs(ExternalDocumentation externalDocs) { } public Builder addServer(ServerObject server) { - this.servers.add(server); + this.servers.get().add(server); return this; } @@ -200,13 +201,13 @@ public Builder clearServer() { } public Builder addSecurity(Map> requirement) { - this.security.add(requirement); + this.security.get().add(requirement); return this; } public Builder security(Collection>> security) { this.security.clear(); - this.security.addAll(security); + security.forEach(this::addSecurity); return this; } diff --git a/smithy-openapi/src/main/java/software/amazon/smithy/openapi/model/OperationObject.java b/smithy-openapi/src/main/java/software/amazon/smithy/openapi/model/OperationObject.java index fc8402988df..49d4cf8a833 100644 --- a/smithy-openapi/src/main/java/software/amazon/smithy/openapi/model/OperationObject.java +++ b/smithy-openapi/src/main/java/software/amazon/smithy/openapi/model/OperationObject.java @@ -4,19 +4,16 @@ */ package software.amazon.smithy.openapi.model; -import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; import java.util.Comparator; -import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; -import java.util.TreeMap; import software.amazon.smithy.model.node.ArrayNode; import software.amazon.smithy.model.node.Node; import software.amazon.smithy.model.node.ObjectNode; +import software.amazon.smithy.utils.BuilderRef; import software.amazon.smithy.utils.ListUtils; import software.amazon.smithy.utils.Pair; import software.amazon.smithy.utils.ToSmithyBuilder; @@ -37,22 +34,22 @@ public final class OperationObject extends Component implements ToSmithyBuilder< private OperationObject(Builder builder) { super(builder); - tags = ListUtils.copyOf(builder.tags); + tags = builder.tags.copy(); summary = builder.summary; description = builder.description; externalDocs = builder.externalDocs; operationId = builder.operationId; - parameters = ListUtils.copyOf(builder.parameters); + parameters = builder.parameters.copy(); requestBody = builder.requestBody; - responses = Collections.unmodifiableMap(new TreeMap<>(builder.responses)); + responses = builder.responses.copy(); deprecated = builder.deprecated; - callbacks = Collections.unmodifiableMap(new TreeMap<>(builder.callbacks)); - if (builder.security != null) { - security = ListUtils.copyOf(builder.security); + callbacks = builder.callbacks.copy(); + if (builder.security.hasValue()) { + security = ListUtils.copyOf(builder.security.peek()); } else { security = null; } - servers = ListUtils.copyOf(builder.servers); + servers = builder.servers.copy(); } public static Builder builder() { @@ -188,14 +185,14 @@ public Builder toBuilder() { } public static final class Builder extends Component.Builder { - private final List tags = new ArrayList<>(); - private final List parameters = new ArrayList<>(); - private final Map responses = new TreeMap<>(); - private final Map callbacks = new TreeMap<>(); + private final BuilderRef> tags = BuilderRef.forList(); + private final BuilderRef> parameters = BuilderRef.forList(); + private final BuilderRef> responses = BuilderRef.forSortedMap(); + private final BuilderRef> callbacks = BuilderRef.forSortedMap(); // Use a set for security as duplicate entries are unnecessary (effectively // represent an "A or A" security posture) and can cause downstream issues. - private Set>> security; - private final List servers = new ArrayList<>(); + private final BuilderRef>>> security = BuilderRef.forOrderedSet(); + private final BuilderRef> servers = BuilderRef.forList(); private String summary; private String description; private ExternalDocumentation externalDocs; @@ -212,12 +209,12 @@ public OperationObject build() { public Builder tags(Collection tags) { this.tags.clear(); - this.tags.addAll(tags); + tags.forEach(this::addTag); return this; } public Builder addTag(String tag) { - tags.add(tag); + tags.get().add(tag); return this; } @@ -243,12 +240,12 @@ public Builder operationId(String operationId) { public Builder parameters(Collection parameters) { this.parameters.clear(); - this.parameters.addAll(parameters); + parameters.forEach(this::addParameter); return this; } public Builder addParameter(ParameterObject parameter) { - parameters.add(parameter); + parameters.get().add(parameter); return this; } @@ -259,23 +256,23 @@ public Builder requestBody(RequestBodyObject requestBody) { public Builder responses(Map responses) { this.responses.clear(); - this.responses.putAll(responses); + responses.forEach(this::putResponse); return this; } public Builder putResponse(String statusCode, ResponseObject response) { - responses.put(statusCode, response); + responses.get().put(statusCode, response); return this; } public Builder callbacks(Map callbacks) { this.callbacks.clear(); - this.callbacks.putAll(callbacks); + callbacks.forEach(this::putCallback); return this; } public Builder putCallback(String expression, CallbackObject callback) { - callbacks.put(expression, callback); + callbacks.get().put(expression, callback); return this; } @@ -285,27 +282,23 @@ public Builder deprecated(boolean deprecated) { } public Builder security(Collection>> security) { - this.security = new LinkedHashSet<>(); - this.security.addAll(security); + this.security.get().addAll(security); return this; } public Builder addSecurity(Map> security) { - if (this.security == null) { - this.security = new LinkedHashSet<>(); - } - this.security.add(security); + this.security.get().add(security); return this; } public Builder servers(Collection servers) { this.servers.clear(); - this.servers.addAll(servers); + servers.forEach(this::addServer); return this; } public Builder addServer(ServerObject server) { - servers.add(server); + servers.get().add(server); return this; } } diff --git a/smithy-openapi/src/main/java/software/amazon/smithy/openapi/model/ParameterObject.java b/smithy-openapi/src/main/java/software/amazon/smithy/openapi/model/ParameterObject.java index b5e3edd6b8b..6233cf85f20 100644 --- a/smithy-openapi/src/main/java/software/amazon/smithy/openapi/model/ParameterObject.java +++ b/smithy-openapi/src/main/java/software/amazon/smithy/openapi/model/ParameterObject.java @@ -4,13 +4,12 @@ */ package software.amazon.smithy.openapi.model; -import java.util.Collections; import java.util.Map; import java.util.Optional; -import java.util.TreeMap; import software.amazon.smithy.jsonschema.Schema; import software.amazon.smithy.model.node.Node; import software.amazon.smithy.model.node.ObjectNode; +import software.amazon.smithy.utils.BuilderRef; import software.amazon.smithy.utils.ToSmithyBuilder; public final class ParameterObject extends Component implements ToSmithyBuilder { @@ -41,8 +40,8 @@ private ParameterObject(Builder builder) { allowReserved = builder.allowReserved; schema = builder.schema; example = builder.example; - examples = Collections.unmodifiableMap(new TreeMap<>(builder.examples)); - content = Collections.unmodifiableMap(new TreeMap<>(builder.content)); + examples = builder.examples.copy(); + content = builder.content.copy(); } public static Builder builder() { @@ -184,8 +183,8 @@ public static final class Builder extends Component.Builder examples = new TreeMap<>(); - private final Map content = new TreeMap<>(); + private final BuilderRef> examples = BuilderRef.forSortedMap(); + private final BuilderRef> content = BuilderRef.forSortedMap(); private Builder() {} @@ -252,24 +251,24 @@ public Builder example(Node example) { public Builder examples(Map examples) { this.examples.clear(); for (Map.Entry example : examples.entrySet()) { - this.examples.put(example.getKey(), ExampleObject.fromNode(example.getValue())); + this.examples.get().put(example.getKey(), ExampleObject.fromNode(example.getValue())); } return this; } public Builder putExample(String name, Node example) { - this.examples.put(name, ExampleObject.fromNode(example)); + this.examples.get().put(name, ExampleObject.fromNode(example)); return this; } public Builder content(Map content) { this.content.clear(); - this.content.putAll(content); + content.forEach(this::putContent); return this; } public Builder putContent(String name, MediaTypeObject mediaTypeObject) { - this.content.put(name, mediaTypeObject); + this.content.get().put(name, mediaTypeObject); return this; } } diff --git a/smithy-openapi/src/main/java/software/amazon/smithy/openapi/model/PathItem.java b/smithy-openapi/src/main/java/software/amazon/smithy/openapi/model/PathItem.java index f7e821a09b6..a83db9c0bb3 100644 --- a/smithy-openapi/src/main/java/software/amazon/smithy/openapi/model/PathItem.java +++ b/smithy-openapi/src/main/java/software/amazon/smithy/openapi/model/PathItem.java @@ -4,7 +4,6 @@ */ package software.amazon.smithy.openapi.model; -import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -13,7 +12,7 @@ import software.amazon.smithy.model.node.ArrayNode; import software.amazon.smithy.model.node.Node; import software.amazon.smithy.model.node.ObjectNode; -import software.amazon.smithy.utils.ListUtils; +import software.amazon.smithy.utils.BuilderRef; import software.amazon.smithy.utils.ToSmithyBuilder; public final class PathItem extends Component implements ToSmithyBuilder { @@ -34,8 +33,8 @@ private PathItem(Builder builder) { super(builder); summary = builder.summary; description = builder.description; - servers = ListUtils.copyOf(builder.servers); - parameters = ListUtils.copyOf(builder.parameters); + servers = builder.servers.copy(); + parameters = builder.parameters.copy(); get = builder.get; put = builder.put; post = builder.post; @@ -164,8 +163,8 @@ public Builder toBuilder() { public static final class Builder extends Component.Builder { private String summary; private String description; - private List servers = new ArrayList<>(); - private List> parameters = new ArrayList<>(); + private final BuilderRef> servers = BuilderRef.forList(); + private final BuilderRef>> parameters = BuilderRef.forList(); private OperationObject get; private OperationObject put; private OperationObject post; @@ -194,18 +193,18 @@ public Builder description(String description) { public Builder servers(List servers) { this.servers.clear(); - this.servers.addAll(servers); + servers.forEach(this::addServer); return this; } public Builder addServer(ServerObject server) { - servers.add(server); + servers.get().add(server); return this; } public Builder parameters(List> parameters) { this.parameters.clear(); - this.parameters.addAll(parameters); + parameters.forEach(this::addParameter); return this; } @@ -214,7 +213,7 @@ public Builder addParameter(ParameterObject parameter) { } public Builder addParameter(Ref parameter) { - parameters.add(parameter); + parameters.get().add(parameter); return this; } diff --git a/smithy-openapi/src/main/java/software/amazon/smithy/openapi/model/RequestBodyObject.java b/smithy-openapi/src/main/java/software/amazon/smithy/openapi/model/RequestBodyObject.java index f192c2a92eb..55bb7868946 100644 --- a/smithy-openapi/src/main/java/software/amazon/smithy/openapi/model/RequestBodyObject.java +++ b/smithy-openapi/src/main/java/software/amazon/smithy/openapi/model/RequestBodyObject.java @@ -9,17 +9,18 @@ import java.util.TreeMap; import software.amazon.smithy.model.node.Node; import software.amazon.smithy.model.node.ObjectNode; +import software.amazon.smithy.utils.BuilderRef; import software.amazon.smithy.utils.ToSmithyBuilder; public final class RequestBodyObject extends Component implements ToSmithyBuilder { private final String description; - private final Map content = new TreeMap<>(); + private final Map content; private final boolean required; private RequestBodyObject(Builder builder) { super(builder); description = builder.description; - content.putAll(builder.content); + content = new TreeMap<>(builder.content.peek()); required = builder.required; } @@ -65,7 +66,7 @@ public Builder toBuilder() { } public static final class Builder extends Component.Builder { - private final Map content = new TreeMap<>(); + private final BuilderRef> content = BuilderRef.forSortedMap(); private String description; private boolean required; @@ -83,12 +84,12 @@ public Builder description(String description) { public Builder content(Map content) { this.content.clear(); - this.content.putAll(content); + content.forEach(this::putContent); return this; } public Builder putContent(String name, MediaTypeObject content) { - this.content.put(name, content); + this.content.get().put(name, content); return this; } diff --git a/smithy-openapi/src/main/java/software/amazon/smithy/openapi/model/ResponseObject.java b/smithy-openapi/src/main/java/software/amazon/smithy/openapi/model/ResponseObject.java index a3f2ea360a3..013867cfaae 100644 --- a/smithy-openapi/src/main/java/software/amazon/smithy/openapi/model/ResponseObject.java +++ b/smithy-openapi/src/main/java/software/amazon/smithy/openapi/model/ResponseObject.java @@ -4,12 +4,11 @@ */ package software.amazon.smithy.openapi.model; -import java.util.Collections; import java.util.Map; import java.util.Optional; -import java.util.TreeMap; import software.amazon.smithy.model.node.Node; import software.amazon.smithy.model.node.ObjectNode; +import software.amazon.smithy.utils.BuilderRef; import software.amazon.smithy.utils.SmithyBuilder; import software.amazon.smithy.utils.ToSmithyBuilder; @@ -22,9 +21,9 @@ public final class ResponseObject extends Component implements ToSmithyBuilder(builder.headers)); - content = Collections.unmodifiableMap(new TreeMap<>(builder.content)); - links = Collections.unmodifiableMap(new TreeMap<>(builder.links)); + headers = builder.headers.copy(); + content = builder.content.copy(); + links = builder.links.copy(); } public static Builder builder() { @@ -104,9 +103,9 @@ public Builder toBuilder() { public static final class Builder extends Component.Builder { private String description; - private final Map> headers = new TreeMap<>(); - private final Map content = new TreeMap<>(); - private final Map> links = new TreeMap<>(); + private final BuilderRef>> headers = BuilderRef.forSortedMap(); + private final BuilderRef> content = BuilderRef.forSortedMap(); + private final BuilderRef>> links = BuilderRef.forSortedMap(); private Builder() {} @@ -121,29 +120,29 @@ public Builder description(String description) { } public Builder putHeader(String name, Ref header) { - headers.put(name, header); + headers.get().put(name, header); return this; } public Builder headers(Map> headers) { this.headers.clear(); - this.headers.putAll(headers); + headers.forEach(this::putHeader); return this; } public Builder putContent(String name, MediaTypeObject mediaTypeObject) { - content.put(name, mediaTypeObject); + content.get().put(name, mediaTypeObject); return this; } public Builder content(Map content) { this.content.clear(); - this.content.putAll(content); + content.forEach(this::putContent); return this; } public Builder putLink(String name, Ref link) { - links.put(name, link); + links.get().put(name, link); return this; } @@ -153,7 +152,7 @@ public Builder putLink(String name, LinkObject link) { public Builder links(Map> links) { this.links.clear(); - this.links.putAll(links); + links.forEach(this::putLink); return this; } } diff --git a/smithy-openapi/src/main/java/software/amazon/smithy/openapi/model/ServerObject.java b/smithy-openapi/src/main/java/software/amazon/smithy/openapi/model/ServerObject.java index b4fcd6d501d..6a299dab5f5 100644 --- a/smithy-openapi/src/main/java/software/amazon/smithy/openapi/model/ServerObject.java +++ b/smithy-openapi/src/main/java/software/amazon/smithy/openapi/model/ServerObject.java @@ -8,7 +8,7 @@ import java.util.Optional; import software.amazon.smithy.model.node.Node; import software.amazon.smithy.model.node.ObjectNode; -import software.amazon.smithy.utils.MapUtils; +import software.amazon.smithy.utils.BuilderRef; import software.amazon.smithy.utils.SmithyBuilder; import software.amazon.smithy.utils.ToSmithyBuilder; @@ -21,7 +21,7 @@ private ServerObject(Builder builder) { super(builder); url = SmithyBuilder.requiredState("url", builder.url); description = builder.description; - variables = MapUtils.copyOf(builder.variables); + variables = builder.variables.copy(); } public static Builder builder() { @@ -72,7 +72,7 @@ protected ObjectNode.Builder createNodeBuilder() { public static final class Builder extends Component.Builder { private String url; private String description; - private Map variables; + private final BuilderRef> variables = BuilderRef.forOrderedMap(); @Override public ServerObject build() { @@ -90,7 +90,8 @@ public Builder description(String description) { } public Builder variables(Map variables) { - this.variables = variables; + this.variables.clear(); + this.variables.get().putAll(variables); return this; } } diff --git a/smithy-protocol-test-traits/src/main/java/software/amazon/smithy/protocoltests/traits/HttpMalformedRequestDefinition.java b/smithy-protocol-test-traits/src/main/java/software/amazon/smithy/protocoltests/traits/HttpMalformedRequestDefinition.java index f49c784fe4a..80cdff25658 100644 --- a/smithy-protocol-test-traits/src/main/java/software/amazon/smithy/protocoltests/traits/HttpMalformedRequestDefinition.java +++ b/smithy-protocol-test-traits/src/main/java/software/amazon/smithy/protocoltests/traits/HttpMalformedRequestDefinition.java @@ -4,8 +4,6 @@ */ package software.amazon.smithy.protocoltests.traits; -import java.util.ArrayList; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; @@ -14,8 +12,7 @@ import software.amazon.smithy.model.node.ObjectNode; import software.amazon.smithy.model.node.StringNode; import software.amazon.smithy.model.node.ToNode; -import software.amazon.smithy.utils.ListUtils; -import software.amazon.smithy.utils.MapUtils; +import software.amazon.smithy.utils.BuilderRef; import software.amazon.smithy.utils.SmithyBuilder; import software.amazon.smithy.utils.SmithyUnstableApi; import software.amazon.smithy.utils.ToSmithyBuilder; @@ -46,9 +43,9 @@ private HttpMalformedRequestDefinition(Builder builder) { body = builder.body; bodyMediaType = builder.bodyMediaType; host = builder.host; - headers = MapUtils.copyOf(builder.headers); + headers = builder.headers.copy(); method = SmithyBuilder.requiredState(METHOD, builder.method); - queryParams = ListUtils.copyOf(builder.queryParams); + queryParams = builder.queryParams.copy(); uri = builder.uri; } @@ -144,9 +141,9 @@ public static final class Builder implements SmithyBuilder headers = new HashMap<>(); + private final BuilderRef> headers = BuilderRef.forOrderedMap(); private String method; - private final List queryParams = new ArrayList<>(); + private final BuilderRef> queryParams = BuilderRef.forList(); private String uri; private Builder() {} @@ -163,12 +160,12 @@ public Builder bodyMediaType(String bodyMediaType) { public Builder headers(Map headers) { this.headers.clear(); - this.headers.putAll(headers); + headers.forEach(this::putHeader); return this; } public Builder putHeader(String key, String value) { - this.headers.put(key, value); + this.headers.get().put(key, value); return this; } @@ -184,7 +181,7 @@ public Builder method(String method) { public Builder queryParams(List queryParams) { this.queryParams.clear(); - this.queryParams.addAll(queryParams); + this.queryParams.get().addAll(queryParams); return this; } diff --git a/smithy-protocol-test-traits/src/main/java/software/amazon/smithy/protocoltests/traits/HttpMalformedRequestTestCase.java b/smithy-protocol-test-traits/src/main/java/software/amazon/smithy/protocoltests/traits/HttpMalformedRequestTestCase.java index 80b40da0040..019c2223f21 100644 --- a/smithy-protocol-test-traits/src/main/java/software/amazon/smithy/protocoltests/traits/HttpMalformedRequestTestCase.java +++ b/smithy-protocol-test-traits/src/main/java/software/amazon/smithy/protocoltests/traits/HttpMalformedRequestTestCase.java @@ -4,12 +4,11 @@ */ package software.amazon.smithy.protocoltests.traits; -import java.util.ArrayList; import java.util.List; import java.util.Optional; import software.amazon.smithy.model.shapes.ShapeId; import software.amazon.smithy.model.shapes.ToShapeId; -import software.amazon.smithy.utils.ListUtils; +import software.amazon.smithy.utils.BuilderRef; import software.amazon.smithy.utils.SmithyBuilder; import software.amazon.smithy.utils.SmithyUnstableApi; import software.amazon.smithy.utils.Tagged; @@ -39,7 +38,7 @@ private HttpMalformedRequestTestCase(Builder builder) { protocol = SmithyBuilder.requiredState(PROTOCOL, builder.protocol); request = SmithyBuilder.requiredState(REQUEST, builder.request); response = SmithyBuilder.requiredState(RESPONSE, builder.response); - tags = ListUtils.copyOf(builder.tags); + tags = builder.tags.copy(); } public Optional getDocumentation() { @@ -93,7 +92,7 @@ public static final class Builder implements SmithyBuilder tags = new ArrayList<>(); + private final BuilderRef> tags = BuilderRef.forList(); private Builder() {} @@ -124,7 +123,7 @@ public Builder response(HttpMalformedResponseDefinition response) { public Builder tags(List tags) { this.tags.clear(); - this.tags.addAll(tags); + this.tags.get().addAll(tags); return this; } diff --git a/smithy-protocol-test-traits/src/main/java/software/amazon/smithy/protocoltests/traits/HttpMalformedResponseDefinition.java b/smithy-protocol-test-traits/src/main/java/software/amazon/smithy/protocoltests/traits/HttpMalformedResponseDefinition.java index fb11db41426..26511b0f7a3 100644 --- a/smithy-protocol-test-traits/src/main/java/software/amazon/smithy/protocoltests/traits/HttpMalformedResponseDefinition.java +++ b/smithy-protocol-test-traits/src/main/java/software/amazon/smithy/protocoltests/traits/HttpMalformedResponseDefinition.java @@ -4,13 +4,12 @@ */ package software.amazon.smithy.protocoltests.traits; -import java.util.HashMap; import java.util.Map; import java.util.Optional; import software.amazon.smithy.model.node.Node; import software.amazon.smithy.model.node.ObjectNode; import software.amazon.smithy.model.node.ToNode; -import software.amazon.smithy.utils.MapUtils; +import software.amazon.smithy.utils.BuilderRef; import software.amazon.smithy.utils.SmithyBuilder; import software.amazon.smithy.utils.SmithyUnstableApi; import software.amazon.smithy.utils.ToSmithyBuilder; @@ -32,7 +31,7 @@ public final class HttpMalformedResponseDefinition implements ToNode, ToSmithyBu private HttpMalformedResponseDefinition(Builder builder) { body = builder.body; code = builder.code; - headers = MapUtils.copyOf(builder.headers); + headers = builder.headers.copy(); } public Optional getBody() { @@ -90,7 +89,7 @@ public static final class Builder implements SmithyBuilder headers = new HashMap<>(); + private final BuilderRef> headers = BuilderRef.forOrderedMap(); private Builder() {} @@ -106,12 +105,12 @@ public Builder code(int code) { public Builder headers(Map headers) { this.headers.clear(); - this.headers.putAll(headers); + headers.forEach(this::putHeader); return this; } public Builder putHeader(String key, String value) { - this.headers.put(key, value); + this.headers.get().put(key, value); return this; } diff --git a/smithy-protocol-test-traits/src/main/java/software/amazon/smithy/protocoltests/traits/HttpMessageTestCase.java b/smithy-protocol-test-traits/src/main/java/software/amazon/smithy/protocoltests/traits/HttpMessageTestCase.java index 4b433090076..3a50178bcc0 100644 --- a/smithy-protocol-test-traits/src/main/java/software/amazon/smithy/protocoltests/traits/HttpMessageTestCase.java +++ b/smithy-protocol-test-traits/src/main/java/software/amazon/smithy/protocoltests/traits/HttpMessageTestCase.java @@ -4,19 +4,16 @@ */ package software.amazon.smithy.protocoltests.traits; -import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.TreeMap; import software.amazon.smithy.model.node.ArrayNode; import software.amazon.smithy.model.node.Node; import software.amazon.smithy.model.node.ObjectNode; import software.amazon.smithy.model.node.StringNode; import software.amazon.smithy.model.node.ToNode; import software.amazon.smithy.model.shapes.ShapeId; -import software.amazon.smithy.utils.ListUtils; +import software.amazon.smithy.utils.BuilderRef; import software.amazon.smithy.utils.SmithyBuilder; import software.amazon.smithy.utils.Tagged; @@ -62,10 +59,10 @@ public abstract class HttpMessageTestCase implements ToNode, Tagged { params = builder.params; vendorParamsShape = builder.vendorParamsShape; vendorParams = builder.vendorParams; - headers = Collections.unmodifiableMap(new TreeMap<>(builder.headers)); - forbidHeaders = ListUtils.copyOf(builder.forbidHeaders); - requireHeaders = ListUtils.copyOf(builder.requireHeaders); - tags = ListUtils.copyOf(builder.tags); + headers = builder.headers.copy(); + forbidHeaders = builder.forbidHeaders.copy(); + requireHeaders = builder.requireHeaders.copy(); + tags = builder.tags.copy(); appliesTo = builder.appliesTo; } @@ -243,10 +240,10 @@ abstract static class Builder, T extends HttpMessageTest private ShapeId vendorParamsShape; private ObjectNode vendorParams = Node.objectNode(); private AppliesTo appliesTo; - private final Map headers = new TreeMap<>(); - private final List forbidHeaders = new ArrayList<>(); - private final List requireHeaders = new ArrayList<>(); - private final List tags = new ArrayList<>(); + private final BuilderRef> headers = BuilderRef.forSortedMap(); + private final BuilderRef> forbidHeaders = BuilderRef.forList(); + private final BuilderRef> requireHeaders = BuilderRef.forList(); + private final BuilderRef> tags = BuilderRef.forList(); @SuppressWarnings("unchecked") public B id(String id) { @@ -305,34 +302,34 @@ public B vendorParams(ObjectNode vendorParams) { @SuppressWarnings("unchecked") public B headers(Map headers) { this.headers.clear(); - this.headers.putAll(headers); + headers.forEach(this::putHeader); return (B) this; } @SuppressWarnings("unchecked") public B putHeader(String key, String value) { - headers.put(key, value); + headers.get().put(key, value); return (B) this; } @SuppressWarnings("unchecked") public B forbidHeaders(List forbidHeaders) { this.forbidHeaders.clear(); - this.forbidHeaders.addAll(forbidHeaders); + this.forbidHeaders.get().addAll(forbidHeaders); return (B) this; } @SuppressWarnings("unchecked") public B requireHeaders(List requireHeaders) { this.requireHeaders.clear(); - this.requireHeaders.addAll(requireHeaders); + this.requireHeaders.get().addAll(requireHeaders); return (B) this; } @SuppressWarnings("unchecked") public B tags(List tags) { this.tags.clear(); - this.tags.addAll(tags); + this.tags.get().addAll(tags); return (B) this; } diff --git a/smithy-protocol-test-traits/src/main/java/software/amazon/smithy/protocoltests/traits/HttpRequestTestCase.java b/smithy-protocol-test-traits/src/main/java/software/amazon/smithy/protocoltests/traits/HttpRequestTestCase.java index a8ca00acbea..477dcccd6fa 100644 --- a/smithy-protocol-test-traits/src/main/java/software/amazon/smithy/protocoltests/traits/HttpRequestTestCase.java +++ b/smithy-protocol-test-traits/src/main/java/software/amazon/smithy/protocoltests/traits/HttpRequestTestCase.java @@ -4,14 +4,13 @@ */ package software.amazon.smithy.protocoltests.traits; -import java.util.ArrayList; import java.util.List; import java.util.Optional; import software.amazon.smithy.model.node.ArrayNode; import software.amazon.smithy.model.node.Node; import software.amazon.smithy.model.node.ObjectNode; import software.amazon.smithy.model.node.StringNode; -import software.amazon.smithy.utils.ListUtils; +import software.amazon.smithy.utils.BuilderRef; import software.amazon.smithy.utils.SmithyBuilder; import software.amazon.smithy.utils.ToSmithyBuilder; @@ -42,9 +41,9 @@ private HttpRequestTestCase(Builder builder) { uri = SmithyBuilder.requiredState(URI, builder.uri); host = builder.host; resolvedHost = builder.resolvedHost; - queryParams = ListUtils.copyOf(builder.queryParams); - forbidQueryParams = ListUtils.copyOf(builder.forbidQueryParams); - requireQueryParams = ListUtils.copyOf(builder.requireQueryParams); + queryParams = builder.queryParams.copy(); + forbidQueryParams = builder.forbidQueryParams.copy(); + requireQueryParams = builder.requireQueryParams.copy(); } public String getMethod() { @@ -141,9 +140,9 @@ public static final class Builder extends HttpMessageTestCase.Builder queryParams = new ArrayList<>(); - private final List forbidQueryParams = new ArrayList<>(); - private final List requireQueryParams = new ArrayList<>(); + private final BuilderRef> queryParams = BuilderRef.forList(); + private final BuilderRef> forbidQueryParams = BuilderRef.forList(); + private final BuilderRef> requireQueryParams = BuilderRef.forList(); private Builder() {} @@ -169,19 +168,19 @@ public Builder resolvedHost(String resolvedHost) { public Builder queryParams(List queryParams) { this.queryParams.clear(); - this.queryParams.addAll(queryParams); + this.queryParams.get().addAll(queryParams); return this; } public Builder forbidQueryParams(List forbidQueryParams) { this.forbidQueryParams.clear(); - this.forbidQueryParams.addAll(forbidQueryParams); + this.forbidQueryParams.get().addAll(forbidQueryParams); return this; } public Builder requireQueryParams(List requireQueryParams) { this.requireQueryParams.clear(); - this.requireQueryParams.addAll(requireQueryParams); + this.requireQueryParams.get().addAll(requireQueryParams); return this; } diff --git a/smithy-protocol-test-traits/src/main/java/software/amazon/smithy/protocoltests/traits/ParameterizedHttpMalformedRequestTestCase.java b/smithy-protocol-test-traits/src/main/java/software/amazon/smithy/protocoltests/traits/ParameterizedHttpMalformedRequestTestCase.java index 838eee6fd55..6a2dcc8f2b0 100644 --- a/smithy-protocol-test-traits/src/main/java/software/amazon/smithy/protocoltests/traits/ParameterizedHttpMalformedRequestTestCase.java +++ b/smithy-protocol-test-traits/src/main/java/software/amazon/smithy/protocoltests/traits/ParameterizedHttpMalformedRequestTestCase.java @@ -17,8 +17,8 @@ import software.amazon.smithy.model.node.ToNode; import software.amazon.smithy.model.shapes.ShapeId; import software.amazon.smithy.model.shapes.ToShapeId; +import software.amazon.smithy.utils.BuilderRef; import software.amazon.smithy.utils.ListUtils; -import software.amazon.smithy.utils.MapUtils; import software.amazon.smithy.utils.SimpleCodeWriter; import software.amazon.smithy.utils.SmithyBuilder; import software.amazon.smithy.utils.SmithyUnstableApi; @@ -57,8 +57,8 @@ private ParameterizedHttpMalformedRequestTestCase(Builder builder) { protocol = SmithyBuilder.requiredState(PROTOCOL, builder.protocol); request = SmithyBuilder.requiredState(REQUEST, builder.request); response = SmithyBuilder.requiredState(RESPONSE, builder.response); - tags = ListUtils.copyOf(builder.tags); - testParameters = MapUtils.copyOf(builder.testParameters); + tags = builder.tags.copy(); + testParameters = builder.testParameters.copy(); } public Optional getDocumentation() { @@ -236,8 +236,8 @@ public static final class Builder implements SmithyBuilder tags = new ArrayList<>(); - private final Map> testParameters = new HashMap<>(); + private final BuilderRef> tags = BuilderRef.forList(); + private final BuilderRef>> testParameters = BuilderRef.forOrderedMap(); private Builder() {} @@ -268,13 +268,13 @@ public Builder response(HttpMalformedResponseDefinition response) { public Builder tags(List tags) { this.tags.clear(); - this.tags.addAll(tags); + this.tags.get().addAll(tags); return this; } public Builder testParameters(Map> testParameters) { this.testParameters.clear(); - this.testParameters.putAll(testParameters); + this.testParameters.get().putAll(testParameters); return this; } diff --git a/smithy-rules-engine/src/main/java/software/amazon/smithy/rulesengine/language/syntax/parameters/Parameters.java b/smithy-rules-engine/src/main/java/software/amazon/smithy/rulesengine/language/syntax/parameters/Parameters.java index 76c90173c4c..95feeedbf54 100644 --- a/smithy-rules-engine/src/main/java/software/amazon/smithy/rulesengine/language/syntax/parameters/Parameters.java +++ b/smithy-rules-engine/src/main/java/software/amazon/smithy/rulesengine/language/syntax/parameters/Parameters.java @@ -4,7 +4,6 @@ */ package software.amazon.smithy.rulesengine.language.syntax.parameters; -import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -23,6 +22,7 @@ import software.amazon.smithy.rulesengine.language.evaluation.Scope; import software.amazon.smithy.rulesengine.language.evaluation.type.Type; import software.amazon.smithy.rulesengine.language.syntax.Identifier; +import software.amazon.smithy.utils.BuilderRef; import software.amazon.smithy.utils.SmithyUnstableApi; import software.amazon.smithy.utils.ToSmithyBuilder; @@ -35,7 +35,7 @@ public final class Parameters implements FromSourceLocation, ToNode, ToSmithyBui private final SourceLocation sourceLocation; private Parameters(Builder builder) { - this.parameters = builder.parameters; + this.parameters = builder.parameters.copy(); this.sourceLocation = builder.getSourceLocation(); } @@ -157,14 +157,14 @@ public String toString() { * A builder used to create a {@link Parameters} class. */ public static class Builder extends RulesComponentBuilder { - private final List parameters = new ArrayList<>(); + private final BuilderRef> parameters = BuilderRef.forList(); public Builder(FromSourceLocation sourceLocation) { super(sourceLocation); } public Builder addParameter(Parameter parameter) { - this.parameters.add(parameter); + this.parameters.get().add(parameter); return this; } diff --git a/smithy-smoke-test-traits/src/main/java/software/amazon/smithy/smoketests/traits/SmokeTestCase.java b/smithy-smoke-test-traits/src/main/java/software/amazon/smithy/smoketests/traits/SmokeTestCase.java index 2d877461a97..26f0f97a805 100644 --- a/smithy-smoke-test-traits/src/main/java/software/amazon/smithy/smoketests/traits/SmokeTestCase.java +++ b/smithy-smoke-test-traits/src/main/java/software/amazon/smithy/smoketests/traits/SmokeTestCase.java @@ -4,7 +4,6 @@ */ package software.amazon.smithy.smoketests.traits; -import java.util.ArrayList; import java.util.List; import java.util.Optional; import software.amazon.smithy.model.node.ArrayNode; @@ -13,7 +12,7 @@ import software.amazon.smithy.model.node.StringNode; import software.amazon.smithy.model.node.ToNode; import software.amazon.smithy.model.shapes.ShapeId; -import software.amazon.smithy.utils.ListUtils; +import software.amazon.smithy.utils.BuilderRef; import software.amazon.smithy.utils.SmithyBuilder; import software.amazon.smithy.utils.Tagged; import software.amazon.smithy.utils.ToSmithyBuilder; @@ -42,7 +41,7 @@ private SmokeTestCase(Builder builder) { this.vendorParams = builder.vendorParams; this.vendorParamsShape = builder.vendorParamsShape; this.expectation = SmithyBuilder.requiredState(EXPECT, builder.expectation); - this.tags = ListUtils.copyOf(builder.tags); + this.tags = builder.tags.copy(); } /** @@ -190,7 +189,7 @@ public static final class Builder implements SmithyBuilder { private ObjectNode vendorParams; private ShapeId vendorParamsShape; private Expectation expectation; - private final List tags = new ArrayList<>(); + private final BuilderRef> tags = BuilderRef.forList(); private Builder() {} @@ -271,7 +270,7 @@ public Builder expectation(Expectation expectation) { */ public Builder tags(List tags) { this.tags.clear(); - this.tags.addAll(tags); + this.tags.get().addAll(tags); return this; }