Skip to content

Commit 11e8f2e

Browse files
feat(codegen): reject null in non-sparse collections
This updates list parsing for SSDKs to throw an error whenever a null value shows up in a list or set that isn't meant to be sparse. Clients remain tolerant of these nulls to preserve compatibility with services that are not so strict.
1 parent 1159680 commit 11e8f2e

File tree

2 files changed

+13
-6
lines changed

2 files changed

+13
-6
lines changed

codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/AwsProtocolUtils.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -334,10 +334,7 @@ private static boolean filterMalformedRequestTests(
334334
if (testCase.getId().startsWith("RestJsonMalformedSet")) {
335335
return true;
336336
}
337-
//TODO: we don't do any list validation
338-
if (testCase.getId().startsWith("RestJsonBodyMalformedList")) {
339-
return true;
340-
}
337+
341338
//TODO: we don't validate map values
342339
if (testCase.getId().equals("RestJsonBodyMalformedMapNullValue")) {
343340
return true;

codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/JsonShapeDeserVisitor.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import software.amazon.smithy.model.traits.SparseTrait;
3333
import software.amazon.smithy.model.traits.TimestampFormatTrait.Format;
3434
import software.amazon.smithy.typescript.codegen.CodegenUtils;
35+
import software.amazon.smithy.typescript.codegen.TypeScriptSettings.ArtifactType;
3536
import software.amazon.smithy.typescript.codegen.TypeScriptWriter;
3637
import software.amazon.smithy.typescript.codegen.integration.DocumentMemberDeserVisitor;
3738
import software.amazon.smithy.typescript.codegen.integration.DocumentShapeDeserVisitor;
@@ -62,16 +63,25 @@ private DocumentMemberDeserVisitor getMemberVisitor(MemberShape memberShape, Str
6263
protected void deserializeCollection(GenerationContext context, CollectionShape shape) {
6364
TypeScriptWriter writer = context.getWriter();
6465
Shape target = context.getModel().expectShape(shape.getMember().getTarget());
66+
ArtifactType artifactType = context.getSettings().getArtifactType();
6567

6668
// Filter out null entries if we don't have the sparse trait.
6769
String potentialFilter = "";
68-
if (!shape.hasTrait(SparseTrait.ID)) {
70+
if (!shape.hasTrait(SparseTrait.ID) && !artifactType.equals(ArtifactType.SSDK)) {
6971
potentialFilter = ".filter((e: any) => e != null)";
7072
}
7173

7274
writer.openBlock("return (output || [])$L.map((entry: any) => {", "});", potentialFilter, () -> {
7375
// Short circuit null values from serialization.
74-
writer.write("if (entry === null) { return null as any; }");
76+
writer.openBlock("if (entry === null) {", "}", () -> {
77+
// In the SSDK we want to be very strict about not accepting nulls in non-sparse lists.
78+
if (!shape.hasTrait(SparseTrait.ID) && artifactType.equals(ArtifactType.SSDK)) {
79+
writer.write("throw new TypeError('All elements of the non-sparse list $S must be non-null.');",
80+
shape.getId());
81+
} else {
82+
writer.write("return null as any;");
83+
}
84+
});
7585

7686
// Dispatch to the output value provider for any additional handling.
7787
writer.write("return $L$L;",

0 commit comments

Comments
 (0)