From 243e15773fa3943662b5106b5c2f6b120d7e0057 Mon Sep 17 00:00:00 2001
From: kstich <kevin@kstich.com>
Date: Wed, 16 Dec 2020 09:47:58 -0800
Subject: [PATCH] Fix an issue loading jsonAdd map from config

---
 .../generating-cloudformation-resources.rst   | 12 +++---
 .../aws/cloudformation/schema/CfnConfig.java  | 14 +++++++
 .../schema/fromsmithy/CfnConfigTest.java      | 37 +++++++++++++++++++
 3 files changed, 58 insertions(+), 5 deletions(-)

diff --git a/docs/source/1.0/guides/generating-cloudformation-resources.rst b/docs/source/1.0/guides/generating-cloudformation-resources.rst
index 034ca0c3830..e1af22d8979 100644
--- a/docs/source/1.0/guides/generating-cloudformation-resources.rst
+++ b/docs/source/1.0/guides/generating-cloudformation-resources.rst
@@ -275,11 +275,13 @@ jsonAdd (``Map<String, Map<String, Node>>``)
                     "service": "smithy.example#Queues",
                     "organizationName": "Smithy",
                     "jsonAdd": {
-                        "/info/title": "Replaced title value",
-                        "/info/nested/foo": {
-                            "hi": "Adding this object created intermediate objects too!"
-                        },
-                        "/info/nested/foo/baz": true
+                        "smithy.example#Queue": {
+                            "/info/title": "Replaced title value",
+                            "/info/nested/foo": {
+                                "hi": "Adding this object created intermediate objects too!"
+                            },
+                            "/info/nested/foo/baz": true
+                        }
                     }
                 }
             }
diff --git a/smithy-aws-cloudformation/src/main/java/software/amazon/smithy/aws/cloudformation/schema/CfnConfig.java b/smithy-aws-cloudformation/src/main/java/software/amazon/smithy/aws/cloudformation/schema/CfnConfig.java
index b65fb61c36c..173d8374ea8 100644
--- a/smithy-aws-cloudformation/src/main/java/software/amazon/smithy/aws/cloudformation/schema/CfnConfig.java
+++ b/smithy-aws-cloudformation/src/main/java/software/amazon/smithy/aws/cloudformation/schema/CfnConfig.java
@@ -16,6 +16,7 @@
 package software.amazon.smithy.aws.cloudformation.schema;
 
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
@@ -24,6 +25,7 @@
 import software.amazon.smithy.model.node.Node;
 import software.amazon.smithy.model.node.NodeMapper;
 import software.amazon.smithy.model.node.ObjectNode;
+import software.amazon.smithy.model.node.StringNode;
 import software.amazon.smithy.model.shapes.ShapeId;
 import software.amazon.smithy.utils.ListUtils;
 
@@ -304,6 +306,18 @@ public static CfnConfig fromNode(Node settings) {
         CfnConfig config = new CfnConfig();
         mapper.deserializeInto(node, config);
 
+        // Load a ShapeId map for the jsonAdd setting.
+        node.getObjectMember("jsonAdd").ifPresent(jsonAddNode -> {
+            Map<ShapeId, Map<String, Node>> jsonAddMap = new HashMap<>();
+
+            for (Map.Entry<StringNode, Node> jsonAddMember : jsonAddNode.getMembers().entrySet()) {
+                jsonAddMap.put(ShapeId.from(jsonAddMember.getKey().getValue()),
+                        jsonAddMember.getValue().expectObjectNode().getStringMap());
+            }
+
+            config.setJsonAdd(jsonAddMap);
+        });
+
         // Add all properties to "extensions" to make them accessible
         // in plugins.
         for (Map.Entry<String, Node> entry : node.getStringMap().entrySet()) {
diff --git a/smithy-aws-cloudformation/src/test/java/software/amazon/smithy/aws/cloudformation/schema/fromsmithy/CfnConfigTest.java b/smithy-aws-cloudformation/src/test/java/software/amazon/smithy/aws/cloudformation/schema/fromsmithy/CfnConfigTest.java
index 06bcdec4af8..4c8068997a4 100644
--- a/smithy-aws-cloudformation/src/test/java/software/amazon/smithy/aws/cloudformation/schema/fromsmithy/CfnConfigTest.java
+++ b/smithy-aws-cloudformation/src/test/java/software/amazon/smithy/aws/cloudformation/schema/fromsmithy/CfnConfigTest.java
@@ -19,10 +19,15 @@
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
+import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 import software.amazon.smithy.aws.cloudformation.schema.CfnConfig;
 import software.amazon.smithy.aws.cloudformation.schema.CfnException;
 import software.amazon.smithy.jsonschema.JsonSchemaConfig;
+import software.amazon.smithy.model.Model;
+import software.amazon.smithy.model.node.Node;
+import software.amazon.smithy.model.node.NodePointer;
+import software.amazon.smithy.model.node.ObjectNode;
 
 public class CfnConfigTest {
     @Test
@@ -57,4 +62,36 @@ public void throwsOnDifferentUnionStrategy() {
         assertThrows(CfnException.class, () -> config.setUnionStrategy(JsonSchemaConfig.UnionStrategy.OBJECT));
         assertThrows(CfnException.class, () -> config.setUnionStrategy(JsonSchemaConfig.UnionStrategy.STRUCTURE));
     }
+
+    @Test
+    public void handlesFromNode() {
+        Model model = Model.assembler()
+                .addImport(CfnConfigTest.class.getResource("mappers/simple.smithy"))
+                .discoverModels()
+                .assemble()
+                .unwrap();
+
+        ObjectNode addNode = Node.objectNodeBuilder()
+                .withMember("/arbitrary/foo", "whoa")
+                .build();
+
+        ObjectNode configNode = Node.objectNodeBuilder()
+                .withMember("organizationName", "Smithy")
+                .withMember("service", "smithy.example#TestService")
+                .withMember("jsonAdd", Node.objectNodeBuilder()
+                        .withMember("smithy.example#FooResource", addNode)
+                        .build())
+                .build();
+
+        CfnConfig config = CfnConfig.fromNode(configNode);
+
+        ObjectNode resourceNode = CfnConverter.create()
+                .config(config)
+                .convertToNodes(model)
+                .get("Smithy::TestService::FooResource");
+
+        String arbitraryFoo = NodePointer.parse("/arbitrary/foo").getValue(resourceNode).expectStringNode().getValue();
+
+        Assertions.assertEquals("whoa", arbitraryFoo);
+    }
 }