diff --git a/codegen-serde/src/main/kotlin/software/amazon/smithy/rust/codegen/serde/SerializeImplGenerator.kt b/codegen-serde/src/main/kotlin/software/amazon/smithy/rust/codegen/serde/SerializeImplGenerator.kt index b7c6c862d0..3db8d0086c 100644 --- a/codegen-serde/src/main/kotlin/software/amazon/smithy/rust/codegen/serde/SerializeImplGenerator.kt +++ b/codegen-serde/src/main/kotlin/software/amazon/smithy/rust/codegen/serde/SerializeImplGenerator.kt @@ -6,6 +6,7 @@ package software.amazon.smithy.rust.codegen.serde import software.amazon.smithy.codegen.core.Symbol +import software.amazon.smithy.model.knowledge.TopDownIndex import software.amazon.smithy.model.shapes.BlobShape import software.amazon.smithy.model.shapes.BooleanShape import software.amazon.smithy.model.shapes.CollectionShape @@ -61,6 +62,7 @@ import software.amazon.smithy.rust.codegen.server.smithy.hasConstraintTrait class SerializeImplGenerator(private val codegenContext: CodegenContext) { private val model = codegenContext.model + private val topIndex = TopDownIndex.of(model) fun generateRootSerializerForShape(shape: Shape): Writable = serializerFn(shape, null) @@ -78,7 +80,9 @@ class SerializeImplGenerator(private val codegenContext: CodegenContext) { applyTo: Writable?, ): Writable { if (shape is ServiceShape) { - return shape.operations.map { serializerFn(model.expectShape(it), null) }.join("\n") + return topIndex.getContainedOperations(shape).map { + serializerFn(it, null) + }.join("\n") } else if (shape is OperationShape) { if (shape.isEventStream(model)) { // Don't generate serializers for event streams diff --git a/codegen-serde/src/test/kotlin/software/amazon/smithy/rust/codegen/serde/SerdeDecoratorTest.kt b/codegen-serde/src/test/kotlin/software/amazon/smithy/rust/codegen/serde/SerdeDecoratorTest.kt index 1e419a3c76..4a1dc3a520 100644 --- a/codegen-serde/src/test/kotlin/software/amazon/smithy/rust/codegen/serde/SerdeDecoratorTest.kt +++ b/codegen-serde/src/test/kotlin/software/amazon/smithy/rust/codegen/serde/SerdeDecoratorTest.kt @@ -179,6 +179,58 @@ class SerdeDecoratorTest { structure NotSerde {} """.asSmithyModel(smithyVersion = "2") + @Test + fun `decorator should traverse resources`() { + val model = + """ + namespace com.example + use smithy.rust#serde + use aws.protocols#awsJson1_0 + + @awsJson1_0 + @serde + service MyResourceService { + resources: [MyResource] + } + + resource MyResource { + read: ReadMyResource + } + + @readonly + operation ReadMyResource { + input := { } + } + """.asSmithyModel(smithyVersion = "2") + + val params = + IntegrationTestParams(cargoCommand = "cargo test --all-features", service = "com.example#MyResourceService") + serverIntegrationTest(model, params = params) { ctx, crate -> + val codegenScope = + arrayOf( + "crate" to RustType.Opaque(ctx.moduleUseName()), + "serde_json" to CargoDependency("serde_json", CratesIo("1")).toDevDependency().toType(), + // we need the derive feature + "serde" to CargoDependency.Serde.toDevDependency().toType(), + ) + + crate.integrationTest("test_serde") { + unitTest("input_serialized") { + rustTemplate( + """ + use #{crate}::input::ReadMyResourceInput; + use #{crate}::serde::*; + let input = ReadMyResourceInput { }; + let settings = SerializationSettings::default(); + let _serialized = #{serde_json}::to_string(&input.serialize_ref(&settings)).expect("failed to serialize"); + """, + *codegenScope, + ) + } + } + } + } + @Test fun generateSerializersThatWorkServer() { serverIntegrationTest(simpleModel, params = params) { ctx, crate ->