diff --git a/smithy-aws-cloudformation/src/main/java/software/amazon/smithy/aws/cloudformation/schema/fromsmithy/mappers/AdditionalPropertiesMapper.java b/smithy-aws-cloudformation/src/main/java/software/amazon/smithy/aws/cloudformation/schema/fromsmithy/mappers/AdditionalPropertiesMapper.java
new file mode 100644
index 00000000000..c4df27b6f8c
--- /dev/null
+++ b/smithy-aws-cloudformation/src/main/java/software/amazon/smithy/aws/cloudformation/schema/fromsmithy/mappers/AdditionalPropertiesMapper.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file is distributed
+ * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package software.amazon.smithy.aws.cloudformation.schema.fromsmithy.mappers;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Optional;
+import software.amazon.smithy.aws.cloudformation.schema.fromsmithy.CfnMapper;
+import software.amazon.smithy.aws.cloudformation.schema.fromsmithy.Context;
+import software.amazon.smithy.aws.cloudformation.schema.model.ResourceSchema;
+import software.amazon.smithy.model.node.Node;
+import software.amazon.smithy.model.node.ObjectNode;
+import software.amazon.smithy.model.node.StringNode;
+
+/**
+ * CloudFormation issues a warning in its build tooling every time it detects
+ * an "object" type in the converted JSON Schema's definitions that doesn't set
+ * "additionalProperties" to "false". This mapper sets that to reduce the
+ * warnings customers receive when developing resources from automatically
+ * generated resource schemas.
+ *
+ * @see Warning in CFN CLI
+ */
+final class AdditionalPropertiesMapper implements CfnMapper {
+
+ @Override
+ public byte getOrder() {
+ // This is a desired behavior from CFN, so set it near the end
+ // while still having room for other overrides if necessary.
+ return 124;
+ }
+
+ @Override
+ public ObjectNode updateNode(Context context, ResourceSchema resourceSchema, ObjectNode node) {
+ Optional definitionsOptional = node.getObjectMember("definitions");
+
+ // This replaces every entry in the "definitions" map and uses a
+ // LinkedHashMap so that order is maintained, as entries will have
+ // been sorted before we get to this mapper.
+ Map updatedNodes = new LinkedHashMap<>();
+ if (definitionsOptional.isPresent()) {
+ for (Map.Entry entry : definitionsOptional.get().getMembers().entrySet()) {
+ ObjectNode valueNode = entry.getValue().expectObjectNode();
+
+ if (valueNode.expectStringMember("type").getValue().equals("object")) {
+ valueNode = valueNode.withMember("additionalProperties", false);
+ }
+
+ updatedNodes.put(entry.getKey(), valueNode);
+ }
+ node = node.withMember("definitions", Node.objectNode(updatedNodes));
+ }
+ return node;
+ }
+}
diff --git a/smithy-aws-cloudformation/src/main/java/software/amazon/smithy/aws/cloudformation/schema/fromsmithy/mappers/CoreExtension.java b/smithy-aws-cloudformation/src/main/java/software/amazon/smithy/aws/cloudformation/schema/fromsmithy/mappers/CoreExtension.java
index 4bc437ff22f..99417647671 100644
--- a/smithy-aws-cloudformation/src/main/java/software/amazon/smithy/aws/cloudformation/schema/fromsmithy/mappers/CoreExtension.java
+++ b/smithy-aws-cloudformation/src/main/java/software/amazon/smithy/aws/cloudformation/schema/fromsmithy/mappers/CoreExtension.java
@@ -27,6 +27,7 @@ public final class CoreExtension implements Smithy2CfnExtension {
@Override
public List getCfnMappers() {
return ListUtils.of(
+ new AdditionalPropertiesMapper(),
new DeprecatedMapper(),
new DocumentationMapper(),
new IdentifierMapper(),
diff --git a/smithy-aws-cloudformation/src/test/java/software/amazon/smithy/aws/cloudformation/schema/fromsmithy/mappers/AdditionalPropertiesMapperTest.java b/smithy-aws-cloudformation/src/test/java/software/amazon/smithy/aws/cloudformation/schema/fromsmithy/mappers/AdditionalPropertiesMapperTest.java
new file mode 100644
index 00000000000..f3127b2d5c2
--- /dev/null
+++ b/smithy-aws-cloudformation/src/test/java/software/amazon/smithy/aws/cloudformation/schema/fromsmithy/mappers/AdditionalPropertiesMapperTest.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file is distributed
+ * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package software.amazon.smithy.aws.cloudformation.schema.fromsmithy.mappers;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+
+import org.junit.jupiter.api.Test;
+import software.amazon.smithy.aws.cloudformation.schema.CfnConfig;
+import software.amazon.smithy.aws.cloudformation.schema.fromsmithy.CfnConverter;
+import software.amazon.smithy.model.Model;
+import software.amazon.smithy.model.node.ObjectNode;
+import software.amazon.smithy.model.shapes.ShapeId;
+
+public class AdditionalPropertiesMapperTest {
+ @Test
+ public void setsAdditionalPropertiesFalse() {
+ Model model = Model.assembler()
+ .addImport(JsonAddTest.class.getResource("simple.smithy"))
+ .discoverModels()
+ .assemble()
+ .unwrap();
+
+ CfnConfig config = new CfnConfig();
+ config.setOrganizationName("Smithy");
+ config.setService(ShapeId.from("smithy.example#TestService"));
+
+ ObjectNode resourceNode = CfnConverter.create()
+ .config(config)
+ .convertToNodes(model)
+ .get("Smithy::TestService::FooResource");
+
+ assertFalse(resourceNode.expectObjectMember("definitions")
+ .expectObjectMember("ComplexProperty")
+ .expectBooleanMember("additionalProperties")
+ .getValue());
+ }
+
+}
diff --git a/smithy-aws-cloudformation/src/test/resources/software/amazon/smithy/aws/cloudformation/schema/fromsmithy/disable-caps-fooresource.cfn.json b/smithy-aws-cloudformation/src/test/resources/software/amazon/smithy/aws/cloudformation/schema/fromsmithy/disable-caps-fooresource.cfn.json
index 3d661348e75..a94941b28b1 100644
--- a/smithy-aws-cloudformation/src/test/resources/software/amazon/smithy/aws/cloudformation/schema/fromsmithy/disable-caps-fooresource.cfn.json
+++ b/smithy-aws-cloudformation/src/test/resources/software/amazon/smithy/aws/cloudformation/schema/fromsmithy/disable-caps-fooresource.cfn.json
@@ -11,7 +11,8 @@
"property": {
"type": "string"
}
- }
+ },
+ "additionalProperties": false
},
"FooMap": {
"type": "object",
@@ -19,7 +20,8 @@
".+": {
"type": "string"
}
- }
+ },
+ "additionalProperties": false
}
},
"properties": {
diff --git a/smithy-aws-cloudformation/src/test/resources/software/amazon/smithy/aws/cloudformation/schema/fromsmithy/integ/complex-resource.cfn.json b/smithy-aws-cloudformation/src/test/resources/software/amazon/smithy/aws/cloudformation/schema/fromsmithy/integ/complex-resource.cfn.json
index 39defd2512b..abfaaf1b0a0 100644
--- a/smithy-aws-cloudformation/src/test/resources/software/amazon/smithy/aws/cloudformation/schema/fromsmithy/integ/complex-resource.cfn.json
+++ b/smithy-aws-cloudformation/src/test/resources/software/amazon/smithy/aws/cloudformation/schema/fromsmithy/integ/complex-resource.cfn.json
@@ -8,7 +8,8 @@
".+": {
"type": "string"
}
- }
+ },
+ "additionalProperties": false
},
"ComplexProperty": {
"type": "object",
@@ -16,7 +17,8 @@
"AnotherProperty": {
"type": "string"
}
- }
+ },
+ "additionalProperties": false
}
},
"properties": {
diff --git a/smithy-aws-cloudformation/src/test/resources/software/amazon/smithy/aws/cloudformation/schema/fromsmithy/integ/queue-example.cfn.json b/smithy-aws-cloudformation/src/test/resources/software/amazon/smithy/aws/cloudformation/schema/fromsmithy/integ/queue-example.cfn.json
index ec253208d93..6abe986793d 100644
--- a/smithy-aws-cloudformation/src/test/resources/software/amazon/smithy/aws/cloudformation/schema/fromsmithy/integ/queue-example.cfn.json
+++ b/smithy-aws-cloudformation/src/test/resources/software/amazon/smithy/aws/cloudformation/schema/fromsmithy/integ/queue-example.cfn.json
@@ -11,7 +11,8 @@
"DeadLetterTargetArn": {
"type": "string"
}
- }
+ },
+ "additionalProperties": false
},
"TagMap": {
"type": "object",
@@ -19,7 +20,8 @@
".+": {
"type": "string"
}
- }
+ },
+ "additionalProperties": false
}
},
"properties": {
diff --git a/smithy-aws-cloudformation/src/test/resources/software/amazon/smithy/aws/cloudformation/schema/fromsmithy/simple-service-aws.cfn.json b/smithy-aws-cloudformation/src/test/resources/software/amazon/smithy/aws/cloudformation/schema/fromsmithy/simple-service-aws.cfn.json
index 26a9ac545fb..9e023fec7f0 100644
--- a/smithy-aws-cloudformation/src/test/resources/software/amazon/smithy/aws/cloudformation/schema/fromsmithy/simple-service-aws.cfn.json
+++ b/smithy-aws-cloudformation/src/test/resources/software/amazon/smithy/aws/cloudformation/schema/fromsmithy/simple-service-aws.cfn.json
@@ -13,7 +13,8 @@
"Another": {
"type": "string"
}
- }
+ },
+ "additionalProperties": false
}
},
"properties": {
diff --git a/smithy-aws-cloudformation/src/test/resources/software/amazon/smithy/aws/cloudformation/schema/fromsmithy/smithy-testservice-fooresource.cfn.json b/smithy-aws-cloudformation/src/test/resources/software/amazon/smithy/aws/cloudformation/schema/fromsmithy/smithy-testservice-fooresource.cfn.json
index 41d6d0a0a75..7f88488a735 100644
--- a/smithy-aws-cloudformation/src/test/resources/software/amazon/smithy/aws/cloudformation/schema/fromsmithy/smithy-testservice-fooresource.cfn.json
+++ b/smithy-aws-cloudformation/src/test/resources/software/amazon/smithy/aws/cloudformation/schema/fromsmithy/smithy-testservice-fooresource.cfn.json
@@ -11,7 +11,8 @@
"Another": {
"type": "string"
}
- }
+ },
+ "additionalProperties": false
},
"FooMap": {
"type": "object",
@@ -19,7 +20,8 @@
".+": {
"type": "string"
}
- }
+ },
+ "additionalProperties": false
}
},
"properties": {