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; } 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")); + } }