From 8780cb4774dd5dec8023ecc9f303be6b4437908d Mon Sep 17 00:00:00 2001 From: Michael Dowling Date: Thu, 6 Aug 2020 22:40:03 -0700 Subject: [PATCH] Simplify prelude loading The previous loading implementation required the prelude to be defined before loading could occur. This had the consequence that much of the prelude had to be defined in Java code rather than a prelude model. Because loading was refactored recently, we can now define the entire prelude in a Smithy model and simplify Prelude.java. --- .../amazon/smithy/model/loader/Prelude.java | 217 +----------------- .../{prelude-traits.smithy => prelude.smithy} | 51 ++++ 2 files changed, 60 insertions(+), 208 deletions(-) rename smithy-model/src/main/resources/software/amazon/smithy/model/loader/{prelude-traits.smithy => prelude.smithy} (97%) diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/loader/Prelude.java b/smithy-model/src/main/java/software/amazon/smithy/model/loader/Prelude.java index e7cb43c8435..d11ef52c4cb 100644 --- a/smithy-model/src/main/java/software/amazon/smithy/model/loader/Prelude.java +++ b/smithy-model/src/main/java/software/amazon/smithy/model/loader/Prelude.java @@ -15,88 +15,9 @@ package software.amazon.smithy.model.loader; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; import software.amazon.smithy.model.Model; -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.LongShape; -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.TimestampShape; import software.amazon.smithy.model.shapes.ToShapeId; -import software.amazon.smithy.model.traits.AuthDefinitionTrait; -import software.amazon.smithy.model.traits.AuthTrait; -import software.amazon.smithy.model.traits.BoxTrait; -import software.amazon.smithy.model.traits.CorsTrait; -import software.amazon.smithy.model.traits.DeprecatedTrait; -import software.amazon.smithy.model.traits.DocumentationTrait; -import software.amazon.smithy.model.traits.EndpointTrait; -import software.amazon.smithy.model.traits.EnumTrait; -import software.amazon.smithy.model.traits.ErrorTrait; -import software.amazon.smithy.model.traits.EventHeaderTrait; -import software.amazon.smithy.model.traits.EventPayloadTrait; -import software.amazon.smithy.model.traits.ExamplesTrait; -import software.amazon.smithy.model.traits.ExternalDocumentationTrait; -import software.amazon.smithy.model.traits.HostLabelTrait; -import software.amazon.smithy.model.traits.HttpApiKeyAuthTrait; -import software.amazon.smithy.model.traits.HttpBasicAuthTrait; -import software.amazon.smithy.model.traits.HttpBearerAuthTrait; -import software.amazon.smithy.model.traits.HttpChecksumRequiredTrait; -import software.amazon.smithy.model.traits.HttpDigestAuthTrait; -import software.amazon.smithy.model.traits.HttpErrorTrait; -import software.amazon.smithy.model.traits.HttpHeaderTrait; -import software.amazon.smithy.model.traits.HttpLabelTrait; -import software.amazon.smithy.model.traits.HttpPayloadTrait; -import software.amazon.smithy.model.traits.HttpPrefixHeadersTrait; -import software.amazon.smithy.model.traits.HttpQueryTrait; -import software.amazon.smithy.model.traits.HttpTrait; -import software.amazon.smithy.model.traits.IdRefTrait; -import software.amazon.smithy.model.traits.IdempotencyTokenTrait; -import software.amazon.smithy.model.traits.IdempotentTrait; -import software.amazon.smithy.model.traits.JsonNameTrait; -import software.amazon.smithy.model.traits.LengthTrait; -import software.amazon.smithy.model.traits.MediaTypeTrait; -import software.amazon.smithy.model.traits.NoReplaceTrait; -import software.amazon.smithy.model.traits.OptionalAuthTrait; -import software.amazon.smithy.model.traits.PaginatedTrait; -import software.amazon.smithy.model.traits.PatternTrait; import software.amazon.smithy.model.traits.PrivateTrait; -import software.amazon.smithy.model.traits.ProtocolDefinitionTrait; -import software.amazon.smithy.model.traits.RangeTrait; -import software.amazon.smithy.model.traits.ReadonlyTrait; -import software.amazon.smithy.model.traits.ReferencesTrait; -import software.amazon.smithy.model.traits.RequiredTrait; -import software.amazon.smithy.model.traits.RequiresLengthTrait; -import software.amazon.smithy.model.traits.ResourceIdentifierTrait; -import software.amazon.smithy.model.traits.RetryableTrait; -import software.amazon.smithy.model.traits.SensitiveTrait; -import software.amazon.smithy.model.traits.SinceTrait; -import software.amazon.smithy.model.traits.StreamingTrait; -import software.amazon.smithy.model.traits.SuppressTrait; -import software.amazon.smithy.model.traits.TagsTrait; -import software.amazon.smithy.model.traits.TimestampFormatTrait; -import software.amazon.smithy.model.traits.TitleTrait; -import software.amazon.smithy.model.traits.TraitDefinition; -import software.amazon.smithy.model.traits.TraitFactory; -import software.amazon.smithy.model.traits.UniqueItemsTrait; -import software.amazon.smithy.model.traits.UnstableTrait; -import software.amazon.smithy.model.traits.XmlAttributeTrait; -import software.amazon.smithy.model.traits.XmlFlattenedTrait; -import software.amazon.smithy.model.traits.XmlNameTrait; -import software.amazon.smithy.model.traits.XmlNamespaceTrait; -import software.amazon.smithy.utils.ListUtils; -import software.amazon.smithy.utils.SetUtils; /** * Represents the prelude model available to every Smithy model. @@ -110,110 +31,10 @@ * result in infinite recursion while loading the prelude model. */ public final class Prelude { + /** The Smithy prelude namespace. */ public static final String NAMESPACE = "smithy.api"; - private static final List PUBLIC_PRELUDE_SHAPES = ListUtils.of( - StringShape.builder().id(NAMESPACE + "#String").build(), - BlobShape.builder().id(NAMESPACE + "#Blob").build(), - BigIntegerShape.builder().id(NAMESPACE + "#BigInteger").build(), - BigDecimalShape.builder().id(NAMESPACE + "#BigDecimal").build(), - TimestampShape.builder().id(NAMESPACE + "#Timestamp").build(), - DocumentShape.builder().id(NAMESPACE + "#Document").build(), - BooleanShape.builder().id(NAMESPACE + "#Boolean").addTrait(new BoxTrait()).build(), - BooleanShape.builder().id(NAMESPACE + "#PrimitiveBoolean").build(), - ByteShape.builder().id(NAMESPACE + "#Byte").addTrait(new BoxTrait()).build(), - ByteShape.builder().id(NAMESPACE + "#PrimitiveByte").build(), - ShortShape.builder().id(NAMESPACE + "#Short").addTrait(new BoxTrait()).build(), - ShortShape.builder().id(NAMESPACE + "#PrimitiveShort").build(), - IntegerShape.builder().id(NAMESPACE + "#Integer").addTrait(new BoxTrait()).build(), - IntegerShape.builder().id(NAMESPACE + "#PrimitiveInteger").build(), - LongShape.builder().id(NAMESPACE + "#Long").addTrait(new BoxTrait()).build(), - LongShape.builder().id(NAMESPACE + "#PrimitiveLong").build(), - FloatShape.builder().id(NAMESPACE + "#Float").addTrait(new BoxTrait()).build(), - FloatShape.builder().id(NAMESPACE + "#PrimitiveFloat").build(), - DoubleShape.builder().id(NAMESPACE + "#Double").addTrait(new BoxTrait()).build(), - DoubleShape.builder().id(NAMESPACE + "#PrimitiveDouble").build()); - - /** - * This list of public prelude traits is manually maintained and must match the - * public prelude traits defined in prelude-traits.smithy. The Prelude itself - * cannot refer to the loaded model because the Prelude abstraction is queried - * while loading the prelude model. - * - *

A check is made each time the prelude is first loaded to ensure that the - * actual traits defined in the prelude match the traits in this list. As long - * as changes are tested before releasing, they should never get out of sync. - */ - private static final Set PRELUDE_TRAITS = SetUtils.of( - AuthTrait.ID, - BoxTrait.ID, - CorsTrait.ID, - DeprecatedTrait.ID, - DocumentationTrait.ID, - EndpointTrait.ID, - EnumTrait.ID, - ErrorTrait.ID, - EventHeaderTrait.ID, - EventPayloadTrait.ID, - ExamplesTrait.ID, - ExternalDocumentationTrait.ID, - HostLabelTrait.ID, - HttpChecksumRequiredTrait.ID, - HttpErrorTrait.ID, - HttpHeaderTrait.ID, - HttpLabelTrait.ID, - HttpPayloadTrait.ID, - HttpPrefixHeadersTrait.ID, - HttpQueryTrait.ID, - HttpTrait.ID, - IdRefTrait.ID, - IdempotencyTokenTrait.ID, - IdempotentTrait.ID, - JsonNameTrait.ID, - LengthTrait.ID, - NoReplaceTrait.ID, - MediaTypeTrait.ID, - PaginatedTrait.ID, - PatternTrait.ID, - PrivateTrait.ID, - ProtocolDefinitionTrait.ID, - AuthDefinitionTrait.ID, - HttpApiKeyAuthTrait.ID, - HttpBasicAuthTrait.ID, - HttpDigestAuthTrait.ID, - HttpBearerAuthTrait.ID, - OptionalAuthTrait.ID, - RangeTrait.ID, - ReadonlyTrait.ID, - ReferencesTrait.ID, - RequiresLengthTrait.ID, - RequiredTrait.ID, - ResourceIdentifierTrait.ID, - RetryableTrait.ID, - SensitiveTrait.ID, - SinceTrait.ID, - StreamingTrait.ID, - SuppressTrait.ID, - TagsTrait.ID, - TimestampFormatTrait.ID, - TitleTrait.ID, - TraitDefinition.ID, - UniqueItemsTrait.ID, - UnstableTrait.ID, - XmlAttributeTrait.ID, - XmlFlattenedTrait.ID, - XmlNameTrait.ID, - XmlNamespaceTrait.ID); - - private static final Set PUBLIC_PRELUDE_SHAPE_IDS; - - static { - PUBLIC_PRELUDE_SHAPE_IDS = PUBLIC_PRELUDE_SHAPES.stream() - .map(Shape::getId) - .collect(SetUtils.toUnmodifiableSet()); - } - private Prelude() {} /** @@ -237,8 +58,9 @@ public static boolean isPreludeShape(ToShapeId id) { * @return Returns true if the shape is a public prelude shape. */ public static boolean isPublicPreludeShape(ToShapeId id) { - ShapeId toId = id.toShapeId(); - return PUBLIC_PRELUDE_SHAPE_IDS.contains(toId) || PRELUDE_TRAITS.contains(toId); + return getPreludeModel().getShape(id.toShapeId()) + .filter(shape -> !shape.hasTrait(PrivateTrait.class)) + .isPresent(); } // Used by the ModelAssembler to load the prelude into another visitor. @@ -251,33 +73,12 @@ private static final class PreludeHolder { private static final Model PRELUDE = loadPrelude(); private static Model loadPrelude() { - TraitFactory traitFactory = ModelAssembler.LazyTraitFactoryHolder.INSTANCE; - ModelAssembler assembler = Model.assembler() + return Model.assembler() .disablePrelude() - .traitFactory(traitFactory) - .addImport(Prelude.class.getResource("prelude-traits.smithy")); - - for (Shape shape : PUBLIC_PRELUDE_SHAPES) { - assembler.addShape(shape); - } - - Model preludeModel = assembler.assemble().unwrap(); - - // Sanity check to ensure that the prelude model and the tracked prelude traits are consistent. - // TODO: Can this be moved to a build step in Gradle? - for (Shape trait : preludeModel.getShapesWithTrait(TraitDefinition.class)) { - if (!PRELUDE_TRAITS.contains(trait.getId())) { - throw new IllegalStateException( - "PRELUDE_TRAITS property of prelude is inconsistent with the traits defined in the " - + "prelude-traits.smithy file. This property MUST be kept consistent with the file. " - + PRELUDE_TRAITS + " in PRELUDE_TRAITS vs " - + preludeModel.getShapesWithTrait(TraitDefinition.class).stream() - .map(Shape::getId) - .collect(Collectors.toList())); - } - } - - return preludeModel; + .traitFactory(ModelAssembler.LazyTraitFactoryHolder.INSTANCE) + .addImport(Prelude.class.getResource("prelude.smithy")) + .assemble() + .unwrap(); } } } diff --git a/smithy-model/src/main/resources/software/amazon/smithy/model/loader/prelude-traits.smithy b/smithy-model/src/main/resources/software/amazon/smithy/model/loader/prelude.smithy similarity index 97% rename from smithy-model/src/main/resources/software/amazon/smithy/model/loader/prelude-traits.smithy rename to smithy-model/src/main/resources/software/amazon/smithy/model/loader/prelude.smithy index 89aa0ceee57..807b55059c5 100644 --- a/smithy-model/src/main/resources/software/amazon/smithy/model/loader/prelude-traits.smithy +++ b/smithy-model/src/main/resources/software/amazon/smithy/model/loader/prelude.smithy @@ -2,6 +2,57 @@ $version: "1.0" namespace smithy.api +// ------ Prelude shapes + +string String + +blob Blob + +bigInteger BigInteger + +bigDecimal BigDecimal + +timestamp Timestamp + +document Document + +@box +boolean Boolean + +boolean PrimitiveBoolean + +@box +byte Byte + +byte PrimitiveByte + +@box +short Short + +short PrimitiveShort + +@box +integer Integer + +integer PrimitiveInteger + +@box +long Long + +long PrimitiveLong + +@box +float Float + +float PrimitiveFloat + +@box +double Double + +double PrimitiveDouble + +// ------ Prelude traits + /// Makes a shape a trait. @trait(selector: ":is(simpleType, list, map, set, structure, union)") @tags(["diff.error.add", "diff.error.remove"])