Repository: smithy-lang/smithy
Pull request #2314 (2024-06-07 14:27:13)

Add protocol tests relating to `Content-Type` and `@httpPayload`
Add protocol tests relating to `Content-Type` and `@httpPayload`

Initial motivation for this stems off #2310, but for when the input is
`@httpPayload`-bound. It's important that we test `Content-Type`
specifically with `@httpPayload` operations, because the header can be
checked without having to inspect the body, and because the spec has
special provisions
(https://smithy.io/2.0/aws/protocols/aws-restjson1-protocol.html#content-type).

There were no protocol tests exercising `Content-Type` when the input is
`@httpPayload`-bound:

- In the case of blobs, servers must accept any (test already exists)
  and no `Content-Type` (test added in this commit).
- In other cases, there were protocol tests for `union` and `structure`
  shapes. I've added an operation with an `@httpPayload`-bound string
  shape. Note that `document` shapes remain untested.

#### Testing

* Ran tests against smithy-rs servers.

---
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.



Patch:
diff --git a/smithy-codegen-core/src/main/java/software/amazon/smithy/codegen/core/WriterDelegator.java b/smithy-codegen-core/src/main/java/software/amazon/smithy/codegen/core/WriterDelegator.java
index 0156be49c..31492a473 100644
--- a/smithy-codegen-core/src/main/java/software/amazon/smithy/codegen/core/WriterDelegator.java
+++ b/smithy-codegen-core/src/main/java/software/amazon/smithy/codegen/core/WriterDelegator.java
@@ -176,8 +176,7 @@ public class WriterDelegator<W extends SymbolWriter<W, ? extends ImportContainer
     }
 
     /**
-     * Gets or creates a writer for a {@link Shape} by converting the {@link Shape}
-     * to a {@code Symbol}.
+     * Gets or creates a writer for a {@link Symbol}.
      *
      * <p>Any dependencies (i.e., {@link SymbolDependency}) required by the
      * {@code Symbol} are automatically registered with the writer.
@@ -190,14 +189,10 @@ public class WriterDelegator<W extends SymbolWriter<W, ? extends ImportContainer
      * the writer (either a newline or whatever value was set on
      * {@link #setAutomaticSeparator}).
      *
-     * <p>This method may be overridden as needed.
-     *
-     * @param shape Shape to create the writer for.
+     * @param symbol Symbol to create the writer for.
      * @param writerConsumer Consumer that is expected to write to the {@code SymbolWriter}.
      */
-    public void useShapeWriter(Shape shape, Consumer<W> writerConsumer) {
-        // Checkout/create the appropriate writer for the shape.
-        Symbol symbol = symbolProvider.toSymbol(shape);
+    public final void useSymbolWriter(Symbol symbol, Consumer<W> writerConsumer) {
         W writer = checkoutWriter(symbol.getDefinitionFile(), symbol.getNamespace());
 
         // Add any needed DECLARE symbols.
@@ -209,6 +204,31 @@ public class WriterDelegator<W extends SymbolWriter<W, ? extends ImportContainer
         writer.popState();
     }
 
+    /**
+     * Gets or creates a writer for a {@link Shape} by converting the {@link Shape}
+     * to a {@code Symbol}.
+     *
+     * <p>Any dependencies (i.e., {@link SymbolDependency}) required by the
+     * {@code Symbol} are automatically registered with the writer.
+     *
+     * <p>Any imports required to declare the {@code Symbol} in code (i.e.,
+     * {@link SymbolReference.ContextOption#DECLARE}) are automatically
+     * registered with the writer.
+     *
+     * <p>If a writer already exists, a newline is automatically appended to
+     * the writer (either a newline or whatever value was set on
+     * {@link #setAutomaticSeparator}).
+     *
+     * <p>This method may be overridden as needed.
+     *
+     * @param shape Shape to create the writer for.
+     * @param writerConsumer Consumer that is expected to write to the {@code SymbolWriter}.
+     */
+    public void useShapeWriter(Shape shape, Consumer<W> writerConsumer) {
+        // Checkout/create the appropriate writer for the shape.
+        useSymbolWriter(symbolProvider.toSymbol(shape), writerConsumer);
+    }
+
     /**
      * Sets the automatic separator that is written to a {@code SymbolWriter}
      * each time the writer is reused.
diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/shapes/SmithyIdlModelSerializer.java b/smithy-model/src/main/java/software/amazon/smithy/model/shapes/SmithyIdlModelSerializer.java
index 8d0aec396..53000a44c 100644
--- a/smithy-model/src/main/java/software/amazon/smithy/model/shapes/SmithyIdlModelSerializer.java
+++ b/smithy-model/src/main/java/software/amazon/smithy/model/shapes/SmithyIdlModelSerializer.java
@@ -34,6 +34,7 @@ import java.util.function.Predicate;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 import software.amazon.smithy.model.Model;
+import software.amazon.smithy.model.knowledge.OperationIndex;
 import software.amazon.smithy.model.loader.Prelude;
 import software.amazon.smithy.model.node.ArrayNode;
 import software.amazon.smithy.model.node.BooleanNode;
@@ -74,6 +75,7 @@ public final class SmithyIdlModelSerializer {
     private final String inlineInputSuffix;
     private final String inlineOutputSuffix;
     private final boolean inferInlineIoSuffixes;
+    private final boolean shouldCoerceInlineIo;
 
     /**
      * Trait serialization features.
@@ -114,15 +116,21 @@ public final class SmithyIdlModelSerializer {
         traitFilter = builder.traitFilter.and(FunctionalUtils.not(Trait::isSynthetic));
         basePath = builder.basePath;
         if (basePath != null) {
-            Function<Shape, Path> shapePlacer = builder.shapePlacer;
-            this.shapePlacer = shape -> this.basePath.resolve(shapePlacer.apply(shape));
+            Function<Shape, Path> placer = builder.shapePlacer;
+            shapePlacer = shape -> basePath.resolve(placer.apply(shape));
         } else {
-            this.shapePlacer = builder.shapePlacer;
+            shapePlacer = builder.shapePlacer;
+        }
+        componentOrder = builder.componentOrder;
+        inlineInputSuffix = builder.inlineInputSuffix;
+        inlineOutputSuffix = builder.inlineOutputSuffix;
+        shouldCoerceInlineIo = builder.shouldCoerceInlineIo;
+        // Force inferring suffixes on if coercion is on.
+        if (shouldCoerceInlineIo) {
+            inferInlineIoSuffixes = true;
+        } else {
+            inferInlineIoSuffixes = builder.inferInlineIoSuffixes;
         }
-        this.componentOrder = builder.componentOrder;
-        this.inlineInputSuffix = builder.inlineInputSuffix;
-        this.inlineOutputSuffix = builder.inlineOutputSuffix;
-        this.inferInlineIoSuffixes = builder.inferInlineIoSuffixes;
     }
 
     /**
@@ -193,6 +201,7 @@ public final class SmithyIdlModelSerializer {
             String inputSuffix,
             String outputSuffix
     ) {
+        OperationIndex operationIndex = OperationIndex.of(fullModel);
         Set<ShapeId> inlineableShapes = new HashSet<>();
         for (Shape shape : shapes) {
             if (!shape.isOperationShape()) {
@@ -201,14 +210,14 @@ public final class SmithyIdlModelSerializer {
             OperationShape operation = shape.asOperationShape().get();
             if (!operation.getInputShape().equals(UnitTypeTrait.UNIT)) {
                 Shape inputShape = fullModel.expectShape(operation.getInputShape());
-                if (shapes.contains(inputShape) && inputShape.hasTrait(InputTrait.ID)
+                if (shapes.contains(inputShape) && shouldInlineInputShape(operationIndex, inputShape)
                         && inputShape.getId().getName().equals(operation.getId().getName() + inputSuffix)) {
                     inlineableShapes.add(operation.getInputShape());
                 }
             }
             if (!operation.getOutputShape().equals(UnitTypeTrait.UNIT)) {
                 Shape outputShape = fullModel.expectShape(operation.getOutputShape());
-                if (shapes.contains(outputShape) && outputShape.hasTrait(OutputTrait.ID)
+                if (shapes.contains(outputShape) && shouldInlineOutputShape(operationIndex, outputShape)
                         && outputShape.getId().getName().equals(operation.getId().getName() + outputSuffix)) {
                     inlineableShapes.add(operation.getOutputShape());
                 }
@@ -217,6 +226,18 @@ public final class SmithyIdlModelSerializer {
         return inlineableShapes;
     }
 
+    private boolean shouldInlineInputShape(OperationIndex operationIndex, Shape target) {
+        // Only allow coercion if the shape is only used as one input.
+        return target.hasTrait(InputTrait.ID)
+                || (shouldCoerceInlineIo && operationIndex.getInputBindings(target).size() == 1);
+    }
+
+    private boolean shouldInlineOutputShape(OperationIndex operationIndex, Shape target) {
+        // Only allow coercion if the shape is only used as one output.
+        return target.hasTrait(OutputTrait.ID)
+                || (shouldCoerceInlineIo && operationIndex.getOutputBindings(target).size() == 1);
+    }
+
     private Pair<String, String> determineInlineSuffixes(Model fullModel, Collection<Shape> shapes) {
         if (!inferInlineIoSuffixes) {
             return Pair.of(inlineInputSuffix, inlineOutputSuffix);
@@ -330,6 +351,7 @@ public final class SmithyIdlModelSerializer {
         private String inlineInputSuffix = DEFAULT_INLINE_INPUT_SUFFIX;
         private String inlineOutputSuffix = DEFAULT_INLINE_OUTPUT_SUFFIX;
         private boolean inferInlineIoSuffixes = false;
+        private boolean shouldCoerceInlineIo = false;
 
         public Builder() {}
 
@@ -457,11 +479,30 @@ public final class SmithyIdlModelSerializer {
          * <p>The suffixes set by {@link #inlineInputSuffix(String)} and {@link #inlineOutputSuffix(String)}
          * will be the default values.
          *
-         * @param shouldinferInlineIoSuffixes Whether inline IO suffixes should be inferred for each file.
+         * @param shouldInferInlineIoSuffixes Whether inline IO suffixes should be inferred for each file.
+         * @return Returns the builder.
+         */
+        public Builder inferInlineIoSuffixes(boolean shouldInferInlineIoSuffixes) {
+            this.inferInlineIoSuffixes = shouldInferInlineIoSuffixes;
+            return this;
+        }
+
+        /**
+         * Determines whether inline IO should be coerced for shapes operation input
+         * and output that does not have the {@code @input} or {@code @output} trait,
+         * respectively.
+         *
+         * <p>If true, this will determine any shared IO suffixes for each file. Only the
+         * shapes present within each file will impact what that file's suffixes will be.
+         *
+         * <p>The suffixes set by {@link #inlineInputSuffix(String)} and {@link #inlineOutputSuffix(String)}
+         * will be the default values.
+         *
+         * @param shouldCoerceInlineIo Whether inline IO should be coerced for each file.
          * @return Returns the builder.
          */
-        public Builder inferInlineIoSuffixes(boolean shouldinferInlineIoSuffixes) {
-            this.inferInlineIoSuffixes = shouldinferInlineIoSuffixes;
+        public Builder coerceInlineIo(boolean shouldCoerceInlineIo) {
+            this.shouldCoerceInlineIo = shouldCoerceInlineIo;
             return this;
         }
 
@@ -833,7 +874,7 @@ public final class SmithyIdlModelSerializer {
         }
 
         private boolean hasOnlyDefaultTrait(Shape shape, ShapeId defaultTrait) {
-            return shape.getAllTraits().size() == 1 && shape.hasTrait(defaultTrait);
+            return shape.getAllTraits().isEmpty() || (shape.getAllTraits().size() == 1 && shape.hasTrait(defaultTrait));
         }
     }
 
diff --git a/smithy-trait-codegen/src/main/java/software/amazon/smithy/traitcodegen/TraitCodegenSymbolProvider.java b/smithy-trait-codegen/src/main/java/software/amazon/smithy/traitcodegen/TraitCodegenSymbolProvider.java
index 4652143e1..3affb9bff 100644
--- a/smithy-trait-codegen/src/main/java/software/amazon/smithy/traitcodegen/TraitCodegenSymbolProvider.java
+++ b/smithy-trait-codegen/src/main/java/software/amazon/smithy/traitcodegen/TraitCodegenSymbolProvider.java
@@ -15,7 +15,7 @@ import java.util.Set;
 import software.amazon.smithy.codegen.core.Symbol;
 import software.amazon.smithy.codegen.core.SymbolProvider;
 import software.amazon.smithy.model.Model;
-import software.amazon.smithy.model.node.ObjectNode;
+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;
@@ -166,7 +166,7 @@ final class TraitCodegenSymbolProvider extends ShapeVisitor.DataShapeVisitor<Sym
 
     @Override
     public Symbol documentShape(DocumentShape shape) {
-        return TraitCodegenUtils.fromClass(ObjectNode.class);
+        return TraitCodegenUtils.fromClass(Node.class);
     }
 
     @Override
diff --git a/smithy-trait-codegen/src/main/java/software/amazon/smithy/traitcodegen/generators/FromNodeMapperVisitor.java b/smithy-trait-codegen/src/main/java/software/amazon/smithy/traitcodegen/generators/FromNodeMapperVisitor.java
index 3b0f2bd14..c53627593 100644
--- a/smithy-trait-codegen/src/main/java/software/amazon/smithy/traitcodegen/generators/FromNodeMapperVisitor.java
+++ b/smithy-trait-codegen/src/main/java/software/amazon/smithy/traitcodegen/generators/FromNodeMapperVisitor.java
@@ -112,6 +112,7 @@ final class FromNodeMapperVisitor extends ShapeVisitor.DataShapeVisitor<Void> {
 
     @Override
     public Void documentShape(DocumentShape shape) {
+        writer.writeWithNoFormatting(varName);
         return null;
     }
 


Test patch:
diff --git a/smithy-aws-protocol-tests/model/restJson1/http-payload.smithy b/smithy-aws-protocol-tests/model/restJson1/http-payload.smithy
index d2acdae8f..14d1e19c7 100644
--- a/smithy-aws-protocol-tests/model/restJson1/http-payload.smithy
+++ b/smithy-aws-protocol-tests/model/restJson1/http-payload.smithy
@@ -6,6 +6,7 @@ $version: "2.0"
 namespace aws.protocoltests.restjson
 
 use aws.protocols#restJson1
+use smithy.test#httpMalformedRequestTests
 use aws.protocoltests.shared#TextPlainBlob
 use smithy.test#httpRequestTests
 use smithy.test#httpResponseTests
@@ -76,6 +77,26 @@ apply HttpPayloadTraits @httpRequestTests([
         },
         appliesTo: "server",
     },
+    {
+        id: "RestJsonHttpPayloadTraitsWithBlobAcceptsNoContentType",
+        documentation: """
+            Servers must accept no content type for blob inputs
+            without the media type trait.""",
+        protocol: restJson1,
+        method: "POST",
+        uri: "/HttpPayloadTraits",
+        body: "This is definitely a jpeg",
+        bodyMediaType: "application/octet-stream",
+        headers: {
+            "X-Foo": "Foo",
+        },
+        params: {
+            foo: "Foo",
+            blob: "This is definitely a jpeg"
+        },
+        appliesTo: "server",
+        tags: [ "content-type" ]
+    },
     {
         id: "RestJsonHttpPayloadTraitsWithBlobAcceptsAllAccepts",
         documentation: """
@@ -353,3 +374,120 @@ structure HttpPayloadWithUnionInputOutput {
 union UnionPayload {
     greeting: String
 }
+
+/// This example serializes a string shape in the payload.
+///
+/// In this example, no JSON document is synthesized because the payload is
+/// not a structure or a union type.
+@http(uri: "/HttpPayloadTraitOnString", method: "POST")
+operation HttpPayloadTraitOnString {
+    input: HttpPayloadTraitOnStringInputOutput,
+    output: HttpPayloadTraitOnStringInputOutput
+}
+
+structure HttpPayloadTraitOnStringInputOutput {
+    @httpPayload
+    foo: String,
+}
+
+apply HttpPayloadTraitOnString @httpRequestTests([
+    {
+        id: "RestJsonHttpPayloadTraitOnString",
+        documentation: "Serializes a string in the HTTP payload",
+        protocol: restJson1,
+        method: "POST",
+        uri: "/HttpPayloadTraitOnString",
+        body: "Foo",
+        bodyMediaType: "text/plain",
+        headers: {
+            "Content-Type": "text/plain",
+        },
+        requireHeaders: [
+            "Content-Length"
+        ],
+        params: {
+            foo: "Foo",
+        }
+    },
+])
+
+apply HttpPayloadTraitOnString @httpResponseTests([
+    {
+        id: "RestJsonHttpPayloadTraitOnString",
+        documentation: "Serializes a string in the HTTP payload",
+        protocol: restJson1,
+        code: 200,
+        body: "Foo",
+        bodyMediaType: "text/plain",
+        headers: {
+            "Content-Type": "text/plain",
+        },
+        params: {
+            foo: "Foo",
+        }
+    },
+])
+
+apply HttpPayloadTraitOnString @httpMalformedRequestTests([
+    {
+        id: "RestJsonHttpPayloadTraitOnStringNoContentType",
+        documentation: "Serializes a string in the HTTP payload without a content-type header",
+        protocol: restJson1,
+        request: {
+            method: "POST",
+            uri: "/HttpPayloadTraitOnString",
+            body: "Foo",
+            // We expect a `Content-Type` header but none was provided.
+        },
+        response: {
+            code: 415,
+            headers: {
+                "x-amzn-errortype": "UnsupportedMediaTypeException"
+            }
+        },
+        tags: [ "content-type" ]
+    },
+    {
+        id: "RestJsonHttpPayloadTraitOnStringWrongContentType",
+        documentation: "Serializes a string in the HTTP payload without the expected content-type header",
+        protocol: restJson1,
+        request: {
+            method: "POST",
+            uri: "/HttpPayloadTraitOnString",
+            body: "Foo",
+            headers: {
+                // We expect `text/plain`.
+                "Content-Type": "application/json",
+            },
+        },
+        response: {
+            code: 415,
+            headers: {
+                "x-amzn-errortype": "UnsupportedMediaTypeException"
+            }
+        },
+        tags: [ "content-type" ]
+    },
+    {
+        id: "RestJsonHttpPayloadTraitOnStringUnsatisfiableAccept",
+        documentation: "Serializes a string in the HTTP payload with an unstatisfiable accept header",
+        protocol: restJson1,
+        request: {
+            method: "POST",
+            uri: "/HttpPayloadTraitOnString",
+            body: "Foo",
+            headers: {
+                "Content-Type": "text/plain",
+                // We can't satisfy this requirement; the server will return `text/plain`.
+                "Accept": "application/json",
+            },
+        },
+        response: {
+            code: 406,
+            headers: {
+                "x-amzn-errortype": "NotAcceptableException"
+            }
+        },
+        tags: [ "accept" ]
+    },
+])
diff --git a/smithy-aws-protocol-tests/model/restJson1/http-string-payload.smithy b/smithy-aws-protocol-tests/model/restJson1/http-string-payload.smithy
index 8aa1f517b..52cab5cc9 100644
--- a/smithy-aws-protocol-tests/model/restJson1/http-string-payload.smithy
+++ b/smithy-aws-protocol-tests/model/restJson1/http-string-payload.smithy
@@ -10,6 +10,7 @@ use smithy.test#httpResponseTests
     {
         id: "RestJsonEnumPayloadRequest",
         uri: "/EnumPayload",
+        headers: { "Content-Type": "text/plain" },
         body: "enumvalue",
         params: { payload: "enumvalue" },
         method: "POST",
@@ -19,6 +20,7 @@ use smithy.test#httpResponseTests
 @httpResponseTests([
     {
         id: "RestJsonEnumPayloadResponse",
+        headers: { "Content-Type": "text/plain" },
         body: "enumvalue",
         params: { payload: "enumvalue" },
         protocol: "aws.protocols#restJson1",
@@ -44,6 +46,7 @@ enum StringEnum {
     {
         id: "RestJsonStringPayloadRequest",
         uri: "/StringPayload",
+        headers: { "Content-Type": "text/plain" },
         body: "rawstring",
         params: { payload: "rawstring" },
         method: "POST",
@@ -53,6 +56,7 @@ enum StringEnum {
 @httpResponseTests([
     {
         id: "RestJsonStringPayloadResponse",
+        headers: { "Content-Type": "text/plain" },
         body: "rawstring",
         params: { payload: "rawstring" },
         protocol: "aws.protocols#restJson1",
diff --git a/smithy-aws-protocol-tests/model/restJson1/main.smithy b/smithy-aws-protocol-tests/model/restJson1/main.smithy
index 2a414502b..5e5171951 100644
--- a/smithy-aws-protocol-tests/model/restJson1/main.smithy
+++ b/smithy-aws-protocol-tests/model/restJson1/main.smithy
@@ -62,6 +62,7 @@ service RestJson {
         HttpEnumPayload,
         HttpStringPayload,
         HttpPayloadWithUnion,
+        HttpPayloadTraitOnString,
 
         // @httpResponseCode tests
         HttpResponseCode,
diff --git a/smithy-aws-protocol-tests/model/restXml/http-string-payload.smithy b/smithy-aws-protocol-tests/model/restXml/http-string-payload.smithy
index 851e34066..9b25b3af0 100644
--- a/smithy-aws-protocol-tests/model/restXml/http-string-payload.smithy
+++ b/smithy-aws-protocol-tests/model/restXml/http-string-payload.smithy
@@ -10,6 +10,7 @@ use smithy.test#httpResponseTests
     {
         id: "RestXmlEnumPayloadRequest",
         uri: "/EnumPayload",
+        headers: { "Content-Type": "text/plain" },
         body: "enumvalue",
         params: { payload: "enumvalue" },
         method: "POST",
@@ -19,6 +20,7 @@ use smithy.test#httpResponseTests
 @httpResponseTests([
     {
         id: "RestXmlEnumPayloadResponse",
+        headers: { "Content-Type": "text/plain" },
         body: "enumvalue",
         params: { payload: "enumvalue" },
         protocol: "aws.protocols#restXml",
@@ -44,6 +46,7 @@ enum StringEnum {
     {
         id: "RestXmlStringPayloadRequest",
         uri: "/StringPayload",
+        headers: { "Content-Type": "text/plain" },
         body: "rawstring",
         params: { payload: "rawstring" },
         method: "POST",
@@ -53,6 +56,7 @@ enum StringEnum {
 @httpResponseTests([
     {
         id: "RestXmlStringPayloadResponse",
+        headers: { "Content-Type": "text/plain" },
         body: "rawstring",
         params: { payload: "rawstring" },
         protocol: "aws.protocols#restXml",
diff --git a/smithy-codegen-core/src/test/java/software/amazon/smithy/codegen/core/WriterDelegatorTest.java b/smithy-codegen-core/src/test/java/software/amazon/smithy/codegen/core/WriterDelegatorTest.java
index 4a5f48de0..b1ed5400a 100644
--- a/smithy-codegen-core/src/test/java/software/amazon/smithy/codegen/core/WriterDelegatorTest.java
+++ b/smithy-codegen-core/src/test/java/software/amazon/smithy/codegen/core/WriterDelegatorTest.java
@@ -47,6 +47,22 @@ public class WriterDelegatorTest {
         assertThat(delegator.getWriters(), hasKey(Paths.get("com/foo/Baz.bam").toString()));
     }
 
+    @Test
+    public void createsFilesForSymbolWriters() {
+        MockManifest mockManifest = new MockManifest();
+        SymbolProvider provider = (shape) -> null;
+        WriterDelegator<MySimpleWriter> delegator = new WriterDelegator<>(
+                mockManifest, provider, (f, n) -> new MySimpleWriter(n));
+        Symbol symbol =  Symbol.builder()
+                .namespace("com.foo", ".")
+                .name("Baz")
+                .definitionFile("com/foo/Baz.bam")
+                .build();
+        delegator.useSymbolWriter(symbol, writer -> { });
+
+        assertThat(delegator.getWriters(), hasKey(Paths.get("com/foo/Baz.bam").toString()));
+    }
+
     @Test
     public void aggregatesDependencies() {
         MockManifest mockManifest = new MockManifest();
diff --git a/smithy-model/src/test/java/software/amazon/smithy/model/shapes/SmithyIdlModelSerializerTest.java b/smithy-model/src/test/java/software/amazon/smithy/model/shapes/SmithyIdlModelSerializerTest.java
index 15431ecd5..27dea4cc8 100644
--- a/smithy-model/src/test/java/software/amazon/smithy/model/shapes/SmithyIdlModelSerializerTest.java
+++ b/smithy-model/src/test/java/software/amazon/smithy/model/shapes/SmithyIdlModelSerializerTest.java
@@ -8,6 +8,7 @@ import static org.hamcrest.Matchers.equalTo;
 import static org.hamcrest.Matchers.hasKey;
 import static org.hamcrest.Matchers.is;
 import static org.hamcrest.Matchers.not;
+import static org.junit.jupiter.api.Assertions.assertEquals;
 
 import java.io.IOException;
 import java.net.URISyntaxException;
@@ -49,7 +50,7 @@ public class SmithyIdlModelSerializerTest {
         }
 
         String serializedString = serialized.entrySet().iterator().next().getValue();
-        Assertions.assertEquals(IoUtils.readUtf8File(path).replaceAll("\\R", "\n"), serializedString);
+        assertEquals(IoUtils.readUtf8File(path).replaceAll("\\R", "\n"), serializedString);
     }
 
     @Test
@@ -259,7 +260,7 @@ public class SmithyIdlModelSerializerTest {
         String expectedOutput = IoUtils.readUtf8Resource(getClass(), "idl-serialization/enum-mixin-output.smithy")
                 .replaceAll("\\R", "\n");
         String serializedString = serialized.entrySet().iterator().next().getValue();
-        Assertions.assertEquals(expectedOutput, serializedString);
+        assertEquals(expectedOutput, serializedString);
     }
 
     @Test
@@ -306,4 +307,21 @@ public class SmithyIdlModelSerializerTest {
             assertThat(actual, equalTo(expected));
         }
     }
+
+    @Test
+    public void coercesInlineIO() {
+        Model before = Model.assembler()
+                .addImport(getClass().getResource("idl-serialization/coerced-io/before.smithy"))
+                .assemble().unwrap();
+
+        Map<Path, String> reserialized = SmithyIdlModelSerializer.builder()
+                .coerceInlineIo(true)
+                .build()
+                .serialize(before);
+        String modelResult = reserialized.values().iterator().next().replace("\r\n", "\n");
+
+        String expected = IoUtils.readUtf8Url(getClass().getResource("idl-serialization/coerced-io/after.smithy"))
+                .replace("\r\n", "\n");
+        assertEquals(expected, modelResult);
+    }
 }
diff --git a/smithy-model/src/test/resources/software/amazon/smithy/model/shapes/idl-serialization/coerced-io/after.smithy b/smithy-model/src/test/resources/software/amazon/smithy/model/shapes/idl-serialization/coerced-io/after.smithy
new file mode 100644
index 000000000..7f76e438f
--- /dev/null
+++ b/smithy-model/src/test/resources/software/amazon/smithy/model/shapes/idl-serialization/coerced-io/after.smithy
@@ -0,0 +1,40 @@
+$version: "2.0"
+$operationInputSuffix: "Request"
+$operationOutputSuffix: "Response"
+
+namespace com.example
+
+service InlineService {
+    operations: [
+        MultipleBind1
+        MultipleBind2
+        WithoutTraits
+        WithTraits
+    ]
+}
+
+operation MultipleBind1 {
+    input: MultipleBindRequest
+    output: MultipleBindResponse
+}
+
+operation MultipleBind2 {
+    input: MultipleBindRequest
+    output: MultipleBindResponse
+}
+
+operation WithoutTraits {
+    input := {}
+    output := {}
+}
+
+operation WithTraits {
+    input := {
+        a: String
+    }
+    output := {}
+}
+
+structure MultipleBindRequest {}
+
+structure MultipleBindResponse {}
diff --git a/smithy-model/src/test/resources/software/amazon/smithy/model/shapes/idl-serialization/coerced-io/before.smithy b/smithy-model/src/test/resources/software/amazon/smithy/model/shapes/idl-serialization/coerced-io/before.smithy
new file mode 100644
index 000000000..c4d9a2a59
--- /dev/null
+++ b/smithy-model/src/test/resources/software/amazon/smithy/model/shapes/idl-serialization/coerced-io/before.smithy
@@ -0,0 +1,48 @@
+$version: "2.0"
+
+namespace com.example
+
+service InlineService {
+    operations: [
+        MultipleBind1
+        MultipleBind2
+        WithoutTraits
+        WithTraits
+    ]
+}
+
+operation MultipleBind1 {
+    input: MultipleBindRequest
+    output: MultipleBindResponse
+}
+
+operation MultipleBind2 {
+    input: MultipleBindRequest
+    output: MultipleBindResponse
+}
+
+operation WithoutTraits {
+    input: WithoutTraitsRequest
+    output: WithoutTraitsResponse
+}
+
+operation WithTraits {
+    input: WithTraitsRequest
+    output: WithTraitsResponse
+}
+
+structure MultipleBindRequest {}
+
+structure MultipleBindResponse {}
+
+structure WithoutTraitsRequest {}
+
+structure WithoutTraitsResponse {}
+
+@input
+structure WithTraitsRequest {
+    a: String
+}
+
+@output
+structure WithTraitsResponse {}
diff --git a/smithy-protocol-tests/model/rpcv2Cbor/cbor-maps.smithy b/smithy-protocol-tests/model/rpcv2Cbor/cbor-maps.smithy
index 93e05e026..0f4a5223d 100644
--- a/smithy-protocol-tests/model/rpcv2Cbor/cbor-maps.smithy
+++ b/smithy-protocol-tests/model/rpcv2Cbor/cbor-maps.smithy
@@ -171,8 +171,7 @@ apply RpcV2CborDenseMaps @httpResponseTests([
         params: {
             "denseSetMap": {
                 "x": [],
-                "y": ["a", "b"],
-                "z": null
+                "y": ["a", "b"]
             }
         }
     }
diff --git a/smithy-protocol-tests/model/rpcv2Cbor/cbor-structs.smithy b/smithy-protocol-tests/model/rpcv2Cbor/cbor-structs.smithy
index 3bb58462a..7ea41d9cf 100644
--- a/smithy-protocol-tests/model/rpcv2Cbor/cbor-structs.smithy
+++ b/smithy-protocol-tests/model/rpcv2Cbor/cbor-structs.smithy
@@ -21,12 +21,12 @@ use smithy.test#httpResponseTests
         method: "POST",
         bodyMediaType: "application/cbor",
         uri: "/service/RpcV2Protocol/operation/SimpleScalarProperties",
-        body: "v2lieXRlVmFsdWUFa2RvdWJsZVZhbHVl+z/+OVgQYk3TcWZhbHNlQm9vbGVhblZhbHVl9GpmbG9hdFZhbHVl+kDz989saW50ZWdlclZhbHVlGQEAaWxvbmdWYWx1ZRkmkWpzaG9ydFZhbHVlGSaqa3N0cmluZ1ZhbHVlZnNpbXBsZXB0cnVlQm9vbGVhblZhbHVl9WlibG9iVmFsdWVDZm9v/w=="
+        body: "v2lieXRlVmFsdWUFa2RvdWJsZVZhbHVl+z/+OVgQYk3TcWZhbHNlQm9vbGVhblZhbHVl9GpmbG9hdFZhbHVl+kD0AABsaW50ZWdlclZhbHVlGQEAaWxvbmdWYWx1ZRkmkWpzaG9ydFZhbHVlGSaqa3N0cmluZ1ZhbHVlZnNpbXBsZXB0cnVlQm9vbGVhblZhbHVl9WlibG9iVmFsdWVDZm9v/w==",
         params: {
             byteValue: 5,
             doubleValue: 1.889,
             falseBooleanValue: false,
-            floatValue: 7.624,
+            floatValue: 7.625,
             integerValue: 256,
             longValue: 9873,
             shortValue: 9898,
@@ -52,12 +52,12 @@ use smithy.test#httpResponseTests
         method: "POST",
         bodyMediaType: "application/cbor",
         uri: "/service/RpcV2Protocol/operation/SimpleScalarProperties",
-        body: "qmlieXRlVmFsdWUFf2Zkb3VibGVlVmFsdWX/+z/+OVgQYk3Tf2VmYWxzZWdCb29sZWFuZVZhbHVl//RqZmxvYXRWYWx1ZfpA8/fPbGludGVnZXJWYWx1ZRkBAGlsb25nVmFsdWUZJpFqc2hvcnRWYWx1ZRkmqn9mc3RyaW5nZVZhbHVl/2ZzaW1wbGVwdHJ1ZUJvb2xlYW5WYWx1ZfVpYmxvYlZhbHVlQ2Zvbw=="
+        body: "qmlieXRlVmFsdWUFf2Zkb3VibGVlVmFsdWX/+z/+OVgQYk3Tf2VmYWxzZWdCb29sZWFuZVZhbHVl//RqZmxvYXRWYWx1ZfpA9AAAbGludGVnZXJWYWx1ZRkBAGlsb25nVmFsdWUZJpFqc2hvcnRWYWx1ZRkmqn9mc3RyaW5nZVZhbHVl/2ZzaW1wbGVwdHJ1ZUJvb2xlYW5WYWx1ZfVpYmxvYlZhbHVlQ2Zvbw==",
         params: {
             byteValue: 5,
             doubleValue: 1.889,
             falseBooleanValue: false,
-            floatValue: 7.624,
+            floatValue: 7.625,
             integerValue: 256,
             longValue: 9873,
             shortValue: 9898,
@@ -246,12 +246,12 @@ use smithy.test#httpResponseTests
         method: "POST",
         bodyMediaType: "application/cbor",
         uri: "/service/RpcV2Protocol/operation/SimpleScalarProperties",
-        body: "v2lieXRlVmFsdWUFa2RvdWJsZVZhbHVl+z/+OVgQYk3TcWZhbHNlQm9vbGVhblZhbHVl9GpmbG9hdFZhbHVl+kDz989rZXh0cmFPYmplY3S/c2luZGVmaW5pdGVMZW5ndGhNYXC/a3dpdGhBbkFycmF5nwECA///cWRlZmluaXRlTGVuZ3RoTWFwo3J3aXRoQURlZmluaXRlQXJyYXmDAQIDeB1hbmRTb21lSW5kZWZpbml0ZUxlbmd0aFN0cmluZ3gfdGhhdCBoYXMsIGJlZW4gY2h1bmtlZCBvbiBjb21tYWxub3JtYWxTdHJpbmdjZm9vanNob3J0VmFsdWUZJw9uc29tZU90aGVyRmllbGR2dGhpcyBzaG91bGQgYmUgc2tpcHBlZP9saW50ZWdlclZhbHVlGQEAaWxvbmdWYWx1ZRkmkWpzaG9ydFZhbHVlGSaqa3N0cmluZ1ZhbHVlZnNpbXBsZXB0cnVlQm9vbGVhblZhbHVl9WlibG9iVmFsdWVDZm9v/w==",
+        body: "v2lieXRlVmFsdWUFa2RvdWJsZVZhbHVl+z/+OVgQYk3TcWZhbHNlQm9vbGVhblZhbHVl9GpmbG9hdFZhbHVl+kD0AABrZXh0cmFPYmplY3S/c2luZGVmaW5pdGVMZW5ndGhNYXC/a3dpdGhBbkFycmF5nwECA///cWRlZmluaXRlTGVuZ3RoTWFwo3J3aXRoQURlZmluaXRlQXJyYXmDAQIDeB1hbmRTb21lSW5kZWZpbml0ZUxlbmd0aFN0cmluZ3gfdGhhdCBoYXMsIGJlZW4gY2h1bmtlZCBvbiBjb21tYWxub3JtYWxTdHJpbmdjZm9vanNob3J0VmFsdWUZJw9uc29tZU90aGVyRmllbGR2dGhpcyBzaG91bGQgYmUgc2tpcHBlZP9saW50ZWdlclZhbHVlGQEAaWxvbmdWYWx1ZRkmkWpzaG9ydFZhbHVlGSaqa3N0cmluZ1ZhbHVlZnNpbXBsZXB0cnVlQm9vbGVhblZhbHVl9WlibG9iVmFsdWVDZm9v/w==",
         params: {
             byteValue: 5,
             doubleValue: 1.889,
             falseBooleanValue: false,
-            floatValue: 7.624,
+            floatValue: 7.625,
             integerValue: 256,
             longValue: 9873,
             shortValue: 9898,
@@ -272,14 +272,14 @@ use smithy.test#httpResponseTests
             "Content-Type": "application/cbor"
         }
         bodyMediaType: "application/cbor",
-        body: "v3B0cnVlQm9vbGVhblZhbHVl9XFmYWxzZUJvb2xlYW5WYWx1ZfRpYnl0ZVZhbHVlBWtkb3VibGVWYWx1Zfs//jlYEGJN02pmbG9hdFZhbHVl+kDz989saW50ZWdlclZhbHVlGQEAanNob3J0VmFsdWUZJqprc3RyaW5nVmFsdWVmc2ltcGxlaWJsb2JWYWx1ZUNmb2//"
+        body: "v3B0cnVlQm9vbGVhblZhbHVl9XFmYWxzZUJvb2xlYW5WYWx1ZfRpYnl0ZVZhbHVlBWtkb3VibGVWYWx1Zfs//jlYEGJN02pmbG9hdFZhbHVl+kD0AABsaW50ZWdlclZhbHVlGQEAanNob3J0VmFsdWUZJqprc3RyaW5nVmFsdWVmc2ltcGxlaWJsb2JWYWx1ZUNmb2//",
         code: 200,
         params: {
             trueBooleanValue: true,
             falseBooleanValue: false,
             byteValue: 5,
             doubleValue: 1.889,
-            floatValue: 7.624,
+            floatValue: 7.625,
             integerValue: 256,
             shortValue: 9898,
             stringValue: "simple",
@@ -295,14 +295,14 @@ use smithy.test#httpResponseTests
             "Content-Type": "application/cbor"
         }
         bodyMediaType: "application/cbor",
-        body: "qXB0cnVlQm9vbGVhblZhbHVl9XFmYWxzZUJvb2xlYW5WYWx1ZfRpYnl0ZVZhbHVlBWtkb3VibGVWYWx1Zfs//jlYEGJN02pmbG9hdFZhbHVl+kDz989saW50ZWdlclZhbHVlGQEAanNob3J0VmFsdWUZJqprc3RyaW5nVmFsdWVmc2ltcGxlaWJsb2JWYWx1ZUNmb28="
+        body: "qXB0cnVlQm9vbGVhblZhbHVl9XFmYWxzZUJvb2xlYW5WYWx1ZfRpYnl0ZVZhbHVlBWtkb3VibGVWYWx1Zfs//jlYEGJN02pmbG9hdFZhbHVl+kD0AABsaW50ZWdlclZhbHVlGQEAanNob3J0VmFsdWUZJqprc3RyaW5nVmFsdWVmc2ltcGxlaWJsb2JWYWx1ZUNmb28=",
         code: 200,
         params: {
             trueBooleanValue: true,
             falseBooleanValue: false,
             byteValue: 5,
             doubleValue: 1.889,
-            floatValue: 7.624,
+            floatValue: 7.625,
             integerValue: 256,
             shortValue: 9898,
             stringValue: "simple",
@@ -421,12 +421,12 @@ use smithy.test#httpResponseTests
         }
         code: 200,
         bodyMediaType: "application/cbor",
-        body: "v2lieXRlVmFsdWUFa2RvdWJsZVZhbHVl+z/+OVgQYk3TcWZhbHNlQm9vbGVhblZhbHVl9GpmbG9hdFZhbHVl+kDz989rZXh0cmFPYmplY3S/c2luZGVmaW5pdGVMZW5ndGhNYXC/a3dpdGhBbkFycmF5nwECA///cWRlZmluaXRlTGVuZ3RoTWFwo3J3aXRoQURlZmluaXRlQXJyYXmDAQIDeB1hbmRTb21lSW5kZWZpbml0ZUxlbmd0aFN0cmluZ3gfdGhhdCBoYXMsIGJlZW4gY2h1bmtlZCBvbiBjb21tYWxub3JtYWxTdHJpbmdjZm9vanNob3J0VmFsdWUZJw9uc29tZU90aGVyRmllbGR2dGhpcyBzaG91bGQgYmUgc2tpcHBlZP9saW50ZWdlclZhbHVlGQEAaWxvbmdWYWx1ZRkmkWpzaG9ydFZhbHVlGSaqa3N0cmluZ1ZhbHVlZnNpbXBsZXB0cnVlQm9vbGVhblZhbHVl9WlibG9iVmFsdWVDZm9v/w==",
+        body: "v2lieXRlVmFsdWUFa2RvdWJsZVZhbHVl+z/+OVgQYk3TcWZhbHNlQm9vbGVhblZhbHVl9GpmbG9hdFZhbHVl+kD0AABrZXh0cmFPYmplY3S/c2luZGVmaW5pdGVMZW5ndGhNYXC/a3dpdGhBbkFycmF5nwECA///cWRlZmluaXRlTGVuZ3RoTWFwo3J3aXRoQURlZmluaXRlQXJyYXmDAQIDeB1hbmRTb21lSW5kZWZpbml0ZUxlbmd0aFN0cmluZ3gfdGhhdCBoYXMsIGJlZW4gY2h1bmtlZCBvbiBjb21tYWxub3JtYWxTdHJpbmdjZm9vanNob3J0VmFsdWUZJw9uc29tZU90aGVyRmllbGR2dGhpcyBzaG91bGQgYmUgc2tpcHBlZP9saW50ZWdlclZhbHVlGQEAaWxvbmdWYWx1ZRkmkWpzaG9ydFZhbHVlGSaqa3N0cmluZ1ZhbHVlZnNpbXBsZXB0cnVlQm9vbGVhblZhbHVl9WlibG9iVmFsdWVDZm9v/w==",
         params: {
             byteValue: 5,
             doubleValue: 1.889,
             falseBooleanValue: false,
-            floatValue: 7.624,
+            floatValue: 7.625,
             integerValue: 256,
             longValue: 9873,
             shortValue: 9898,
diff --git a/smithy-protocol-tests/model/rpcv2Cbor/defaults.smithy b/smithy-protocol-tests/model/rpcv2Cbor/defaults.smithy
index a62f26b83..bf1e44834 100644
--- a/smithy-protocol-tests/model/rpcv2Cbor/defaults.smithy
+++ b/smithy-protocol-tests/model/rpcv2Cbor/defaults.smithy
@@ -24,7 +24,7 @@ apply OperationWithDefaults @httpRequestTests([
             "Content-Length"
         ],
         bodyMediaType: "application/cbor"
-        body: "v21kZWZhdWx0U3RyaW5nYmhpbmRlZmF1bHRCb29sZWFu9WtkZWZhdWx0TGlzdIBwZGVmYXVsdFRpbWVzdGFtcMH7AAAAAAAAAABrZGVmYXVsdEJsb2JDYWJja2RlZmF1bHRCeXRlAWxkZWZhdWx0U2hvcnQBbmRlZmF1bHRJbnRlZ2VyCmtkZWZhdWx0TG9uZxhkbGRlZmF1bHRGbG9hdPo/gAAAbWRlZmF1bHREb3VibGX7P/AAAAAAAABqZGVmYXVsdE1hcKBrZGVmYXVsdEVudW1jRk9PbmRlZmF1bHRJbnRFbnVtAWtlbXB0eVN0cmluZ2BsZmFsc2VCb29sZWFu9GllbXB0eUJsb2JAaHplcm9CeXRlAGl6ZXJvU2hvcnQAa3plcm9JbnRlZ2VyAGh6ZXJvTG9uZwBpemVyb0Zsb2F0+gAAAABqemVyb0RvdWJsZfsAAAAAAAAAAP8="
+        body: "v2hkZWZhdWx0c79tZGVmYXVsdFN0cmluZ2JoaW5kZWZhdWx0Qm9vbGVhbvVrZGVmYXVsdExpc3Sf/3BkZWZhdWx0VGltZXN0YW1wwQBrZGVmYXVsdEJsb2JjYWJja2RlZmF1bHRCeXRlAWxkZWZhdWx0U2hvcnQBbmRlZmF1bHRJbnRlZ2VyCmtkZWZhdWx0TG9uZxhkbGRlZmF1bHRGbG9hdPo/gAAAbWRlZmF1bHREb3VibGX6P4AAAGpkZWZhdWx0TWFwv/9rZGVmYXVsdEVudW1jRk9PbmRlZmF1bHRJbnRFbnVtAWtlbXB0eVN0cmluZ2BsZmFsc2VCb29sZWFu9GllbXB0eUJsb2JgaHplcm9CeXRlAGl6ZXJvU2hvcnQAa3plcm9JbnRlZ2VyAGh6ZXJvTG9uZwBpemVyb0Zsb2F0+gAAAABqemVyb0RvdWJsZfoAAAAA//8="
         params: {
             defaults: {}
         }
diff --git a/smithy-trait-codegen/src/it/java/software/amazon/smithy/traitcodegen/test/CreatesTraitTest.java b/smithy-trait-codegen/src/it/java/software/amazon/smithy/traitcodegen/test/CreatesTraitTest.java
index 0aa918b88..29f268a06 100644
--- a/smithy-trait-codegen/src/it/java/software/amazon/smithy/traitcodegen/test/CreatesTraitTest.java
+++ b/smithy-trait-codegen/src/it/java/software/amazon/smithy/traitcodegen/test/CreatesTraitTest.java
@@ -9,11 +9,13 @@ import com.example.traits.documents.StructWithNestedDocumentTrait;
 import com.example.traits.enums.IntEnumTrait;
 import com.example.traits.enums.StringEnumTrait;
 import com.example.traits.enums.SuitTrait;
+import com.example.traits.lists.DocumentListTrait;
 import com.example.traits.lists.ListMember;
 import com.example.traits.lists.NumberListTrait;
 import com.example.traits.lists.StringListTrait;
 import com.example.traits.lists.StructureListTrait;
 import com.example.traits.maps.MapValue;
+import com.example.traits.maps.StringDocumentMapTrait;
 import com.example.traits.maps.StringStringMapTrait;
 import com.example.traits.maps.StringToStructMapTrait;
 import com.example.traits.mixins.StructWithMixinTrait;
@@ -81,6 +83,10 @@ public class CreatesTraitTest {
                         ListMember.builder().a("first").b(1).c("other").build().toNode(),
                         ListMember.builder().a("second").b(2).c("more").build().toNode()
                 )),
+                Arguments.of(DocumentListTrait.ID, ArrayNode.fromNodes(
+                        ObjectNode.builder().withMember("a", "b").build(),
+                        ObjectNode.builder().withMember("c", "d").withMember("e", "f").build()
+                )),
                 // Maps
                 Arguments.of(StringStringMapTrait.ID, StringStringMapTrait.builder()
                         .putValues("a", "first").putValues("b", "other").build().toNode()
@@ -90,6 +96,13 @@ public class CreatesTraitTest {
                         .putValues("two", MapValue.builder().a("bar").b(4).build())
                         .build().toNode()
                 ),
+                Arguments.of(StringDocumentMapTrait.ID, StringDocumentMapTrait.builder()
+                        .putValues("a", ObjectNode.builder().withMember("a", "a").build().toNode())
+                        .putValues("b", ObjectNode.builder().withMember("b", "b").build().toNode())
+                        .putValues("string", Node.from("stuff"))
+                        .putValues("number", Node.from(1))
+                        .build().toNode()
+                ),
                 // Mixins
                 Arguments.of(StructureListWithMixinMemberTrait.ID,
                         ArrayNode.fromNodes(ObjectNode.builder().withMember("a", "a").withMember("d", "d").build())),
diff --git a/smithy-trait-codegen/src/it/java/software/amazon/smithy/traitcodegen/test/LoadsFromModelTest.java b/smithy-trait-codegen/src/it/java/software/amazon/smithy/traitcodegen/test/LoadsFromModelTest.java
index 377b4953f..5a14fe995 100644
--- a/smithy-trait-codegen/src/it/java/software/amazon/smithy/traitcodegen/test/LoadsFromModelTest.java
+++ b/smithy-trait-codegen/src/it/java/software/amazon/smithy/traitcodegen/test/LoadsFromModelTest.java
@@ -16,10 +16,12 @@ import com.example.traits.idref.IdRefStringTrait;
 import com.example.traits.idref.IdRefStructTrait;
 import com.example.traits.idref.IdRefStructWithNestedIdsTrait;
 import com.example.traits.idref.NestedIdRefHolder;
+import com.example.traits.lists.DocumentListTrait;
 import com.example.traits.lists.ListMember;
 import com.example.traits.lists.NumberListTrait;
 import com.example.traits.lists.StructureListTrait;
 import com.example.traits.maps.MapValue;
+import com.example.traits.maps.StringDocumentMapTrait;
 import com.example.traits.maps.StringStringMapTrait;
 import com.example.traits.maps.StringToStructMapTrait;
 import com.example.traits.mixins.ListMemberWithMixin;
@@ -115,6 +117,11 @@ public class LoadsFromModelTest {
                         MapUtils.of("getValues", ListUtils.of(
                                 ListMember.builder().a("first").b(1).c("other").build(),
                                 ListMember.builder().a("second").b(2).c("more").build()))),
+                Arguments.of("lists/document-list-trait.smithy", DocumentListTrait.class,
+                        MapUtils.of("getValues", ListUtils.of(
+                            ObjectNode.builder().withMember("a", "a").build().toNode(),
+                            ObjectNode.builder().withMember("b", "b").withMember("c", 1).build().toNode(),
+                            Node.from("string")))),
                 // Maps
                 Arguments.of("maps/string-string-map-trait.smithy", StringStringMapTrait.class,
                         MapUtils.of("getValues", MapUtils.of("a", "stuff",
@@ -123,6 +130,13 @@ public class LoadsFromModelTest {
                         MapUtils.of("getValues", MapUtils.of(
                                 "one", MapValue.builder().a("foo").b(2).build(),
                                 "two", MapValue.builder().a("bar").b(4).build()))),
+                Arguments.of("maps/string-to-document-map-trait.smithy", StringDocumentMapTrait.class,
+                        MapUtils.of("getValues", MapUtils.of(
+                                "a", ObjectNode.builder().withMember("a", "a").build().toNode(),
+                                "b", ObjectNode.builder().withMember("b", "b").withMember("c", 1).build().toNode(),
+                                "c", Node.from("stuff"),
+                                "d", Node.from(1)
+                        ))),
                 // Mixins
                 Arguments.of("mixins/struct-with-mixin-member.smithy", StructureListWithMixinMemberTrait.class,
                         MapUtils.of("getValues", ListUtils.of(
diff --git a/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/defaults/defaults.smithy b/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/defaults/defaults.smithy
index dbd2c1950..79cc9718b 100644
--- a/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/defaults/defaults.smithy
+++ b/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/defaults/defaults.smithy
@@ -5,5 +5,4 @@ namespace test.smithy.traitcodegen
 use test.smithy.traitcodegen.defaults#StructDefaults
 
 @StructDefaults
-structure myStruct {
-}
+structure myStruct {}
diff --git a/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/documents/document-trait.smithy b/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/documents/document-trait.smithy
index b75085405..bb5857276 100644
--- a/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/documents/document-trait.smithy
+++ b/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/documents/document-trait.smithy
@@ -4,9 +4,5 @@ namespace test.smithy.traitcodegen
 
 use test.smithy.traitcodegen.documents#DocumentTrait
 
-@DocumentTrait({
-    metadata: "woo"
-    more: "yay"
-})
-structure myStruct {
-}
+@DocumentTrait({ metadata: "woo", more: "yay" })
+structure myStruct {}
diff --git a/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/documents/struct-with-nested-document.smithy b/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/documents/struct-with-nested-document.smithy
index 375e3706c..ef3cdae5b 100644
--- a/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/documents/struct-with-nested-document.smithy
+++ b/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/documents/struct-with-nested-document.smithy
@@ -5,10 +5,6 @@ namespace test.smithy.traitcodegen
 use test.smithy.traitcodegen.documents#structWithNestedDocument
 
 @structWithNestedDocument(
-    doc: {
-        foo: "bar"
-        fizz: "buzz"
-    }
+    doc: { foo: "bar", fizz: "buzz" }
 )
-structure myStruct {
-}
+structure myStruct {}
diff --git a/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/enums/enum-trait.smithy b/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/enums/enum-trait.smithy
index b253f4ad3..03c97e7f2 100644
--- a/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/enums/enum-trait.smithy
+++ b/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/enums/enum-trait.smithy
@@ -5,5 +5,4 @@ namespace test.smithy.traitcodegen
 use test.smithy.traitcodegen.enums#StringEnum
 
 @StringEnum("yes")
-structure myStruct {
-}
+structure myStruct {}
diff --git a/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/enums/string-enum-compatibility.smithy b/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/enums/string-enum-compatibility.smithy
index 943878846..8724d1401 100644
--- a/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/enums/string-enum-compatibility.smithy
+++ b/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/enums/string-enum-compatibility.smithy
@@ -5,5 +5,4 @@ namespace test.smithy.traitcodegen
 use test.smithy.traitcodegen.enums#Suit
 
 @Suit("club")
-structure myStruct {
-}
+structure myStruct {}
diff --git a/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/errorfiles/number-trait-errors.smithy b/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/errorfiles/number-trait-errors.smithy
index fc6471fa9..826455e53 100644
--- a/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/errorfiles/number-trait-errors.smithy
+++ b/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/errorfiles/number-trait-errors.smithy
@@ -9,5 +9,3 @@ namespace test.smithy.traitcodegen.numbers
 @ShortTrait("bad")
 @DoubleTrait("bad")
 structure structWithInvalidStringInput {}
-
-
diff --git a/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/errorfiles/set-trait-errors.smithy b/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/errorfiles/set-trait-errors.smithy
index 33b33db40..31fca0719 100644
--- a/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/errorfiles/set-trait-errors.smithy
+++ b/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/errorfiles/set-trait-errors.smithy
@@ -4,9 +4,7 @@ namespace test.smithy.traitcodegen.uniqueitems
 
 // Doesnt have unique items. Expect failure
 @NumberSetTrait([1, 1, 3, 4])
-structure repeatedNumberValues {
-}
+structure repeatedNumberValues {}
 
 @StringSetTrait(["a", "a", "b"])
-structure repeatedStringValues {
-}
+structure repeatedStringValues {}
diff --git a/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/errorfiles/structure-trait-warns.smithy b/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/errorfiles/structure-trait-warns.smithy
index 8af8dcedf..44c6c4ffd 100644
--- a/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/errorfiles/structure-trait-warns.smithy
+++ b/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/errorfiles/structure-trait-warns.smithy
@@ -2,24 +2,15 @@ $version: "2.0"
 
 namespace test.smithy.traitcodegen.structures
 
-
 @structureTrait(
     fieldA: "first"
     fieldB: false
-    fieldC: {
-        fieldN: "nested"
-        fieldQ: true
-        fieldZ: "A"
-    }
+    fieldC: { fieldN: "nested", fieldQ: true, fieldZ: "A" }
     fieldD: ["a", "b", "c"]
-    fieldE: {
-        a: "one"
-        b: "two"
-    }
-    fieldF: 100.01,
-    fieldG: 100,
-    extraA: 100,
+    fieldE: { a: "one", b: "two" }
+    fieldF: 100.01
+    fieldG: 100
+    extraA: 100
     extraB: 200
 )
-structure myStruct {
-}
+structure myStruct {}
diff --git a/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/idref/idref-map.smithy b/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/idref/idref-map.smithy
index f73eb02e8..a784f169b 100644
--- a/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/idref/idref-map.smithy
+++ b/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/idref/idref-map.smithy
@@ -4,10 +4,7 @@ namespace test.smithy.traitcodegen
 
 use test.smithy.traitcodegen.idref#IdRefMap
 
-@IdRefMap(
-    a: IdRefTarget1
-    b: IdRefTarget2
-)
+@IdRefMap(a: IdRefTarget1, b: IdRefTarget2)
 structure myStruct {}
 
 string IdRefTarget1
diff --git a/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/idref/idref-struct-with-nested-refs.smithy b/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/idref/idref-struct-with-nested-refs.smithy
index cc3dc064d..c81da2e4e 100644
--- a/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/idref/idref-struct-with-nested-refs.smithy
+++ b/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/idref/idref-struct-with-nested-refs.smithy
@@ -5,14 +5,9 @@ namespace test.smithy.traitcodegen
 use test.smithy.traitcodegen.idref#IdRefStructWithNestedIds
 
 @IdRefStructWithNestedIds(
-    idRefHolder: {
-        id: IdRefTarget1
-    }
+    idRefHolder: { id: IdRefTarget1 }
     idList: [IdRefTarget1, IdRefTarget2]
-    idMap: {
-        a: IdRefTarget1
-        b: IdRefTarget2
-    }
+    idMap: { a: IdRefTarget1, b: IdRefTarget2 }
 )
 structure myStruct {}
 
diff --git a/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/lists/document-list-trait.smithy b/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/lists/document-list-trait.smithy
new file mode 100644
index 000000000..bf83c25b8
--- /dev/null
+++ b/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/lists/document-list-trait.smithy
@@ -0,0 +1,17 @@
+$version: "2.0"
+
+namespace test.smithy.traitcodegen
+
+use test.smithy.traitcodegen.lists#DocumentListTrait
+
+@DocumentListTrait([
+    {
+        a: "a"
+    }
+    {
+        b: "b"
+        c: 1
+    }
+    "string"
+])
+structure myStruct {}
diff --git a/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/lists/number-list-trait.smithy b/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/lists/number-list-trait.smithy
index cab37d227..4498a3426 100644
--- a/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/lists/number-list-trait.smithy
+++ b/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/lists/number-list-trait.smithy
@@ -5,5 +5,4 @@ namespace test.smithy.traitcodegen
 use test.smithy.traitcodegen.lists#NumberListTrait
 
 @NumberListTrait([1, 2, 3, 4, 5])
-structure myStruct {
-}
+structure myStruct {}
diff --git a/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/lists/string-list-trait.smithy b/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/lists/string-list-trait.smithy
index 8821df4df..15e073b8c 100644
--- a/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/lists/string-list-trait.smithy
+++ b/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/lists/string-list-trait.smithy
@@ -5,5 +5,4 @@ namespace test.smithy.traitcodegen
 use test.smithy.traitcodegen.lists#StringListTrait
 
 @StringListTrait(["a", "b", "c", "d"])
-structure myStruct {
-}
+structure myStruct {}
diff --git a/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/lists/struct-list-trait.smithy b/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/lists/struct-list-trait.smithy
index 528317b1f..be8bf22e1 100644
--- a/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/lists/struct-list-trait.smithy
+++ b/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/lists/struct-list-trait.smithy
@@ -9,11 +9,11 @@ use test.smithy.traitcodegen.lists#StructureListTrait
         a: "first"
         b: 1
         c: "other"
-    } {
+    }
+    {
         a: "second"
         b: 2
         c: "more"
     }
 ])
-structure myStruct {
-}
+structure myStruct {}
diff --git a/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/maps/string-string-map-trait.smithy b/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/maps/string-string-map-trait.smithy
index bf824192e..4eae963c8 100644
--- a/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/maps/string-string-map-trait.smithy
+++ b/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/maps/string-string-map-trait.smithy
@@ -4,10 +4,5 @@ namespace test.smithy.traitcodegen
 
 use test.smithy.traitcodegen.maps#StringStringMap
 
-@StringStringMap(
-    a: "stuff"
-    b: "other"
-    c: "more!"
-)
-structure myStruct {
-}
+@StringStringMap(a: "stuff", b: "other", c: "more!")
+structure myStruct {}
diff --git a/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/maps/string-to-document-map-trait.smithy b/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/maps/string-to-document-map-trait.smithy
new file mode 100644
index 000000000..bd4b0b920
--- /dev/null
+++ b/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/maps/string-to-document-map-trait.smithy
@@ -0,0 +1,13 @@
+$version: "2.0"
+
+namespace test.smithy.traitcodegen
+
+use test.smithy.traitcodegen.maps#StringDocumentMap
+
+@StringDocumentMap(
+    a: { a: "a" }
+    b: { b: "b", c: 1 }
+    c: "stuff"
+    d: 1
+)
+structure myStruct {}
diff --git a/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/maps/string-to-struct-map-trait.smithy b/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/maps/string-to-struct-map-trait.smithy
index 55d20f23f..b8b70af3f 100644
--- a/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/maps/string-to-struct-map-trait.smithy
+++ b/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/maps/string-to-struct-map-trait.smithy
@@ -5,14 +5,7 @@ namespace test.smithy.traitcodegen
 use test.smithy.traitcodegen.maps#StringToStructMap
 
 @StringToStructMap(
-    one: {
-        a: "foo"
-        b: 2
-    }
-    two: {
-        a: "bar"
-        b: 4
-    }
+    one: { a: "foo", b: 2 }
+    two: { a: "bar", b: 4 }
 )
-structure myStruct {
-}
+structure myStruct {}
diff --git a/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/mixins/struct-with-mixin-member.smithy b/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/mixins/struct-with-mixin-member.smithy
index 6c908fccc..d0f920152 100644
--- a/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/mixins/struct-with-mixin-member.smithy
+++ b/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/mixins/struct-with-mixin-member.smithy
@@ -10,7 +10,8 @@ use test.smithy.traitcodegen.mixins#structureListWithMixinMember
         b: 1
         c: "other"
         d: "mixed-in"
-    } {
+    }
+    {
         a: "second"
         b: 2
         c: "more"
diff --git a/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/mixins/struct-with-only-mixin-member.smithy b/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/mixins/struct-with-only-mixin-member.smithy
index dc738524f..800769185 100644
--- a/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/mixins/struct-with-only-mixin-member.smithy
+++ b/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/mixins/struct-with-only-mixin-member.smithy
@@ -4,8 +4,5 @@ namespace test.smithy.traitcodegen
 
 use test.smithy.traitcodegen.mixins#structWithMixin
 
-@structWithMixin(
-    d: "mixed-in"
-)
-structure myStruct {
-}
+@structWithMixin(d: "mixed-in")
+structure myStruct {}
diff --git a/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/names/snake-case-struct.smithy b/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/names/snake-case-struct.smithy
index 6f97ca27f..00fe3abce 100644
--- a/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/names/snake-case-struct.smithy
+++ b/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/names/snake-case-struct.smithy
@@ -4,8 +4,5 @@ namespace test.smithy.traitcodegen
 
 use test.smithy.traitcodegen.names#snake_case_structure
 
-@snake_case_structure(
-    snake_case_member: "stuff"
-)
-structure myStruct {
-}
+@snake_case_structure(snake_case_member: "stuff")
+structure myStruct {}
diff --git a/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/structures/struct-trait.smithy b/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/structures/struct-trait.smithy
index df16a7253..89e7ad3f1 100644
--- a/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/structures/struct-trait.smithy
+++ b/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/structures/struct-trait.smithy
@@ -7,18 +7,10 @@ use test.smithy.traitcodegen.structures#structureTrait
 @structureTrait(
     fieldA: "first"
     fieldB: false
-    fieldC: {
-        fieldN: "nested"
-        fieldQ: true
-        fieldZ: "A"
-    }
+    fieldC: { fieldN: "nested", fieldQ: true, fieldZ: "A" }
     fieldD: ["a", "b", "c"]
-    fieldE: {
-        a: "one"
-        b: "two"
-    }
-    fieldF: 100.01,
+    fieldE: { a: "one", b: "two" }
+    fieldF: 100.01
     fieldG: 100
 )
-structure myStruct {
-}
+structure myStruct {}
diff --git a/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/structures/struct-with-non-existent-collections.smithy b/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/structures/struct-with-non-existent-collections.smithy
index ab195d5d6..d050edbbe 100644
--- a/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/structures/struct-with-non-existent-collections.smithy
+++ b/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/structures/struct-with-non-existent-collections.smithy
@@ -7,11 +7,6 @@ use test.smithy.traitcodegen.structures#structureTrait
 @structureTrait(
     fieldA: "first"
     fieldB: false
-    fieldC: {
-        fieldN: "nested"
-        fieldQ: true
-        fieldZ: "A"
-    }
+    fieldC: { fieldN: "nested", fieldQ: true, fieldZ: "A" }
 )
-structure myStruct {
-}
+structure myStruct {}
diff --git a/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/uniqueitems/number-set-trait.smithy b/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/uniqueitems/number-set-trait.smithy
index 3dd069c07..167d38bb1 100644
--- a/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/uniqueitems/number-set-trait.smithy
+++ b/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/uniqueitems/number-set-trait.smithy
@@ -5,5 +5,4 @@ namespace test.smithy.traitcodegen
 use test.smithy.traitcodegen.uniqueitems#NumberSetTrait
 
 @NumberSetTrait([1, 2, 3, 4])
-structure myStruct {
-}
+structure myStruct {}
diff --git a/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/uniqueitems/string-set-trait.smithy b/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/uniqueitems/string-set-trait.smithy
index 8145ca6d3..57e885e04 100644
--- a/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/uniqueitems/string-set-trait.smithy
+++ b/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/uniqueitems/string-set-trait.smithy
@@ -5,5 +5,4 @@ namespace test.smithy.traitcodegen
 use test.smithy.traitcodegen.uniqueitems#StringSetTrait
 
 @StringSetTrait(["a", "b", "c", "d"])
-structure myStruct {
-}
+structure myStruct {}
diff --git a/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/uniqueitems/struct-set-trait.smithy b/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/uniqueitems/struct-set-trait.smithy
index 0e0c14b2e..0eee8fe05 100644
--- a/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/uniqueitems/struct-set-trait.smithy
+++ b/smithy-trait-codegen/src/it/resources/software/amazon/smithy/traitcodegen/test/uniqueitems/struct-set-trait.smithy
@@ -9,11 +9,11 @@ use test.smithy.traitcodegen.uniqueitems#StructureSetTrait
         a: "first"
         b: 1
         c: "other"
-    } {
+    }
+    {
         a: "second"
         b: 2
         c: "more"
     }
 ])
-structure myStruct {
-}
+structure myStruct {}
diff --git a/smithy-trait-codegen/src/test/java/software/amazon/smithy/traitcodegen/TraitCodegenPluginTest.java b/smithy-trait-codegen/src/test/java/software/amazon/smithy/traitcodegen/TraitCodegenPluginTest.java
index 916faabb0..1d3bbcc00 100644
--- a/smithy-trait-codegen/src/test/java/software/amazon/smithy/traitcodegen/TraitCodegenPluginTest.java
+++ b/smithy-trait-codegen/src/test/java/software/amazon/smithy/traitcodegen/TraitCodegenPluginTest.java
@@ -28,7 +28,7 @@ import software.amazon.smithy.model.node.ObjectNode;
 
 
 public class TraitCodegenPluginTest {
-    private static final int EXPECTED_NUMBER_OF_FILES = 56;
+    private static final int EXPECTED_NUMBER_OF_FILES = 58;
 
     private MockManifest manifest;
     private Model model;
diff --git a/smithy-trait-codegen/src/test/resources/META-INF/smithy/defaults/defaults.smithy b/smithy-trait-codegen/src/test/resources/META-INF/smithy/defaults/defaults.smithy
index ff89a1e17..8f61ed31c 100644
--- a/smithy-trait-codegen/src/test/resources/META-INF/smithy/defaults/defaults.smithy
+++ b/smithy-trait-codegen/src/test/resources/META-INF/smithy/defaults/defaults.smithy
@@ -6,28 +6,40 @@ namespace test.smithy.traitcodegen.defaults
 structure StructDefaults {
     @default([])
     defaultList: StringList
+
     @default({})
     defaultMap: StringMap
+
     @default(true)
     defaultBoolean: Boolean
+
     @default("default")
     defaultString: String
+
     @default(1)
     defaultByte: Byte
+
     @default(1)
     defaultShort: Short
+
     @default(1)
     defaultInt: Integer
+
     @default(1)
     defaultLong: Long
+
     @default(2.2)
     defaultFloat: Float
+
     @default(1.1)
     defaultDouble: Double
+
     @default(100)
     defaultBigInt: BigInteger
+
     @default(100.01)
     defaultBigDecimal: BigDecimal
+
     @default("1985-04-12T23:20:50.52Z")
     defaultTimestamp: Timestamp
 }
diff --git a/smithy-trait-codegen/src/test/resources/META-INF/smithy/enums/int-enum-trait.smithy b/smithy-trait-codegen/src/test/resources/META-INF/smithy/enums/int-enum-trait.smithy
index 63793dc3b..e6f34cd93 100644
--- a/smithy-trait-codegen/src/test/resources/META-INF/smithy/enums/int-enum-trait.smithy
+++ b/smithy-trait-codegen/src/test/resources/META-INF/smithy/enums/int-enum-trait.smithy
@@ -10,4 +10,3 @@ intEnum IntEnum {
     /// Negative response
     NO = 2
 }
-
diff --git a/smithy-trait-codegen/src/test/resources/META-INF/smithy/enums/string-enum-compatibility.smithy b/smithy-trait-codegen/src/test/resources/META-INF/smithy/enums/string-enum-compatibility.smithy
index 46ed2ec2e..c14018ec2 100644
--- a/smithy-trait-codegen/src/test/resources/META-INF/smithy/enums/string-enum-compatibility.smithy
+++ b/smithy-trait-codegen/src/test/resources/META-INF/smithy/enums/string-enum-compatibility.smithy
@@ -7,22 +7,21 @@ namespace test.smithy.traitcodegen.enums
 // ========================
 // The following trait check that the plugin can generate traits from a
 // legacy string enum (i.e. a string with the @enum trait applied).
-
 @enum([
     {
-        name: "DIAMOND",
+        name: "DIAMOND"
         value: "diamond"
-    },
+    }
     {
-        name: "CLUB",
+        name: "CLUB"
         value: "club"
-    },
+    }
     {
-        name: "HEART",
+        name: "HEART"
         value: "heart"
-    },
+    }
     {
-        name: "SPADE",
+        name: "SPADE"
         value: "spade"
     }
 ])
diff --git a/smithy-trait-codegen/src/test/resources/META-INF/smithy/idref/idref-list.smithy b/smithy-trait-codegen/src/test/resources/META-INF/smithy/idref/idref-list.smithy
index 9a8cdf699..20234d9fb 100644
--- a/smithy-trait-codegen/src/test/resources/META-INF/smithy/idref/idref-list.smithy
+++ b/smithy-trait-codegen/src/test/resources/META-INF/smithy/idref/idref-list.smithy
@@ -4,7 +4,6 @@ namespace test.smithy.traitcodegen.idref
 
 // The following trait check to make sure that Strings are converted to ShapeIds
 // when an @IdRef trait is added to a string
-
 @trait
 list IdRefList {
     member: IdRefListmember
diff --git a/smithy-trait-codegen/src/test/resources/META-INF/smithy/idref/idref-string.smithy b/smithy-trait-codegen/src/test/resources/META-INF/smithy/idref/idref-string.smithy
index f660635ca..dafacf953 100644
--- a/smithy-trait-codegen/src/test/resources/META-INF/smithy/idref/idref-string.smithy
+++ b/smithy-trait-codegen/src/test/resources/META-INF/smithy/idref/idref-string.smithy
@@ -4,7 +4,6 @@ namespace test.smithy.traitcodegen.idref
 
 // The following trait check to make sure that Strings are converted to ShapeIds
 // when an @IdRef trait is added to a string
-
 @trait
 @idRef
 string IdRefString
diff --git a/smithy-trait-codegen/src/test/resources/META-INF/smithy/lists/document-list-trait.smithy b/smithy-trait-codegen/src/test/resources/META-INF/smithy/lists/document-list-trait.smithy
new file mode 100644
index 000000000..b606dba7b
--- /dev/null
+++ b/smithy-trait-codegen/src/test/resources/META-INF/smithy/lists/document-list-trait.smithy
@@ -0,0 +1,8 @@
+$version: "2.0"
+
+namespace test.smithy.traitcodegen.lists
+
+@trait
+list DocumentListTrait {
+    member: Document
+}
diff --git a/smithy-trait-codegen/src/test/resources/META-INF/smithy/manifest b/smithy-trait-codegen/src/test/resources/META-INF/smithy/manifest
index e1e57d9ef..8e659e2ba 100644
--- a/smithy-trait-codegen/src/test/resources/META-INF/smithy/manifest
+++ b/smithy-trait-codegen/src/test/resources/META-INF/smithy/manifest
@@ -13,8 +13,10 @@ ignored.smithy
 lists/number-list-trait.smithy
 lists/string-list-trait.smithy
 lists/struct-list-trait.smithy
+lists/document-list-trait.smithy
 maps/string-string-map-trait.smithy
 maps/string-to-struct-map-trait.smithy
+maps/string-to-document-map-trait.smithy
 mixins/struct-with-mixin-member.smithy
 mixins/struct-with-only-mixin-member.smithy
 names/snake-case-structure.smithy
diff --git a/smithy-trait-codegen/src/test/resources/META-INF/smithy/maps/string-to-document-map-trait.smithy b/smithy-trait-codegen/src/test/resources/META-INF/smithy/maps/string-to-document-map-trait.smithy
new file mode 100644
index 000000000..867f9a95a
--- /dev/null
+++ b/smithy-trait-codegen/src/test/resources/META-INF/smithy/maps/string-to-document-map-trait.smithy
@@ -0,0 +1,9 @@
+$version: "2.0"
+
+namespace test.smithy.traitcodegen.maps
+
+@trait
+map StringDocumentMap {
+    key: String
+    value: Document
+}
diff --git a/smithy-trait-codegen/src/test/resources/META-INF/smithy/mixins/struct-with-mixin-member.smithy b/smithy-trait-codegen/src/test/resources/META-INF/smithy/mixins/struct-with-mixin-member.smithy
index 7ddf89b46..f4166cef1 100644
--- a/smithy-trait-codegen/src/test/resources/META-INF/smithy/mixins/struct-with-mixin-member.smithy
+++ b/smithy-trait-codegen/src/test/resources/META-INF/smithy/mixins/struct-with-mixin-member.smithy
@@ -4,7 +4,6 @@ namespace test.smithy.traitcodegen.mixins
 
 // The following trait checks that mixins are correctly flattened by
 // the trait codegen plugin
-
 @trait
 list structureListWithMixinMember {
     member: listMemberWithMixin
diff --git a/smithy-trait-codegen/src/test/resources/META-INF/smithy/mixins/struct-with-only-mixin-member.smithy b/smithy-trait-codegen/src/test/resources/META-INF/smithy/mixins/struct-with-only-mixin-member.smithy
index bb41257e2..338596b53 100644
--- a/smithy-trait-codegen/src/test/resources/META-INF/smithy/mixins/struct-with-only-mixin-member.smithy
+++ b/smithy-trait-codegen/src/test/resources/META-INF/smithy/mixins/struct-with-only-mixin-member.smithy
@@ -4,7 +4,6 @@ namespace test.smithy.traitcodegen.mixins
 
 // The following trait checks that mixins are correctly flattened by
 // the trait codegen plugin
-
 @trait
 structure structWithMixin with [extras] {}
 
diff --git a/smithy-trait-codegen/src/test/resources/META-INF/smithy/names/snake-case-structure.smithy b/smithy-trait-codegen/src/test/resources/META-INF/smithy/names/snake-case-structure.smithy
index ad2c853fa..f3a6c86ed 100644
--- a/smithy-trait-codegen/src/test/resources/META-INF/smithy/names/snake-case-structure.smithy
+++ b/smithy-trait-codegen/src/test/resources/META-INF/smithy/names/snake-case-structure.smithy
@@ -7,7 +7,6 @@ namespace test.smithy.traitcodegen.names
 // ===================
 // The following traits check that non-java-style names are
 // correctly changed into a useable Java-compatible name
-
 /// Snake cased
 @trait
 structure snake_case_structure {
diff --git a/smithy-trait-codegen/src/test/resources/META-INF/smithy/names/trait-with-name-conflict.smithy b/smithy-trait-codegen/src/test/resources/META-INF/smithy/names/trait-with-name-conflict.smithy
index 0ed2f02df..457edf921 100644
--- a/smithy-trait-codegen/src/test/resources/META-INF/smithy/names/trait-with-name-conflict.smithy
+++ b/smithy-trait-codegen/src/test/resources/META-INF/smithy/names/trait-with-name-conflict.smithy
@@ -4,7 +4,6 @@ namespace test.smithy.traitcodegen.names
 
 // The following traits check to make sure that name conflicts between shapes and
 // java classes used in the generated codegen code are correctly handled
-
 /// Conflicts with AbstractTrait base class
 @trait
 structure Abstract {}
diff --git a/smithy-trait-codegen/src/test/resources/META-INF/smithy/nested/nested-namespace.smithy b/smithy-trait-codegen/src/test/resources/META-INF/smithy/nested/nested-namespace.smithy
index 0dacd2eea..0afb579bc 100644
--- a/smithy-trait-codegen/src/test/resources/META-INF/smithy/nested/nested-namespace.smithy
+++ b/smithy-trait-codegen/src/test/resources/META-INF/smithy/nested/nested-namespace.smithy
@@ -7,7 +7,6 @@ namespace test.smithy.traitcodegen.nested
 // =======================
 // The following traits check to make sure that traits within a nested smithy
 // namespace are mapped to a nested java namespace
-
 /// A trait that should be generated in a nested namespace
 @trait
 structure nestedNamespaceTrait {
diff --git a/smithy-trait-codegen/src/test/resources/META-INF/smithy/structures/structure-trait.smithy b/smithy-trait-codegen/src/test/resources/META-INF/smithy/structures/structure-trait.smithy
index 9ff4944b6..e56dbb686 100644
--- a/smithy-trait-codegen/src/test/resources/META-INF/smithy/structures/structure-trait.smithy
+++ b/smithy-trait-codegen/src/test/resources/META-INF/smithy/structures/structure-trait.smithy
@@ -60,6 +60,7 @@ structure NestedA {
 enum NestedB {
     /// An A!
     A
+
     /// A B!
     B
 }
@@ -68,6 +69,7 @@ enum NestedB {
 intEnum NestedC {
     /// An A!
     A = 1
+
     /// A B!
     B = 2
 }
diff --git a/smithy-trait-codegen/src/test/resources/META-INF/smithy/timestamps/struct-with-nested-timestamps.smithy b/smithy-trait-codegen/src/test/resources/META-INF/smithy/timestamps/struct-with-nested-timestamps.smithy
index 394427bf6..960e4d8d8 100644
--- a/smithy-trait-codegen/src/test/resources/META-INF/smithy/timestamps/struct-with-nested-timestamps.smithy
+++ b/smithy-trait-codegen/src/test/resources/META-INF/smithy/timestamps/struct-with-nested-timestamps.smithy
@@ -6,10 +6,13 @@ namespace test.smithy.traitcodegen.timestamps
 structure structWithNestedTimestamps {
     @required
     baseTime: basicTimestamp
+
     @required
     dateTime: dateTimeTimestamp
+
     @required
     httpDate: httpDateTimestamp
+
     @required
     epochSeconds: epochSecondsTimestamp
 }