From bc2be87eadd9be655bd38a083e961c5a23403ee9 Mon Sep 17 00:00:00 2001 From: Hunter Mellema Date: Fri, 15 Nov 2024 11:52:08 -0700 Subject: [PATCH] Add transform to mark required idempotency tokens client optional --- docs/source-2.0/guides/smithy-build-json.rst | 25 +++++++++++++++ .../MarkIdempotencyTokensClientOptional.java | 27 ++++++++++++++++ ....amazon.smithy.build.ProjectionTransformer | 2 ++ .../core/directed/CodegenDirector.java | 12 +++++++ .../MakeIdempotencyTokenClientOptional.java | 25 +++++++++++++++ .../model/transform/ModelTransformer.java | 14 +++++++++ ...akeIdempotencyTokenClientOptionalTest.java | 31 +++++++++++++++++++ .../model/transform/idempotency-token.smithy | 11 +++++++ 8 files changed, 147 insertions(+) create mode 100644 smithy-build/src/main/java/software/amazon/smithy/build/transforms/MarkIdempotencyTokensClientOptional.java create mode 100644 smithy-model/src/main/java/software/amazon/smithy/model/transform/MakeIdempotencyTokenClientOptional.java create mode 100644 smithy-model/src/test/java/software/amazon/smithy/model/transform/MakeIdempotencyTokenClientOptionalTest.java create mode 100644 smithy-model/src/test/resources/software/amazon/smithy/model/transform/idempotency-token.smithy diff --git a/docs/source-2.0/guides/smithy-build-json.rst b/docs/source-2.0/guides/smithy-build-json.rst index cba39798b14..e4adfa2e719 100644 --- a/docs/source-2.0/guides/smithy-build-json.rst +++ b/docs/source-2.0/guides/smithy-build-json.rst @@ -573,6 +573,31 @@ applied. use an :ref:`enum shape ` instead to avoid needing to use this transform. +.. _markIdempotencyTokensClientOptional: + +markIdempotencyTokensClientOptional +----------------------------------- + +Marks required Idempotency token members as ``@clientOptional``. + +Idempotency tokens that are required should fail validation, but shouldn't be required to create a type, +allowing for a default value to get injected when missing. + +.. code-block:: json + + { + "version": "1.0", + "projections": { + "exampleProjection": { + "transforms": [ + { + "name": "markIdempotencyTokensClientOptional" + } + ] + } + } + } + .. _changeTypes: changeTypes diff --git a/smithy-build/src/main/java/software/amazon/smithy/build/transforms/MarkIdempotencyTokensClientOptional.java b/smithy-build/src/main/java/software/amazon/smithy/build/transforms/MarkIdempotencyTokensClientOptional.java new file mode 100644 index 00000000000..59796ffa1c6 --- /dev/null +++ b/smithy-build/src/main/java/software/amazon/smithy/build/transforms/MarkIdempotencyTokensClientOptional.java @@ -0,0 +1,27 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.build.transforms; + +import software.amazon.smithy.build.ProjectionTransformer; +import software.amazon.smithy.build.TransformContext; +import software.amazon.smithy.model.Model; + +/** + * {@code markIdempotencyTokensClientOptional} marks required idempotency token fields clientOptional. + */ +public final class MarkIdempotencyTokensClientOptional implements ProjectionTransformer { + + @Override + public String getName() { + return "markIdempotencyTokensClientOptional"; + } + + @Override + public Model transform(TransformContext context) { + Model model = context.getModel(); + return context.getTransformer().markIdempotencyTokensClientOptional(model); + } +} diff --git a/smithy-build/src/main/resources/META-INF/services/software.amazon.smithy.build.ProjectionTransformer b/smithy-build/src/main/resources/META-INF/services/software.amazon.smithy.build.ProjectionTransformer index 9a251b195da..4d40c2998d1 100644 --- a/smithy-build/src/main/resources/META-INF/services/software.amazon.smithy.build.ProjectionTransformer +++ b/smithy-build/src/main/resources/META-INF/services/software.amazon.smithy.build.ProjectionTransformer @@ -18,6 +18,8 @@ software.amazon.smithy.build.transforms.IncludeShapesByTag software.amazon.smithy.build.transforms.IncludeTags software.amazon.smithy.build.transforms.IncludeTraits software.amazon.smithy.build.transforms.IncludeTraitsByTag +software.amazon.smithy.build.transforms.MarkIdempotencyTokensClientOptional +software.amazon.smithy.build.transforms.RemoveDeprecatedShapes software.amazon.smithy.build.transforms.RemoveTraitDefinitions software.amazon.smithy.build.transforms.RemoveUnusedShapes software.amazon.smithy.build.transforms.RenameShapes diff --git a/smithy-codegen-core/src/main/java/software/amazon/smithy/codegen/core/directed/CodegenDirector.java b/smithy-codegen-core/src/main/java/software/amazon/smithy/codegen/core/directed/CodegenDirector.java index 13aedaeb8f4..9e116cc9307 100644 --- a/smithy-codegen-core/src/main/java/software/amazon/smithy/codegen/core/directed/CodegenDirector.java +++ b/smithy-codegen-core/src/main/java/software/amazon/smithy/codegen/core/directed/CodegenDirector.java @@ -315,6 +315,18 @@ public void removeShapesDeprecatedBeforeVersion(String relativeVersion) { }); } + /** + * Marks idempotency token fields {@code clientOptional}. + * + * @see ModelTransformer#markIdempotencyTokensClientOptional(Model) + */ + public void markIdempotencyTokensClientOptional() { + transforms.add((model, transformer) -> { + LOGGER.finest("Marking Idempotency Token fields `@clientOptional`"); + return transformer.filterDeprecatedRelativeVersion(model); + }); + } + /** * Changes each compatible string shape with the enum trait to an enum shape. * diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/transform/MakeIdempotencyTokenClientOptional.java b/smithy-model/src/main/java/software/amazon/smithy/model/transform/MakeIdempotencyTokenClientOptional.java new file mode 100644 index 00000000000..0af534dc295 --- /dev/null +++ b/smithy-model/src/main/java/software/amazon/smithy/model/transform/MakeIdempotencyTokenClientOptional.java @@ -0,0 +1,25 @@ +package software.amazon.smithy.model.transform; + + +import software.amazon.smithy.model.Model; +import software.amazon.smithy.model.shapes.Shape; +import software.amazon.smithy.model.traits.ClientOptionalTrait; +import software.amazon.smithy.model.traits.IdempotencyTokenTrait; +import software.amazon.smithy.model.traits.RequiredTrait; + +/** + * Mark Idempotency token members as clientOptional so they can be injected if missing. + */ +final class MakeIdempotencyTokenClientOptional { + public static Model transform(Model model) { + return ModelTransformer.create().mapShapes(model, shape -> { + if (shape.isMemberShape() + && shape.hasTrait(RequiredTrait.class) + && shape.hasTrait(IdempotencyTokenTrait.class) + && !shape.hasTrait(ClientOptionalTrait.class)) { + return Shape.shapeToBuilder(shape).addTrait(new ClientOptionalTrait()).build(); + } + return shape; + }); + } +} diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/transform/ModelTransformer.java b/smithy-model/src/main/java/software/amazon/smithy/model/transform/ModelTransformer.java index ed2123608d3..627524b7918 100644 --- a/smithy-model/src/main/java/software/amazon/smithy/model/transform/ModelTransformer.java +++ b/smithy-model/src/main/java/software/amazon/smithy/model/transform/ModelTransformer.java @@ -43,6 +43,7 @@ import software.amazon.smithy.model.traits.synthetic.OriginalShapeIdTrait; import software.amazon.smithy.utils.FunctionalUtils; import software.amazon.smithy.utils.ListUtils; +import sun.awt.ModalityListener; /** * Class used to transform {@link Model}s. @@ -720,4 +721,17 @@ public Model filterDeprecatedRelativeDate(Model model, String relativeDate) { public Model filterDeprecatedRelativeVersion(Model model, String relativeVersion) { return new FilterDeprecatedRelativeVersion(relativeVersion).transform(this, model); } + + /** + * Marks any Idempotency token fields {@code @clientOptional} so that missing tokens can be injected. + * + *

Idempotency tokens that are required should fail validation, but shouldn't be required to create a type, + * allowing for a default value to get injected when missing. + * + * @param model Model to transform. + * @return Returns the transformed model. + */ + public Model markIdempotencyTokensClientOptional(Model model) { + return MakeIdempotencyTokenClientOptional.transform(model); + } } diff --git a/smithy-model/src/test/java/software/amazon/smithy/model/transform/MakeIdempotencyTokenClientOptionalTest.java b/smithy-model/src/test/java/software/amazon/smithy/model/transform/MakeIdempotencyTokenClientOptionalTest.java new file mode 100644 index 00000000000..c67c3daa520 --- /dev/null +++ b/smithy-model/src/test/java/software/amazon/smithy/model/transform/MakeIdempotencyTokenClientOptionalTest.java @@ -0,0 +1,31 @@ +package software.amazon.smithy.model.transform; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; +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.traits.ClientOptionalTrait; +import software.amazon.smithy.model.traits.IdempotencyTokenTrait; +import software.amazon.smithy.model.traits.RequiredTrait; + +public class MakeIdempotencyTokenClientOptionalTest { + private static final ShapeId operationInput = ShapeId.from("smithy.example#IdempotencyTokenRequiredInput"); + + @Test + void compareTransform() { + Model before = Model.assembler() + .addImport(FlattenPaginationInfoTest.class.getResource("idempotency-token.smithy")) + .assemble() + .unwrap(); + Model result = ModelTransformer.create().markIdempotencyTokensClientOptional(before); + + Shape input = result.expectShape(operationInput); + Shape member = result.expectShape(input.getMember("token").get().getId()); + + assertTrue(member.hasTrait(ClientOptionalTrait.class)); + assertTrue(member.hasTrait(RequiredTrait.class)); + assertTrue(member.hasTrait(IdempotencyTokenTrait.class)); + } +} diff --git a/smithy-model/src/test/resources/software/amazon/smithy/model/transform/idempotency-token.smithy b/smithy-model/src/test/resources/software/amazon/smithy/model/transform/idempotency-token.smithy new file mode 100644 index 00000000000..b6975966cdb --- /dev/null +++ b/smithy-model/src/test/resources/software/amazon/smithy/model/transform/idempotency-token.smithy @@ -0,0 +1,11 @@ +$version: "2.0" + +namespace smithy.example + +operation IdempotencyTokenRequired { + input := { + @idempotencyToken + @required + token: String + } +}