From be0cc887aab43b20dc069ec1dc2a9f312342de55 Mon Sep 17 00:00:00 2001 From: Michael Dowling Date: Mon, 17 May 2021 22:45:21 -0700 Subject: [PATCH] Add methods to get shapes by type and trait Model now contains methods for every shape type to get a Set of shapes or that type or a set of shapes of a type that have a specific trait. These methods are simpler to use than `shapes(Class)` and `toSet(Class)`, and they hopefully encourage the use of the caches that Model uses. These methods also eliminated a lot of boilerplat that getShapesWithTrait previously required when only shapes of a certain type were needed. --- .../amazon/smithy/aws/traits/ArnIndex.java | 6 +- .../aws/traits/ArnTemplateValidator.java | 4 +- .../aws/traits/EventSourceValidator.java | 7 +- .../aws/traits/SdkServiceIdValidator.java | 7 +- .../CleanClientDiscoveryTraitTransformer.java | 32 +- .../ClientEndpointDiscoveryIndex.java | 30 +- .../ClientEndpointDiscoveryValidator.java | 6 +- .../software/amazon/smithy/model/Model.java | 439 ++++++++++++++++++ .../smithy/model/ShapeTypeFilteredSet.java | 115 +++++ .../smithy/model/knowledge/BottomUpIndex.java | 2 +- .../model/knowledge/EventStreamIndex.java | 2 +- .../model/knowledge/HttpBindingIndex.java | 14 +- .../knowledge/IdentifierBindingIndex.java | 2 +- .../smithy/model/knowledge/NullableIndex.java | 2 +- .../model/knowledge/OperationIndex.java | 2 +- .../model/knowledge/PaginatedIndex.java | 2 +- .../smithy/model/knowledge/TopDownIndex.java | 4 +- .../model/neighbor/NeighborVisitor.java | 4 +- .../plugins/CleanResourceReferences.java | 33 +- .../plugins/CleanTraitDefinitions.java | 55 ++- .../EventPayloadTraitValidator.java | 11 +- .../validators/ExamplesTraitValidator.java | 6 +- .../validators/HostLabelTraitValidator.java | 6 +- .../validators/HttpHeaderTraitValidator.java | 11 +- .../validators/HttpLabelTraitValidator.java | 6 +- .../HttpMethodSemanticsValidator.java | 7 +- .../validators/HttpPayloadValidator.java | 13 +- .../HttpPrefixHeadersTraitValidator.java | 8 +- .../HttpQueryParamsTraitValidator.java | 21 +- .../validators/HttpQueryTraitValidator.java | 21 +- .../HttpResponseCodeSemanticsValidator.java | 12 +- .../validators/PaginatedTraitValidator.java | 8 +- .../MqttSubscribeOutputValidator.java | 6 +- 33 files changed, 702 insertions(+), 202 deletions(-) create mode 100644 smithy-model/src/main/java/software/amazon/smithy/model/ShapeTypeFilteredSet.java diff --git a/smithy-aws-traits/src/main/java/software/amazon/smithy/aws/traits/ArnIndex.java b/smithy-aws-traits/src/main/java/software/amazon/smithy/aws/traits/ArnIndex.java index 499d132a4dd..cf87739c3bb 100644 --- a/smithy-aws-traits/src/main/java/software/amazon/smithy/aws/traits/ArnIndex.java +++ b/smithy-aws-traits/src/main/java/software/amazon/smithy/aws/traits/ArnIndex.java @@ -47,10 +47,8 @@ public final class ArnIndex implements KnowledgeIndex { public ArnIndex(Model model) { // Pre-compute the ARN services. - for (Shape shape : model.getShapesWithTrait(ServiceTrait.class)) { - shape.asServiceShape().ifPresent(service -> { - arnServices.put(service.getId(), service.expectTrait(ServiceTrait.class).getArnNamespace()); - }); + for (Shape service : model.getServiceShapesWithTrait(ServiceTrait.class)) { + arnServices.put(service.getId(), service.expectTrait(ServiceTrait.class).getArnNamespace()); } // Pre-compute all of the ArnTemplates in a service shape. diff --git a/smithy-aws-traits/src/main/java/software/amazon/smithy/aws/traits/ArnTemplateValidator.java b/smithy-aws-traits/src/main/java/software/amazon/smithy/aws/traits/ArnTemplateValidator.java index 698f9fcb3f0..7ff7ff470fa 100644 --- a/smithy-aws-traits/src/main/java/software/amazon/smithy/aws/traits/ArnTemplateValidator.java +++ b/smithy-aws-traits/src/main/java/software/amazon/smithy/aws/traits/ArnTemplateValidator.java @@ -48,8 +48,8 @@ public final class ArnTemplateValidator extends AbstractValidator { public List validate(Model model) { ArnIndex arnIndex = ArnIndex.of(model); List events = new ArrayList<>(); - for (Shape shape : model.getShapesWithTrait(ServiceTrait.class)) { - shape.asServiceShape().ifPresent(service -> events.addAll(validateService(model, arnIndex, service))); + for (ServiceShape service : model.getServiceShapesWithTrait(ServiceTrait.class)) { + events.addAll(validateService(model, arnIndex, service)); } return events; } diff --git a/smithy-aws-traits/src/main/java/software/amazon/smithy/aws/traits/EventSourceValidator.java b/smithy-aws-traits/src/main/java/software/amazon/smithy/aws/traits/EventSourceValidator.java index 7b4ebb71f40..73f931041d4 100644 --- a/smithy-aws-traits/src/main/java/software/amazon/smithy/aws/traits/EventSourceValidator.java +++ b/smithy-aws-traits/src/main/java/software/amazon/smithy/aws/traits/EventSourceValidator.java @@ -22,7 +22,6 @@ import java.util.Optional; import software.amazon.smithy.model.Model; import software.amazon.smithy.model.shapes.ServiceShape; -import software.amazon.smithy.model.shapes.Shape; import software.amazon.smithy.model.validation.AbstractValidator; import software.amazon.smithy.model.validation.ValidationEvent; import software.amazon.smithy.utils.MapUtils; @@ -44,10 +43,8 @@ public final class EventSourceValidator extends AbstractValidator { @Override public List validate(Model model) { List events = new ArrayList<>(); - for (Shape shape : model.getShapesWithTrait(ServiceTrait.class)) { - shape.asServiceShape() - .flatMap(service -> validateService(service, service.expectTrait(ServiceTrait.class))) - .ifPresent(events::add); + for (ServiceShape service : model.getServiceShapesWithTrait(ServiceTrait.class)) { + validateService(service, service.expectTrait(ServiceTrait.class)).ifPresent(events::add); } return events; } diff --git a/smithy-aws-traits/src/main/java/software/amazon/smithy/aws/traits/SdkServiceIdValidator.java b/smithy-aws-traits/src/main/java/software/amazon/smithy/aws/traits/SdkServiceIdValidator.java index 765044a5f3c..512be443d11 100644 --- a/smithy-aws-traits/src/main/java/software/amazon/smithy/aws/traits/SdkServiceIdValidator.java +++ b/smithy-aws-traits/src/main/java/software/amazon/smithy/aws/traits/SdkServiceIdValidator.java @@ -23,7 +23,6 @@ import java.util.regex.Pattern; import software.amazon.smithy.model.Model; import software.amazon.smithy.model.shapes.ServiceShape; -import software.amazon.smithy.model.shapes.Shape; import software.amazon.smithy.model.validation.AbstractValidator; import software.amazon.smithy.model.validation.ValidationEvent; import software.amazon.smithy.model.validation.ValidationUtils; @@ -71,10 +70,8 @@ public final class SdkServiceIdValidator extends AbstractValidator { @Override public List validate(Model model) { List events = new ArrayList<>(); - for (Shape shape : model.getShapesWithTrait(ServiceTrait.class)) { - shape.asServiceShape() - .flatMap(service -> validateService(service, service.expectTrait(ServiceTrait.class))) - .ifPresent(events::add); + for (ServiceShape service : model.getServiceShapesWithTrait(ServiceTrait.class)) { + validateService(service, service.expectTrait(ServiceTrait.class)).ifPresent(events::add); } return events; } diff --git a/smithy-aws-traits/src/main/java/software/amazon/smithy/aws/traits/clientendpointdiscovery/CleanClientDiscoveryTraitTransformer.java b/smithy-aws-traits/src/main/java/software/amazon/smithy/aws/traits/clientendpointdiscovery/CleanClientDiscoveryTraitTransformer.java index 7721a4f52f1..389b24c7000 100644 --- a/smithy-aws-traits/src/main/java/software/amazon/smithy/aws/traits/clientendpointdiscovery/CleanClientDiscoveryTraitTransformer.java +++ b/smithy-aws-traits/src/main/java/software/amazon/smithy/aws/traits/clientendpointdiscovery/CleanClientDiscoveryTraitTransformer.java @@ -62,15 +62,13 @@ public Model onRemove(ModelTransformer transformer, Collection shapes, Mo private Set getServicesToUpdate(Model model, Set removedOperations, Set removedErrors) { Set result = new HashSet<>(); - for (Shape shape : model.getShapesWithTrait(ClientEndpointDiscoveryTrait.class)) { - shape.asServiceShape().ifPresent(service -> { - ClientEndpointDiscoveryTrait trait = service.expectTrait(ClientEndpointDiscoveryTrait.class); - if (removedOperations.contains(trait.getOperation()) || removedErrors.contains(trait.getError())) { - ServiceShape.Builder builder = service.toBuilder(); - builder.removeTrait(ClientEndpointDiscoveryTrait.ID); - result.add(builder.build()); - } - }); + for (ServiceShape service : model.getServiceShapesWithTrait(ClientEndpointDiscoveryTrait.class)) { + ClientEndpointDiscoveryTrait trait = service.expectTrait(ClientEndpointDiscoveryTrait.class); + if (removedOperations.contains(trait.getOperation()) || removedErrors.contains(trait.getError())) { + ServiceShape.Builder builder = service.toBuilder(); + builder.removeTrait(ClientEndpointDiscoveryTrait.ID); + result.add(builder.build()); + } } return result; } @@ -92,15 +90,13 @@ private Set getOperationsToUpdate( // Get all endpoint discovery operations Set result = new HashSet<>(); - for (Shape shape : model.getShapesWithTrait(ClientDiscoveredEndpointTrait.class)) { - shape.asOperationShape().ifPresent(operation -> { - ClientDiscoveredEndpointTrait trait = operation.expectTrait(ClientDiscoveredEndpointTrait.class); - // Only get the ones where discovery is optional, as it is safe to remove in that case. - // Only get the ones that aren't still bound to a service that requires endpoint discovery. - if (!trait.isRequired() && !stillBoundOperations.contains(operation.getId())) { - result.add(operation.toBuilder().removeTrait(ClientDiscoveredEndpointTrait.ID).build()); - } - }); + for (OperationShape operation : model.getOperationShapesWithTrait(ClientDiscoveredEndpointTrait.class)) { + ClientDiscoveredEndpointTrait trait = operation.expectTrait(ClientDiscoveredEndpointTrait.class); + // Only get the ones where discovery is optional, as it is safe to remove in that case. + // Only get the ones that aren't still bound to a service that requires endpoint discovery. + if (!trait.isRequired() && !stillBoundOperations.contains(operation.getId())) { + result.add(operation.toBuilder().removeTrait(ClientDiscoveredEndpointTrait.ID).build()); + } } return result; } diff --git a/smithy-aws-traits/src/main/java/software/amazon/smithy/aws/traits/clientendpointdiscovery/ClientEndpointDiscoveryIndex.java b/smithy-aws-traits/src/main/java/software/amazon/smithy/aws/traits/clientendpointdiscovery/ClientEndpointDiscoveryIndex.java index 38a77dbe006..76e162bdcaa 100644 --- a/smithy-aws-traits/src/main/java/software/amazon/smithy/aws/traits/clientendpointdiscovery/ClientEndpointDiscoveryIndex.java +++ b/smithy-aws-traits/src/main/java/software/amazon/smithy/aws/traits/clientendpointdiscovery/ClientEndpointDiscoveryIndex.java @@ -41,25 +41,23 @@ public ClientEndpointDiscoveryIndex(Model model) { TopDownIndex topDownIndex = TopDownIndex.of(model); OperationIndex opIndex = OperationIndex.of(model); - for (Shape shape : model.getShapesWithTrait(ClientEndpointDiscoveryTrait.class)) { - shape.asServiceShape().ifPresent(service -> { - ClientEndpointDiscoveryTrait trait = service.expectTrait(ClientEndpointDiscoveryTrait.class); - ShapeId endpointOperationId = trait.getOperation(); - ShapeId endpointErrorId = trait.getError(); + for (ServiceShape service : model.getServiceShapesWithTrait(ClientEndpointDiscoveryTrait.class)) { + ClientEndpointDiscoveryTrait trait = service.expectTrait(ClientEndpointDiscoveryTrait.class); + ShapeId endpointOperationId = trait.getOperation(); + ShapeId endpointErrorId = trait.getError(); - Optional endpointOperation = model.getShape(endpointOperationId) - .flatMap(Shape::asOperationShape); - Optional endpointError = model.getShape(endpointErrorId) - .flatMap(Shape::asStructureShape); + Optional endpointOperation = model.getShape(endpointOperationId) + .flatMap(Shape::asOperationShape); + Optional endpointError = model.getShape(endpointErrorId) + .flatMap(Shape::asStructureShape); - if (endpointOperation.isPresent() && endpointError.isPresent()) { - Map serviceInfo = getOperations( - service, endpointOperation.get(), endpointError.get(), topDownIndex, opIndex); - if (!serviceInfo.isEmpty()) { - endpointDiscoveryInfo.put(service.getId(), serviceInfo); - } + if (endpointOperation.isPresent() && endpointError.isPresent()) { + Map serviceInfo = getOperations( + service, endpointOperation.get(), endpointError.get(), topDownIndex, opIndex); + if (!serviceInfo.isEmpty()) { + endpointDiscoveryInfo.put(service.getId(), serviceInfo); } - }); + } } } diff --git a/smithy-aws-traits/src/main/java/software/amazon/smithy/aws/traits/clientendpointdiscovery/ClientEndpointDiscoveryValidator.java b/smithy-aws-traits/src/main/java/software/amazon/smithy/aws/traits/clientendpointdiscovery/ClientEndpointDiscoveryValidator.java index f27b266f6bf..2cb0fc5fcad 100644 --- a/smithy-aws-traits/src/main/java/software/amazon/smithy/aws/traits/clientendpointdiscovery/ClientEndpointDiscoveryValidator.java +++ b/smithy-aws-traits/src/main/java/software/amazon/smithy/aws/traits/clientendpointdiscovery/ClientEndpointDiscoveryValidator.java @@ -48,10 +48,8 @@ public List validate(Model model) { OperationIndex opIndex = OperationIndex.of(model); Map endpointDiscoveryServices = new HashMap<>(); - for (Shape shape : model.getShapesWithTrait(ClientEndpointDiscoveryTrait.class)) { - shape.asServiceShape().ifPresent(service -> { - endpointDiscoveryServices.put(service, service.expectTrait(ClientEndpointDiscoveryTrait.class)); - }); + for (ServiceShape service : model.getServiceShapesWithTrait(ClientEndpointDiscoveryTrait.class)) { + endpointDiscoveryServices.put(service, service.expectTrait(ClientEndpointDiscoveryTrait.class)); } List validationEvents = endpointDiscoveryServices.values().stream() diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/Model.java b/smithy-model/src/main/java/software/amazon/smithy/model/Model.java index ea3bd26dbfc..9dd82670400 100644 --- a/smithy-model/src/main/java/software/amazon/smithy/model/Model.java +++ b/smithy-model/src/main/java/software/amazon/smithy/model/Model.java @@ -33,11 +33,32 @@ import software.amazon.smithy.model.loader.ModelAssembler; import software.amazon.smithy.model.node.ExpectationNotMetException; import software.amazon.smithy.model.node.Node; +import software.amazon.smithy.model.shapes.BigDecimalShape; +import software.amazon.smithy.model.shapes.BigIntegerShape; +import software.amazon.smithy.model.shapes.BlobShape; +import software.amazon.smithy.model.shapes.BooleanShape; +import software.amazon.smithy.model.shapes.ByteShape; +import software.amazon.smithy.model.shapes.DocumentShape; +import software.amazon.smithy.model.shapes.DoubleShape; +import software.amazon.smithy.model.shapes.FloatShape; +import software.amazon.smithy.model.shapes.IntegerShape; +import software.amazon.smithy.model.shapes.ListShape; +import software.amazon.smithy.model.shapes.LongShape; +import software.amazon.smithy.model.shapes.MapShape; import software.amazon.smithy.model.shapes.MemberShape; import software.amazon.smithy.model.shapes.NumberShape; +import software.amazon.smithy.model.shapes.OperationShape; +import software.amazon.smithy.model.shapes.ResourceShape; +import software.amazon.smithy.model.shapes.ServiceShape; +import software.amazon.smithy.model.shapes.SetShape; import software.amazon.smithy.model.shapes.Shape; import software.amazon.smithy.model.shapes.ShapeId; +import software.amazon.smithy.model.shapes.ShortShape; +import software.amazon.smithy.model.shapes.StringShape; +import software.amazon.smithy.model.shapes.StructureShape; +import software.amazon.smithy.model.shapes.TimestampShape; import software.amazon.smithy.model.shapes.ToShapeId; +import software.amazon.smithy.model.shapes.UnionShape; import software.amazon.smithy.model.traits.Trait; import software.amazon.smithy.model.traits.TraitDefinition; import software.amazon.smithy.model.traits.TraitFactory; @@ -192,6 +213,424 @@ public Set getShapesWithTrait(Class trait) { return Collections.unmodifiableSet(mappings.getOrDefault(trait, Collections.emptySet())); } + /** + * Gets an immutable set of all bigDecimals in the Model. + * + * @return Returns the Set of {@code bigDecimals}s. + */ + public Set getBigDecimalShapes() { + return toSet(BigDecimalShape.class); + } + + /** + * Gets an immutable set of all bigDecimals in the Model that have a specific trait. + * + * @param trait The exact trait class to look for on shapes. + * @return Returns the set of {@code bigdecimal}s that have a specific trait. + */ + public Set getBigDecimalShapesWithTrait(Class trait) { + return new ShapeTypeFilteredSet<>(getShapesWithTrait(trait), BigDecimalShape.class); + } + + /** + * Gets an immutable set of all bigIntegers in the Model. + * + * @return Returns the Set of {@code bigIntegers}s. + */ + public Set getBigIntegerShapes() { + return toSet(BigIntegerShape.class); + } + + /** + * Gets an immutable set of all bigIntegers in the Model that have a specific trait. + * + * @param trait The exact trait class to look for on shapes. + * @return Returns the set of {@code bigIntegers}s that have a specific trait. + */ + public Set getBigIntegerShapesWithTrait(Class trait) { + return new ShapeTypeFilteredSet<>(getShapesWithTrait(trait), BigIntegerShape.class); + } + + /** + * Gets an immutable set of all blobs in the Model. + * + * @return Returns the Set of {@code blob}s. + */ + public Set getBlobShapes() { + return toSet(BlobShape.class); + } + + /** + * Gets an immutable set of all blobs in the Model that have a specific trait. + * + * @param trait The exact trait class to look for on shapes. + * @return Returns the set of {@code blob}s that have a specific trait. + */ + public Set getBlobShapesWithTrait(Class trait) { + return new ShapeTypeFilteredSet<>(getShapesWithTrait(trait), BlobShape.class); + } + + /** + * Gets an immutable set of all booleans in the Model. + * + * @return Returns the Set of {@code boolean}s. + */ + public Set getBooleanShapes() { + return toSet(BooleanShape.class); + } + + /** + * Gets an immutable set of all booleans in the Model that have a specific trait. + * + * @param trait The exact trait class to look for on shapes. + * @return Returns the set of {@code boolean}s that have a specific trait. + */ + public Set getBooleanShapesWithTrait(Class trait) { + return new ShapeTypeFilteredSet<>(getShapesWithTrait(trait), BooleanShape.class); + } + + /** + * Gets an immutable set of all bytes in the Model. + * + * @return Returns the Set of {@code byte}s. + */ + public Set getByteShapes() { + return toSet(ByteShape.class); + } + + /** + * Gets an immutable set of all bytes in the Model that have a specific trait. + * + * @param trait The exact trait class to look for on shapes. + * @return Returns the set of {@code byte}s that have a specific trait. + */ + public Set getByteShapesWithTrait(Class trait) { + return new ShapeTypeFilteredSet<>(getShapesWithTrait(trait), ByteShape.class); + } + + /** + * Gets an immutable set of all documents in the Model. + * + * @return Returns the Set of {@code document}s. + */ + public Set getDocumentShapes() { + return toSet(DocumentShape.class); + } + + /** + * Gets an immutable set of all documents in the Model that have a specific trait. + * + * @param trait The exact trait class to look for on shapes. + * @return Returns the set of {@code document}s that have a specific trait. + */ + public Set getDocumentShapesWithTrait(Class trait) { + return new ShapeTypeFilteredSet<>(getShapesWithTrait(trait), DocumentShape.class); + } + + /** + * Gets an immutable set of all doubles in the Model. + * + * @return Returns the Set of {@code double}s. + */ + public Set getDoubleShapes() { + return toSet(DoubleShape.class); + } + + /** + * Gets an immutable set of all doubles in the Model that have a specific trait. + * + * @param trait The exact trait class to look for on shapes. + * @return Returns the set of {@code double}s that have a specific trait. + */ + public Set getDoubleShapesWithTrait(Class trait) { + return new ShapeTypeFilteredSet<>(getShapesWithTrait(trait), DoubleShape.class); + } + + /** + * Gets an immutable set of all floats in the Model. + * + * @return Returns the Set of {@code float}s. + */ + public Set getFloatShapes() { + return toSet(FloatShape.class); + } + + /** + * Gets an immutable set of all floats in the Model that have a specific trait. + * + * @param trait The exact trait class to look for on shapes. + * @return Returns the set of {@code float}s that have a specific trait. + */ + public Set getFloatShapesWithTrait(Class trait) { + return new ShapeTypeFilteredSet<>(getShapesWithTrait(trait), FloatShape.class); + } + + /** + * Gets an immutable set of all integers in the Model. + * + * @return Returns the Set of {@code integer}s. + */ + public Set getIntegerShapes() { + return toSet(IntegerShape.class); + } + + /** + * Gets an immutable set of all integers in the Model that have a specific trait. + * + * @param trait The exact trait class to look for on shapes. + * @return Returns the set of {@code integer}s that have a specific trait. + */ + public Set getIntegerShapesWithTrait(Class trait) { + return new ShapeTypeFilteredSet<>(getShapesWithTrait(trait), IntegerShape.class); + } + + /** + * Gets an immutable set of all lists in the Model. + * + * @return Returns the Set of {@code list}s. + */ + public Set getListShapes() { + return toSet(ListShape.class); + } + + /** + * Gets an immutable set of all lists in the Model that have a specific trait. + * + * @param trait The exact trait class to look for on shapes. + * @return Returns the set of {@code list}s that have a specific trait. + */ + public Set getListShapesWithTrait(Class trait) { + return new ShapeTypeFilteredSet<>(getShapesWithTrait(trait), ListShape.class); + } + + /** + * Gets an immutable set of all longs in the Model. + * + * @return Returns the Set of {@code long}s. + */ + public Set getLongShapes() { + return toSet(LongShape.class); + } + + /** + * Gets an immutable set of all longs in the Model that have a specific trait. + * + * @param trait The exact trait class to look for on shapes. + * @return Returns the set of {@code long}s that have a specific trait. + */ + public Set getLongShapesWithTrait(Class trait) { + return new ShapeTypeFilteredSet<>(getShapesWithTrait(trait), LongShape.class); + } + + /** + * Gets an immutable set of all maps in the Model. + * + * @return Returns the Set of {@code map}s. + */ + public Set getMapShapes() { + return toSet(MapShape.class); + } + + /** + * Gets an immutable set of all maps in the Model that have a specific trait. + * + * @param trait The exact trait class to look for on shapes. + * @return Returns the set of {@code map}s that have a specific trait. + */ + public Set getMapShapesWithTrait(Class trait) { + return new ShapeTypeFilteredSet<>(getShapesWithTrait(trait), MapShape.class); + } + + /** + * Gets an immutable set of all members in the Model. + * + * @return Returns the Set of {@code member}s. + */ + public Set getMemberShapes() { + return toSet(MemberShape.class); + } + + /** + * Gets an immutable set of all members in the Model that have a specific trait. + * + * @param trait The exact trait class to look for on shapes. + * @return Returns the set of {@code member}s that have a specific trait. + */ + public Set getMemberShapesWithTrait(Class trait) { + return new ShapeTypeFilteredSet<>(getShapesWithTrait(trait), MemberShape.class); + } + + /** + * Gets an immutable set of all operations in the Model. + * + * @return Returns the Set of {@code operation}s. + */ + public Set getOperationShapes() { + return toSet(OperationShape.class); + } + + /** + * Gets an immutable set of all operations in the Model that have a specific trait. + * + * @param trait The exact trait class to look for on shapes. + * @return Returns the set of {@code operation}s that have a specific trait. + */ + public Set getOperationShapesWithTrait(Class trait) { + return new ShapeTypeFilteredSet<>(getShapesWithTrait(trait), OperationShape.class); + } + + /** + * Gets an immutable set of all resources in the Model. + * + * @return Returns the Set of {@code resource}s. + */ + public Set getResourceShapes() { + return toSet(ResourceShape.class); + } + + /** + * Gets an immutable set of all resources in the Model that have a specific trait. + * + * @param trait The exact trait class to look for on shapes. + * @return Returns the set of {@code resource}s that have a specific trait. + */ + public Set getResourceShapesWithTrait(Class trait) { + return new ShapeTypeFilteredSet<>(getShapesWithTrait(trait), ResourceShape.class); + } + + /** + * Gets an immutable set of all services in the Model. + * + * @return Returns the Set of {@code service}s. + */ + public Set getServiceShapes() { + return toSet(ServiceShape.class); + } + + /** + * Gets an immutable set of all services in the Model that have a specific trait. + * + * @param trait The exact trait class to look for on shapes. + * @return Returns the set of {@code service}s that have a specific trait. + */ + public Set getServiceShapesWithTrait(Class trait) { + return new ShapeTypeFilteredSet<>(getShapesWithTrait(trait), ServiceShape.class); + } + + /** + * Gets an immutable set of all sets in the Model. + * + * @return Returns the Set of {@code set}s. + */ + public Set getSetShapes() { + return toSet(SetShape.class); + } + + /** + * Gets an immutable set of all sets in the Model that have a specific trait. + * + * @param trait The exact trait class to look for on shapes. + * @return Returns the set of {@code set}s that have a specific trait. + */ + public Set getSetShapesWithTrait(Class trait) { + return new ShapeTypeFilteredSet<>(getShapesWithTrait(trait), SetShape.class); + } + + /** + * Gets an immutable set of all shorts in the Model. + * + * @return Returns the Set of {@code short}s. + */ + public Set getShortShapes() { + return toSet(ShortShape.class); + } + + /** + * Gets an immutable set of all shorts in the Model that have a specific trait. + * + * @param trait The exact trait class to look for on shapes. + * @return Returns the set of {@code short}s that have a specific trait. + */ + public Set getShortShapesWithTrait(Class trait) { + return new ShapeTypeFilteredSet<>(getShapesWithTrait(trait), ShortShape.class); + } + + /** + * Gets an immutable set of all strings in the Model. + * + * @return Returns the Set of {@code string}s. + */ + public Set getStringShapes() { + return toSet(StringShape.class); + } + + /** + * Gets an immutable set of all strings in the Model that have a specific trait. + * + * @param trait The exact trait class to look for on shapes. + * @return Returns the set of {@code string}s that have a specific trait. + */ + public Set getStringShapesWithTrait(Class trait) { + return new ShapeTypeFilteredSet<>(getShapesWithTrait(trait), StringShape.class); + } + + /** + * Gets an immutable set of all structures in the Model. + * + * @return Returns the Set of {@code structure}s. + */ + public Set getStructureShapes() { + return toSet(StructureShape.class); + } + + /** + * Gets an immutable set of all structures in the Model that have a specific trait. + * + * @param trait The exact trait class to look for on shapes. + * @return Returns the set of {@code structure}s that have a specific trait. + */ + public Set getStructureShapesWithTrait(Class trait) { + return new ShapeTypeFilteredSet<>(getShapesWithTrait(trait), StructureShape.class); + } + + /** + * Gets an immutable set of all timestamps in the Model. + * + * @return Returns the Set of {@code timestamp}s. + */ + public Set getTimestampShapes() { + return toSet(TimestampShape.class); + } + + /** + * Gets an immutable set of all timestamps in the Model that have a specific trait. + * + * @param trait The exact trait class to look for on shapes. + * @return Returns the set of {@code timestamp}s that have a specific trait. + */ + public Set getTimestampShapesWithTrait(Class trait) { + return new ShapeTypeFilteredSet<>(getShapesWithTrait(trait), TimestampShape.class); + } + + /** + * Gets an immutable set of all unions in the Model. + * + * @return Returns the Set of {@code union}s. + */ + public Set getUnionShapes() { + return toSet(UnionShape.class); + } + + /** + * Gets an immutable set of all unions in the Model that have a specific trait. + * + * @param trait The exact trait class to look for on shapes. + * @return Returns the set of {@code union}s that have a specific trait. + */ + public Set getUnionShapesWithTrait(Class trait) { + return new ShapeTypeFilteredSet<>(getShapesWithTrait(trait), UnionShape.class); + } + /** * Gets a set of every trait shape ID that is used in the model. * diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/ShapeTypeFilteredSet.java b/smithy-model/src/main/java/software/amazon/smithy/model/ShapeTypeFilteredSet.java new file mode 100644 index 00000000000..b991f25f86d --- /dev/null +++ b/smithy-model/src/main/java/software/amazon/smithy/model/ShapeTypeFilteredSet.java @@ -0,0 +1,115 @@ +/* + * Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package software.amazon.smithy.model; + +import java.util.AbstractSet; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.Set; +import software.amazon.smithy.model.shapes.Shape; + +/** + * Provides a view of a set returned by the getXwithTrait methods so that only + * shapes of a specific type are treated as present within the set. + * + * @param Type of shape to project out of the Set. + */ +final class ShapeTypeFilteredSet extends AbstractSet { + + private final Set shapes; + private final Class shapeType; + + // -1 means that the size is yet to be computed and cached. + private volatile int size = -1; + + ShapeTypeFilteredSet(Set shapes, Class shapeType) { + this.shapes = shapes; + this.shapeType = shapeType; + } + + @Override + public boolean contains(Object o) { + return o.getClass() == shapeType && super.contains(o); + } + + @Override + public Iterator iterator() { + return new FilteredIterator<>(shapes.iterator(), shapeType); + } + + @Override + public int size() { + // Computing the size of the set is O(N) because we need to iterate + // over every value and test if it's of the right type. The size is + // cached to avoid doing this repeatedly. + int result = size; + + if (result == -1) { + result = 0; + for (Shape shape : shapes) { + if (shapeType == shape.getClass()) { + result++; + } + } + size = result; + } + + return result; + } + + private static final class FilteredIterator implements Iterator { + private final Iterator iterator; + private final Class shapeType; + private T next; + + FilteredIterator(Iterator iterator, Class shapeType) { + this.iterator = iterator; + this.shapeType = shapeType; + + // Always compute the first element in the iterator. + next = computeNext(); + } + + @SuppressWarnings("unchecked") + private T computeNext() { + // Filter out shapes of other types. + while (iterator.hasNext()) { + Shape nextCandidate = iterator.next(); + if (shapeType == nextCandidate.getClass()) { + return (T) nextCandidate; + } + } + return null; + } + + @Override + public boolean hasNext() { + return next != null; + } + + @Override + public T next() { + if (next == null) { + throw new NoSuchElementException("No more shapes in iterator"); + } + + T result = next; + next = computeNext(); + + return result; + } + } +} diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/knowledge/BottomUpIndex.java b/smithy-model/src/main/java/software/amazon/smithy/model/knowledge/BottomUpIndex.java index 09c1a073091..5c157c28158 100644 --- a/smithy-model/src/main/java/software/amazon/smithy/model/knowledge/BottomUpIndex.java +++ b/smithy-model/src/main/java/software/amazon/smithy/model/knowledge/BottomUpIndex.java @@ -41,7 +41,7 @@ public final class BottomUpIndex implements KnowledgeIndex { public BottomUpIndex(Model model) { PathFinder pathFinder = PathFinder.create(model); - for (ServiceShape service : model.toSet(ServiceShape.class)) { + for (ServiceShape service : model.getServiceShapes()) { Map> serviceBindings = new HashMap<>(); parentBindings.put(service.getId(), serviceBindings); for (PathFinder.Path path : pathFinder.search(service, SELECTOR)) { diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/knowledge/EventStreamIndex.java b/smithy-model/src/main/java/software/amazon/smithy/model/knowledge/EventStreamIndex.java index 6d2e8e42f29..8f1b2fb6fd1 100644 --- a/smithy-model/src/main/java/software/amazon/smithy/model/knowledge/EventStreamIndex.java +++ b/smithy-model/src/main/java/software/amazon/smithy/model/knowledge/EventStreamIndex.java @@ -45,7 +45,7 @@ public final class EventStreamIndex implements KnowledgeIndex { public EventStreamIndex(Model model) { OperationIndex operationIndex = OperationIndex.of(model); - for (OperationShape operation : model.toSet(OperationShape.class)) { + for (OperationShape operation : model.getOperationShapes()) { operationIndex.getInput(operation).ifPresent(input -> { computeEvents(model, operation, input, inputInfo); }); diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/knowledge/HttpBindingIndex.java b/smithy-model/src/main/java/software/amazon/smithy/model/knowledge/HttpBindingIndex.java index 8f070c85e70..94223be6f94 100644 --- a/smithy-model/src/main/java/software/amazon/smithy/model/knowledge/HttpBindingIndex.java +++ b/smithy-model/src/main/java/software/amazon/smithy/model/knowledge/HttpBindingIndex.java @@ -67,18 +67,14 @@ public HttpBindingIndex(Model model) { this.model = new WeakReference<>(model); OperationIndex opIndex = OperationIndex.of(model); - for (Shape shape : model.getShapesWithTrait(HttpTrait.class)) { - shape.asOperationShape().ifPresent(operation -> { - requestBindings.put(operation.getId(), computeRequestBindings(opIndex, operation)); - responseBindings.put(operation.getId(), computeResponseBindings(opIndex, operation)); - }); + for (OperationShape operation : model.getOperationShapesWithTrait(HttpTrait.class)) { + requestBindings.put(operation.getId(), computeRequestBindings(opIndex, operation)); + responseBindings.put(operation.getId(), computeResponseBindings(opIndex, operation)); } // Add error structure bindings. - for (Shape shape : model.getShapesWithTrait(ErrorTrait.class)) { - shape.asStructureShape().ifPresent(structure -> { - responseBindings.put(structure.getId(), createStructureBindings(structure, false)); - }); + for (StructureShape structure : model.getStructureShapesWithTrait(ErrorTrait.class)) { + responseBindings.put(structure.getId(), createStructureBindings(structure, false)); } } diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/knowledge/IdentifierBindingIndex.java b/smithy-model/src/main/java/software/amazon/smithy/model/knowledge/IdentifierBindingIndex.java index 74492b7efff..f60d5c4ac27 100644 --- a/smithy-model/src/main/java/software/amazon/smithy/model/knowledge/IdentifierBindingIndex.java +++ b/smithy-model/src/main/java/software/amazon/smithy/model/knowledge/IdentifierBindingIndex.java @@ -53,7 +53,7 @@ public enum BindingType { public IdentifierBindingIndex(Model model) { OperationIndex operationIndex = OperationIndex.of(model); - for (ResourceShape resource : model.toSet(ResourceShape.class)) { + for (ResourceShape resource : model.getResourceShapes()) { processResource(resource, operationIndex, model); } } diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/knowledge/NullableIndex.java b/smithy-model/src/main/java/software/amazon/smithy/model/knowledge/NullableIndex.java index fee0b488b70..4324aecedd0 100644 --- a/smithy-model/src/main/java/software/amazon/smithy/model/knowledge/NullableIndex.java +++ b/smithy-model/src/main/java/software/amazon/smithy/model/knowledge/NullableIndex.java @@ -60,7 +60,7 @@ public NullableIndex(Model model) { } } - for (MemberShape member : model.toSet(MemberShape.class)) { + for (MemberShape member : model.getMemberShapes()) { if (isMemberNullable(model, member)) { nullableShapes.add(member.getId()); } diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/knowledge/OperationIndex.java b/smithy-model/src/main/java/software/amazon/smithy/model/knowledge/OperationIndex.java index 60fbf1fbb62..98ec4a0b82a 100644 --- a/smithy-model/src/main/java/software/amazon/smithy/model/knowledge/OperationIndex.java +++ b/smithy-model/src/main/java/software/amazon/smithy/model/knowledge/OperationIndex.java @@ -43,7 +43,7 @@ public final class OperationIndex implements KnowledgeIndex { private final Map> errors = new HashMap<>(); public OperationIndex(Model model) { - for (OperationShape operation : model.toSet(OperationShape.class)) { + for (OperationShape operation : model.getOperationShapes()) { operation.getInput() .flatMap(id -> getStructure(model, id)) .ifPresent(shape -> inputs.put(operation.getId(), shape)); diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/knowledge/PaginatedIndex.java b/smithy-model/src/main/java/software/amazon/smithy/model/knowledge/PaginatedIndex.java index 830336d7ca6..4aab7e64fbd 100644 --- a/smithy-model/src/main/java/software/amazon/smithy/model/knowledge/PaginatedIndex.java +++ b/smithy-model/src/main/java/software/amazon/smithy/model/knowledge/PaginatedIndex.java @@ -49,7 +49,7 @@ public PaginatedIndex(Model model) { TopDownIndex topDownIndex = TopDownIndex.of(model); OperationIndex opIndex = OperationIndex.of(model); - for (ServiceShape service : model.toSet(ServiceShape.class)) { + for (ServiceShape service : model.getServiceShapes()) { PaginatedTrait serviceTrait = service.getTrait(PaginatedTrait.class).orElse(null); Map mappings = new HashMap<>(); for (OperationShape operation : topDownIndex.getContainedOperations(service)) { diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/knowledge/TopDownIndex.java b/smithy-model/src/main/java/software/amazon/smithy/model/knowledge/TopDownIndex.java index f854f2bd3ce..218bdd1df47 100644 --- a/smithy-model/src/main/java/software/amazon/smithy/model/knowledge/TopDownIndex.java +++ b/smithy-model/src/main/java/software/amazon/smithy/model/knowledge/TopDownIndex.java @@ -62,11 +62,11 @@ public TopDownIndex(Model model) { } }; - for (ResourceShape resource : model.toSet(ResourceShape.class)) { + for (ResourceShape resource : model.getResourceShapes()) { findContained(resource.getId(), walker.walkShapes(resource, filter)); } - for (ServiceShape service : model.toSet(ServiceShape.class)) { + for (ServiceShape service : model.getServiceShapes()) { findContained(service.getId(), walker.walkShapes(service, filter)); } } diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/neighbor/NeighborVisitor.java b/smithy-model/src/main/java/software/amazon/smithy/model/neighbor/NeighborVisitor.java index 2f9c747505c..756da6c36d7 100644 --- a/smithy-model/src/main/java/software/amazon/smithy/model/neighbor/NeighborVisitor.java +++ b/smithy-model/src/main/java/software/amazon/smithy/model/neighbor/NeighborVisitor.java @@ -128,12 +128,12 @@ public List resourceShape(ResourceShape shape) { relationship(shape, RelationshipType.INSTANCE_OPERATION, id))); // Find resource shapes that bind this resource to it. - for (ResourceShape resource : model.toSet(ResourceShape.class)) { + for (ResourceShape resource : model.getResourceShapes()) { addServiceAndResourceBindings(result, shape, resource); } // Find service shapes that bind this resource to it. - for (ServiceShape service : model.toSet(ServiceShape.class)) { + for (ServiceShape service : model.getServiceShapes()) { addServiceAndResourceBindings(result, shape, service); } diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/transform/plugins/CleanResourceReferences.java b/smithy-model/src/main/java/software/amazon/smithy/model/transform/plugins/CleanResourceReferences.java index 5f0cbc0f2c1..c239e333678 100644 --- a/smithy-model/src/main/java/software/amazon/smithy/model/transform/plugins/CleanResourceReferences.java +++ b/smithy-model/src/main/java/software/amazon/smithy/model/transform/plugins/CleanResourceReferences.java @@ -21,6 +21,7 @@ import java.util.Set; import software.amazon.smithy.model.Model; import software.amazon.smithy.model.shapes.Shape; +import software.amazon.smithy.model.shapes.StructureShape; import software.amazon.smithy.model.traits.ReferencesTrait; import software.amazon.smithy.model.transform.ModelTransformer; import software.amazon.smithy.model.transform.ModelTransformerPlugin; @@ -40,28 +41,26 @@ public Model onRemove(ModelTransformer transformer, Collection shapes, Mo private Set getAffectedStructures(Model model, Shape resource) { Set result = new HashSet<>(); - for (Shape shape : model.getShapesWithTrait(ReferencesTrait.class)) { + for (StructureShape struct : model.getStructureShapesWithTrait(ReferencesTrait.class)) { // References can also be on strings, but we only care about structs. - shape.asStructureShape().ifPresent(struct -> { - ReferencesTrait trait = struct.expectTrait(ReferencesTrait.class); - // Get the reference to a particular shape. - List references = trait.getResourceReferences(resource.getId()); + ReferencesTrait trait = struct.expectTrait(ReferencesTrait.class); + // Get the reference to a particular shape. + List references = trait.getResourceReferences(resource.getId()); - if (!references.isEmpty()) { - // If the trait contains a reference to the resource, then create a new version of the - // trait and shape that no longer reference the resource. - ReferencesTrait.Builder traitBuilder = trait.toBuilder(); - traitBuilder.clearReferences(); + if (!references.isEmpty()) { + // If the trait contains a reference to the resource, then create a new version of the + // trait and shape that no longer reference the resource. + ReferencesTrait.Builder traitBuilder = trait.toBuilder(); + traitBuilder.clearReferences(); - for (ReferencesTrait.Reference ref : trait.getReferences()) { - if (!references.contains(ref)) { - traitBuilder.addReference(ref); - } + for (ReferencesTrait.Reference ref : trait.getReferences()) { + if (!references.contains(ref)) { + traitBuilder.addReference(ref); } - - result.add(struct.toBuilder().addTrait(traitBuilder.build()).build()); } - }); + + result.add(struct.toBuilder().addTrait(traitBuilder.build()).build()); + } } return result; diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/transform/plugins/CleanTraitDefinitions.java b/smithy-model/src/main/java/software/amazon/smithy/model/transform/plugins/CleanTraitDefinitions.java index 080ecc651ab..25b9df7467b 100644 --- a/smithy-model/src/main/java/software/amazon/smithy/model/transform/plugins/CleanTraitDefinitions.java +++ b/smithy-model/src/main/java/software/amazon/smithy/model/transform/plugins/CleanTraitDefinitions.java @@ -23,6 +23,7 @@ import software.amazon.smithy.model.Model; import software.amazon.smithy.model.shapes.Shape; import software.amazon.smithy.model.shapes.ShapeId; +import software.amazon.smithy.model.shapes.StructureShape; import software.amazon.smithy.model.traits.AuthDefinitionTrait; import software.amazon.smithy.model.traits.ProtocolDefinitionTrait; import software.amazon.smithy.model.transform.ModelTransformer; @@ -43,42 +44,38 @@ public Model onRemove(ModelTransformer transformer, Collection removed, M private Set getAuthDefShapesToReplace(Model model, Set removedShapeIds) { Set shapes = new HashSet<>(); - for (Shape shape : model.getShapesWithTrait(AuthDefinitionTrait.class)) { - shape.asStructureShape().ifPresent(structure -> { - AuthDefinitionTrait authDefTrait = structure.expectTrait(AuthDefinitionTrait.class); - List traits = authDefTrait.getTraits(); - List newTraits = excludeTraitsInSet(traits, removedShapeIds); - // Return early if re-built list of traits is the same as existing list. - if (!traits.equals(newTraits)) { - // If the list of traits on the AuthDefinitionTrait has changed due to a trait shape being - // removed from the model, return a new version of the shape with a new version of the trait. - shapes.add(structure.toBuilder() - .addTrait(authDefTrait.toBuilder().traits(newTraits).build()) - .build()); - } - }); + for (StructureShape structure : model.getStructureShapesWithTrait(AuthDefinitionTrait.class)) { + AuthDefinitionTrait authDefTrait = structure.expectTrait(AuthDefinitionTrait.class); + List traits = authDefTrait.getTraits(); + List newTraits = excludeTraitsInSet(traits, removedShapeIds); + // Return early if re-built list of traits is the same as existing list. + if (!traits.equals(newTraits)) { + // If the list of traits on the AuthDefinitionTrait has changed due to a trait shape being + // removed from the model, return a new version of the shape with a new version of the trait. + shapes.add(structure.toBuilder() + .addTrait(authDefTrait.toBuilder().traits(newTraits).build()) + .build()); + } } return shapes; } private Set getProtocolDefShapesToReplace(Model model, Set removedShapeIds) { Set shapes = new HashSet<>(); - for (Shape shape : model.getShapesWithTrait(ProtocolDefinitionTrait.class)) { - shape.asStructureShape().ifPresent(structure -> { - ProtocolDefinitionTrait protocolDefinitionTrait = structure.expectTrait(ProtocolDefinitionTrait.class); - List traits = protocolDefinitionTrait.getTraits(); - List newTraits = excludeTraitsInSet(traits, removedShapeIds); + for (StructureShape structure : model.getStructureShapesWithTrait(ProtocolDefinitionTrait.class)) { + ProtocolDefinitionTrait protocolDefinitionTrait = structure.expectTrait(ProtocolDefinitionTrait.class); + List traits = protocolDefinitionTrait.getTraits(); + List newTraits = excludeTraitsInSet(traits, removedShapeIds); - // Return early if re-built list of traits is the same as existing list. - if (!traits.equals(newTraits)) { - // If the list of traits on the ProtocolDefinitionTrait has changed due to a trait shape - // being removed from the model, return a new version of the shape with a new version of - // the trait. - shapes.add(structure.toBuilder() - .addTrait(protocolDefinitionTrait.toBuilder().traits(newTraits).build()) - .build()); - } - }); + // Return early if re-built list of traits is the same as existing list. + if (!traits.equals(newTraits)) { + // If the list of traits on the ProtocolDefinitionTrait has changed due to a trait shape + // being removed from the model, return a new version of the shape with a new version of + // the trait. + shapes.add(structure.toBuilder() + .addTrait(protocolDefinitionTrait.toBuilder().traits(newTraits).build()) + .build()); + } } return shapes; } diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/EventPayloadTraitValidator.java b/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/EventPayloadTraitValidator.java index 57038bc4cda..5dc7122e26f 100644 --- a/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/EventPayloadTraitValidator.java +++ b/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/EventPayloadTraitValidator.java @@ -41,12 +41,11 @@ public final class EventPayloadTraitValidator extends AbstractValidator { @Override public List validate(Model model) { List events = new ArrayList<>(); - for (Shape shape : model.getShapesWithTrait(EventPayloadTrait.class)) { - shape.asMemberShape().ifPresent(member -> { - model.getShape(member.getContainer()).flatMap(Shape::asStructureShape).ifPresent(structure -> { - validateEvent(structure, member).ifPresent(events::add); - }); - }); + for (MemberShape member : model.getMemberShapesWithTrait(EventPayloadTrait.class)) { + model.getShape(member.getContainer()) + .flatMap(Shape::asStructureShape) + .flatMap(structure -> validateEvent(structure, member)) + .ifPresent(events::add); } return events; diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/ExamplesTraitValidator.java b/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/ExamplesTraitValidator.java index eaedb9db864..4c3279fac93 100644 --- a/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/ExamplesTraitValidator.java +++ b/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/ExamplesTraitValidator.java @@ -34,10 +34,8 @@ public final class ExamplesTraitValidator extends AbstractValidator { @Override public List validate(Model model) { List events = new ArrayList<>(); - for (Shape shape : model.getShapesWithTrait(ExamplesTrait.class)) { - shape.asOperationShape().ifPresent(operation -> { - events.addAll(validateExamples(model, operation, operation.expectTrait(ExamplesTrait.class))); - }); + for (OperationShape operation : model.getOperationShapesWithTrait(ExamplesTrait.class)) { + events.addAll(validateExamples(model, operation, operation.expectTrait(ExamplesTrait.class))); } return events; diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/HostLabelTraitValidator.java b/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/HostLabelTraitValidator.java index 44908917c8c..935e53322c2 100644 --- a/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/HostLabelTraitValidator.java +++ b/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/HostLabelTraitValidator.java @@ -68,10 +68,8 @@ public List validate(Model model) { // Validate all operation shapes with the `endpoint` trait. List events = new ArrayList<>(); - for (Shape shape : model.getShapesWithTrait(EndpointTrait.class)) { - shape.asOperationShape().ifPresent(operation -> { - events.addAll(validateStructure(model, operation, operation.expectTrait(EndpointTrait.class))); - }); + for (OperationShape operation : model.getOperationShapesWithTrait(EndpointTrait.class)) { + events.addAll(validateStructure(model, operation, operation.expectTrait(EndpointTrait.class))); } return events; diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/HttpHeaderTraitValidator.java b/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/HttpHeaderTraitValidator.java index 532383f199c..a438298b1df 100644 --- a/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/HttpHeaderTraitValidator.java +++ b/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/HttpHeaderTraitValidator.java @@ -27,7 +27,6 @@ import java.util.Set; import software.amazon.smithy.model.Model; import software.amazon.smithy.model.shapes.MemberShape; -import software.amazon.smithy.model.shapes.Shape; import software.amazon.smithy.model.shapes.StructureShape; import software.amazon.smithy.model.traits.HttpHeaderTrait; import software.amazon.smithy.model.validation.AbstractValidator; @@ -79,15 +78,13 @@ public List validate(Model model) { List events = new ArrayList<>(); - for (StructureShape structure : model.toSet(StructureShape.class)) { + for (StructureShape structure : model.getStructureShapes()) { events.addAll(validateStructure(structure)); } - for (Shape shape : model.getShapesWithTrait(HttpHeaderTrait.class)) { - shape.asMemberShape().ifPresent(member -> { - HttpHeaderTrait httpHeaderTrait = member.expectTrait(HttpHeaderTrait.class); - validateHeader(member, httpHeaderTrait).ifPresent(events::add); - }); + for (MemberShape member : model.getMemberShapesWithTrait(HttpHeaderTrait.class)) { + HttpHeaderTrait httpHeaderTrait = member.expectTrait(HttpHeaderTrait.class); + validateHeader(member, httpHeaderTrait).ifPresent(events::add); } return events; diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/HttpLabelTraitValidator.java b/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/HttpLabelTraitValidator.java index 6f74a31106d..83cff7a8b42 100644 --- a/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/HttpLabelTraitValidator.java +++ b/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/HttpLabelTraitValidator.java @@ -56,10 +56,8 @@ public List validate(Model model) { List events = new ArrayList<>(); // Validate all operation shapes with the `http` trait. - for (Shape shape : model.getShapesWithTrait(HttpTrait.class)) { - shape.asOperationShape().ifPresent(operation -> { - events.addAll(validateStructure(model, operation, operation.expectTrait(HttpTrait.class))); - }); + for (OperationShape operation : model.getOperationShapesWithTrait(HttpTrait.class)) { + events.addAll(validateStructure(model, operation, operation.expectTrait(HttpTrait.class))); } return events; diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/HttpMethodSemanticsValidator.java b/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/HttpMethodSemanticsValidator.java index 5e45a1d3df2..34c1b7050a4 100644 --- a/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/HttpMethodSemanticsValidator.java +++ b/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/HttpMethodSemanticsValidator.java @@ -24,7 +24,6 @@ import software.amazon.smithy.model.knowledge.HttpBinding; import software.amazon.smithy.model.knowledge.HttpBindingIndex; import software.amazon.smithy.model.shapes.OperationShape; -import software.amazon.smithy.model.shapes.Shape; import software.amazon.smithy.model.traits.HttpTrait; import software.amazon.smithy.model.traits.IdempotentTrait; import software.amazon.smithy.model.traits.ReadonlyTrait; @@ -69,10 +68,8 @@ public List validate(Model model) { HttpBindingIndex bindingIndex = HttpBindingIndex.of(model); List events = new ArrayList<>(); - for (Shape shape : model.getShapesWithTrait(HttpTrait.class)) { - shape.asOperationShape().ifPresent(operation -> { - events.addAll(validateOperation(bindingIndex, operation, operation.expectTrait(HttpTrait.class))); - }); + for (OperationShape operation : model.getOperationShapesWithTrait(HttpTrait.class)) { + events.addAll(validateOperation(bindingIndex, operation, operation.expectTrait(HttpTrait.class))); } return events; diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/HttpPayloadValidator.java b/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/HttpPayloadValidator.java index c60caaefc7b..bb7b6e6d646 100644 --- a/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/HttpPayloadValidator.java +++ b/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/HttpPayloadValidator.java @@ -27,7 +27,6 @@ import software.amazon.smithy.model.knowledge.HttpBindingIndex; import software.amazon.smithy.model.knowledge.OperationIndex; import software.amazon.smithy.model.shapes.OperationShape; -import software.amazon.smithy.model.shapes.Shape; import software.amazon.smithy.model.shapes.ShapeId; import software.amazon.smithy.model.shapes.StructureShape; import software.amazon.smithy.model.traits.ErrorTrait; @@ -54,16 +53,12 @@ public List validate(Model model) { HttpBindingIndex bindings = HttpBindingIndex.of(model); List events = new ArrayList<>(); - for (Shape shape : model.getShapesWithTrait(HttpTrait.class)) { - shape.asOperationShape().ifPresent(operation -> { - events.addAll(validateOperation(bindings, opIndex, operation)); - }); + for (OperationShape operation : model.getOperationShapesWithTrait(HttpTrait.class)) { + events.addAll(validateOperation(bindings, opIndex, operation)); } - for (Shape shape : model.getShapesWithTrait(ErrorTrait.class)) { - shape.asStructureShape().ifPresent(structure -> { - events.addAll(validateError(structure, bindings)); - }); + for (StructureShape structure : model.getStructureShapesWithTrait(ErrorTrait.class)) { + events.addAll(validateError(structure, bindings)); } return events; diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/HttpPrefixHeadersTraitValidator.java b/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/HttpPrefixHeadersTraitValidator.java index b4f8923c3c9..f7992f1e98a 100644 --- a/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/HttpPrefixHeadersTraitValidator.java +++ b/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/HttpPrefixHeadersTraitValidator.java @@ -36,11 +36,9 @@ public final class HttpPrefixHeadersTraitValidator extends AbstractValidator { @Override public List validate(Model model) { List events = new ArrayList<>(); - for (Shape shape : model.getShapesWithTrait(HttpPrefixHeadersTrait.class)) { - shape.asMemberShape().ifPresent(member -> { - model.getShape(member.getContainer()).flatMap(Shape::asStructureShape).ifPresent(structure -> { - events.addAll(validateMember(structure, member, member.expectTrait(HttpPrefixHeadersTrait.class))); - }); + for (MemberShape member : model.getMemberShapesWithTrait(HttpPrefixHeadersTrait.class)) { + model.getShape(member.getContainer()).flatMap(Shape::asStructureShape).ifPresent(structure -> { + events.addAll(validateMember(structure, member, member.expectTrait(HttpPrefixHeadersTrait.class))); }); } diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/HttpQueryParamsTraitValidator.java b/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/HttpQueryParamsTraitValidator.java index 204c198989e..b6dda3f1a23 100644 --- a/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/HttpQueryParamsTraitValidator.java +++ b/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/HttpQueryParamsTraitValidator.java @@ -46,17 +46,16 @@ public List validate(Model model) { private List validateQueryTraitUsage(Model model) { List events = new ArrayList<>(); - for (Shape shape : model.getShapesWithTrait(HttpQueryParamsTrait.class)) { - shape.asMemberShape() - .flatMap(member -> model.getShape(member.getContainer()) - .flatMap(Shape::asStructureShape)) - .ifPresent(structure -> { - // Gather the names of member shapes, as strings, that apply HttpQuery traits - List queryShapes = getMembersWithTrait(structure, HttpQueryTrait.class); - if (queryShapes.size() > 0) { - events.add(createNote(structure, shape.toShapeId().getMember().get(), queryShapes)); - } - }); + for (MemberShape member : model.getMemberShapesWithTrait(HttpQueryParamsTrait.class)) { + model.getShape(member.getContainer()) + .flatMap(Shape::asStructureShape) + .ifPresent(structure -> { + // Gather the names of member shapes, as strings, that apply HttpQuery traits + List queryShapes = getMembersWithTrait(structure, HttpQueryTrait.class); + if (queryShapes.size() > 0) { + events.add(createNote(structure, member.getMemberName(), queryShapes)); + } + }); } return events; diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/HttpQueryTraitValidator.java b/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/HttpQueryTraitValidator.java index b73f1ca73e0..8b25211edcc 100644 --- a/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/HttpQueryTraitValidator.java +++ b/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/HttpQueryTraitValidator.java @@ -23,6 +23,7 @@ import java.util.Map; import java.util.Set; import software.amazon.smithy.model.Model; +import software.amazon.smithy.model.shapes.MemberShape; import software.amazon.smithy.model.shapes.Shape; import software.amazon.smithy.model.shapes.StructureShape; import software.amazon.smithy.model.traits.HttpQueryTrait; @@ -48,17 +49,15 @@ private Map>> getQueryBindings(Model mod Map>> queryBindings = new HashMap<>(); // Find all members in the model that have the HttpQuery trait. - for (Shape shape : model.getShapesWithTrait(HttpQueryTrait.class)) { - shape.asMemberShape().ifPresent(member -> { - // Get the structure of the member. Validation events are going to be - // applied to the structure and not to members. - model.getShape(member.getContainer()).flatMap(Shape::asStructureShape).ifPresent(structure -> { - HttpQueryTrait trait = shape.expectTrait(HttpQueryTrait.class); - queryBindings - .computeIfAbsent(structure, s -> new HashMap<>()) - .computeIfAbsent(trait.getValue(), v -> new HashSet<>()) - .add(member.getMemberName()); - }); + for (MemberShape member : model.getMemberShapesWithTrait(HttpQueryTrait.class)) { + // Get the structure of the member. Validation events are going to be + // applied to the structure and not to members. + model.getShape(member.getContainer()).flatMap(Shape::asStructureShape).ifPresent(structure -> { + HttpQueryTrait trait = member.expectTrait(HttpQueryTrait.class); + queryBindings + .computeIfAbsent(structure, s -> new HashMap<>()) + .computeIfAbsent(trait.getValue(), v -> new HashSet<>()) + .add(member.getMemberName()); }); } diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/HttpResponseCodeSemanticsValidator.java b/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/HttpResponseCodeSemanticsValidator.java index cc8fb5741be..02fc9ddcfcb 100644 --- a/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/HttpResponseCodeSemanticsValidator.java +++ b/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/HttpResponseCodeSemanticsValidator.java @@ -38,16 +38,12 @@ public final class HttpResponseCodeSemanticsValidator extends AbstractValidator public List validate(Model model) { List events = new ArrayList<>(); - for (Shape shape : model.getShapesWithTrait(HttpTrait.class)) { - shape.asOperationShape().ifPresent(operation -> { - validateOperationsWithHttpTrait(operation).ifPresent(events::add); - }); + for (OperationShape operation : model.getOperationShapesWithTrait(HttpTrait.class)) { + validateOperationsWithHttpTrait(operation).ifPresent(events::add); } - for (Shape shape : model.getShapesWithTrait(ErrorTrait.class)) { - shape.asStructureShape().ifPresent(structure -> { - validateError(structure, structure.expectTrait(ErrorTrait.class)).ifPresent(events::add); - }); + for (StructureShape structure : model.getStructureShapesWithTrait(ErrorTrait.class)) { + validateError(structure, structure.expectTrait(ErrorTrait.class)).ifPresent(events::add); } return events; diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/PaginatedTraitValidator.java b/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/PaginatedTraitValidator.java index 26f623ea3e9..1457160c891 100644 --- a/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/PaginatedTraitValidator.java +++ b/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/PaginatedTraitValidator.java @@ -68,11 +68,9 @@ public List validate(Model model) { TopDownIndex topDown = TopDownIndex.of(model); List events = new ArrayList<>(); - for (Shape shape : model.getShapesWithTrait(PaginatedTrait.class)) { - shape.asOperationShape().ifPresent(operation -> { - PaginatedTrait paginatedTrait = shape.expectTrait(PaginatedTrait.class); - events.addAll(validateOperation(model, topDown, opIndex, operation, paginatedTrait)); - }); + for (OperationShape operation : model.getOperationShapesWithTrait(PaginatedTrait.class)) { + PaginatedTrait paginatedTrait = operation.expectTrait(PaginatedTrait.class); + events.addAll(validateOperation(model, topDown, opIndex, operation, paginatedTrait)); } return events; diff --git a/smithy-mqtt-traits/src/main/java/software/amazon/smithy/mqtt/traits/validators/MqttSubscribeOutputValidator.java b/smithy-mqtt-traits/src/main/java/software/amazon/smithy/mqtt/traits/validators/MqttSubscribeOutputValidator.java index 051ef058d6c..d41a1e465e2 100644 --- a/smithy-mqtt-traits/src/main/java/software/amazon/smithy/mqtt/traits/validators/MqttSubscribeOutputValidator.java +++ b/smithy-mqtt-traits/src/main/java/software/amazon/smithy/mqtt/traits/validators/MqttSubscribeOutputValidator.java @@ -49,10 +49,8 @@ public final class MqttSubscribeOutputValidator extends AbstractValidator { public List validate(Model model) { EventStreamIndex eventStreamIndex = EventStreamIndex.of(model); List events = new ArrayList<>(); - for (Shape shape : model.getShapesWithTrait(SubscribeTrait.class)) { - shape.asOperationShape().ifPresent(operation -> { - events.addAll(validateOperation(model, operation, eventStreamIndex)); - }); + for (OperationShape operation : model.getOperationShapesWithTrait(SubscribeTrait.class)) { + events.addAll(validateOperation(model, operation, eventStreamIndex)); } return events; }