diff --git a/java/resource-overrides/pom.xml b/java/resource-overrides/pom.xml
index 80704781a9..5c052bc920 100644
--- a/java/resource-overrides/pom.xml
+++ b/java/resource-overrides/pom.xml
@@ -85,6 +85,21 @@
28.1-jre
+
+
+ junit
+ junit
+ 4.12
+ test
+
+
+
+ org.skyscreamer
+ jsonassert
+ 1.5.0
+ test
+
+
diff --git a/java/resource-overrides/src/main/java/software/amazon/awscdk/examples/ResourceOverridesStack.java b/java/resource-overrides/src/main/java/software/amazon/awscdk/examples/ResourceOverridesStack.java
index cb61da1946..42dd13f7f8 100644
--- a/java/resource-overrides/src/main/java/software/amazon/awscdk/examples/ResourceOverridesStack.java
+++ b/java/resource-overrides/src/main/java/software/amazon/awscdk/examples/ResourceOverridesStack.java
@@ -114,6 +114,7 @@ public ResourceOverridesStack(final Construct parent, final String name) {
// The default child resource is called `Resource`, but secondary resources, such as
// an LaunchConfig, InstanceRole will have a different ID.
// See https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_core.ConstructNode.html#defaultchild
+ // You can see all the resources under given construct by running `cdk synth` and looking for `aws:cdk:path`
//
CfnLaunchConfiguration launchConfiguration = (CfnLaunchConfiguration) asg.getNode().findChild("LaunchConfig");
launchConfiguration.addPropertyOverride("Foo.Bar", "Hello");
diff --git a/java/resource-overrides/src/test/java/software/amazon/awscdk/examples/ResourceOverridesStackTest.java b/java/resource-overrides/src/test/java/software/amazon/awscdk/examples/ResourceOverridesStackTest.java
new file mode 100644
index 0000000000..d6bbb648ff
--- /dev/null
+++ b/java/resource-overrides/src/test/java/software/amazon/awscdk/examples/ResourceOverridesStackTest.java
@@ -0,0 +1,45 @@
+package software.amazon.awscdk.examples;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.junit.Test;
+import org.skyscreamer.jsonassert.JSONAssert;
+import org.skyscreamer.jsonassert.JSONCompareMode;
+import software.amazon.awscdk.core.App;
+import software.amazon.awscdk.core.ConstructNode;
+import software.amazon.awscdk.core.IConstruct;
+import software.amazon.awscdk.core.Stack;
+import software.amazon.awscdk.cxapi.CloudFormationStackArtifact;
+
+import java.io.IOException;
+
+public class ResourceOverridesStackTest {
+ private static final ObjectMapper JSON = new ObjectMapper();
+
+ @Test
+ public void shouldGenerateValidCloudFormationTemplate() throws Exception {
+ App app = new App();
+ Stack stack = new ResourceOverridesStack(app, "resource-overrides");
+
+ String actual = getStackTemplateJson(stack)
+ .toPrettyString();
+ String expected = readJsonFromResource("testResourceOverrides.expected.json")
+ .toPrettyString();
+
+ JSONAssert.assertEquals(expected, actual, JSONCompareMode.LENIENT);
+ }
+
+ private static JsonNode readJsonFromResource(String resourceName) throws IOException {
+ return JSON.readTree(
+ ResourceOverridesStackTest.class.getResource(resourceName)
+ );
+ }
+
+ private static JsonNode getStackTemplateJson(Stack stack) {
+ IConstruct root = stack.getNode().getRoot();
+ CloudFormationStackArtifact stackArtifact = ConstructNode.synth(root.getNode())
+ .getStackByName(stack.getStackName());
+
+ return JSON.valueToTree(stackArtifact.getTemplate());
+ }
+}
diff --git a/java/resource-overrides/src/test/resources/software/amazon/awscdk/examples/testResourceOverrides.expected.json b/java/resource-overrides/src/test/resources/software/amazon/awscdk/examples/testResourceOverrides.expected.json
new file mode 100644
index 0000000000..20c62234d3
--- /dev/null
+++ b/java/resource-overrides/src/test/resources/software/amazon/awscdk/examples/testResourceOverrides.expected.json
@@ -0,0 +1,400 @@
+{
+ "Resources": {
+ "Other34654A52": {
+ "Type": "AWS::S3::Bucket",
+ "UpdateReplacePolicy": "Retain",
+ "DeletionPolicy": "Retain"
+ },
+ "MyBucketF68F3FF0": {
+ "Type": "AWS::S3::Bucketeer",
+ "Properties": {
+ "AnalyticsConfigurations": [
+ {
+ "Id": "config1",
+ "StorageClassAnalysis": {
+ "DataExport": {
+ "Destination": {
+ "BucketArn": {
+ "Fn::GetAtt": [
+ "Other34654A52",
+ "Arn"
+ ]
+ },
+ "Format": "html"
+ },
+ "OutputSchemaVersion": "1"
+ }
+ }
+ }
+ ],
+ "BucketEncryption": {
+ "ServerSideEncryptionConfiguration": [
+ {
+ "EncryptEverythingAndAlways": true
+ }
+ ]
+ },
+ "CorsConfiguration": {
+ "Custom": 123
+ },
+ "LoggingConfiguration": {
+ "DestinationBucketName": {
+ "Ref": "Other34654A52"
+ }
+ },
+ "VersioningConfiguration": {
+ "Status": "NewStatus"
+ },
+ "Token": {
+ "Fn::GetAtt": [
+ "Other34654A52",
+ "Arn"
+ ]
+ }
+ },
+ "DependsOn": [
+ "Other34654A52"
+ ],
+ "UpdatePolicy": {
+ "AutoScalingRollingUpdate": {
+ "PauseTime": "390"
+ }
+ },
+ "UpdateReplacePolicy": "Retain",
+ "DeletionPolicy": "Retain",
+ "Transform": "Boom"
+ },
+ "VPCB9E5F0B4": {
+ "Type": "AWS::EC2::VPC",
+ "Properties": {
+ "CidrBlock": "10.0.0.0/16",
+ "EnableDnsHostnames": true,
+ "EnableDnsSupport": true,
+ "InstanceTenancy": "default",
+ "Tags": [
+ {
+ "Key": "Name",
+ "Value": "resource-overrides/VPC"
+ }
+ ]
+ }
+ },
+ "VPCPublicSubnet1SubnetB4246D30": {
+ "Type": "AWS::EC2::Subnet",
+ "Properties": {
+ "CidrBlock": "10.0.0.0/17",
+ "VpcId": {
+ "Ref": "VPCB9E5F0B4"
+ },
+ "AvailabilityZone": {
+ "Fn::Select": [
+ 0,
+ {
+ "Fn::GetAZs": ""
+ }
+ ]
+ },
+ "MapPublicIpOnLaunch": true,
+ "Tags": [
+ {
+ "Key": "Name",
+ "Value": "resource-overrides/VPC/PublicSubnet1"
+ },
+ {
+ "Key": "aws-cdk:subnet-name",
+ "Value": "Public"
+ },
+ {
+ "Key": "aws-cdk:subnet-type",
+ "Value": "Public"
+ }
+ ]
+ }
+ },
+ "VPCPublicSubnet1RouteTableFEE4B781": {
+ "Type": "AWS::EC2::RouteTable",
+ "Properties": {
+ "VpcId": {
+ "Ref": "VPCB9E5F0B4"
+ },
+ "Tags": [
+ {
+ "Key": "Name",
+ "Value": "resource-overrides/VPC/PublicSubnet1"
+ }
+ ]
+ }
+ },
+ "VPCPublicSubnet1RouteTableAssociation0B0896DC": {
+ "Type": "AWS::EC2::SubnetRouteTableAssociation",
+ "Properties": {
+ "RouteTableId": {
+ "Ref": "VPCPublicSubnet1RouteTableFEE4B781"
+ },
+ "SubnetId": {
+ "Ref": "VPCPublicSubnet1SubnetB4246D30"
+ }
+ }
+ },
+ "VPCPublicSubnet1DefaultRoute91CEF279": {
+ "Type": "AWS::EC2::Route",
+ "Properties": {
+ "RouteTableId": {
+ "Ref": "VPCPublicSubnet1RouteTableFEE4B781"
+ },
+ "DestinationCidrBlock": "0.0.0.0/0",
+ "GatewayId": {
+ "Ref": "VPCIGWB7E252D3"
+ }
+ },
+ "DependsOn": [
+ "VPCVPCGW99B986DC"
+ ]
+ },
+ "VPCPublicSubnet1EIP6AD938E8": {
+ "Type": "AWS::EC2::EIP",
+ "Properties": {
+ "Domain": "vpc"
+ }
+ },
+ "VPCPublicSubnet1NATGatewayE0556630": {
+ "Type": "AWS::EC2::NatGateway",
+ "Properties": {
+ "AllocationId": {
+ "Fn::GetAtt": [
+ "VPCPublicSubnet1EIP6AD938E8",
+ "AllocationId"
+ ]
+ },
+ "SubnetId": {
+ "Ref": "VPCPublicSubnet1SubnetB4246D30"
+ },
+ "Tags": [
+ {
+ "Key": "Name",
+ "Value": "resource-overrides/VPC/PublicSubnet1"
+ }
+ ]
+ }
+ },
+ "VPCPrivateSubnet1Subnet8BCA10E0": {
+ "Type": "AWS::EC2::Subnet",
+ "Properties": {
+ "CidrBlock": "10.0.128.0/17",
+ "VpcId": {
+ "Ref": "VPCB9E5F0B4"
+ },
+ "AvailabilityZone": {
+ "Fn::Select": [
+ 0,
+ {
+ "Fn::GetAZs": ""
+ }
+ ]
+ },
+ "MapPublicIpOnLaunch": false,
+ "Tags": [
+ {
+ "Key": "Name",
+ "Value": "resource-overrides/VPC/PrivateSubnet1"
+ },
+ {
+ "Key": "aws-cdk:subnet-name",
+ "Value": "Private"
+ },
+ {
+ "Key": "aws-cdk:subnet-type",
+ "Value": "Private"
+ }
+ ]
+ }
+ },
+ "VPCPrivateSubnet1RouteTableBE8A6027": {
+ "Type": "AWS::EC2::RouteTable",
+ "Properties": {
+ "VpcId": {
+ "Ref": "VPCB9E5F0B4"
+ },
+ "Tags": [
+ {
+ "Key": "Name",
+ "Value": "resource-overrides/VPC/PrivateSubnet1"
+ }
+ ]
+ }
+ },
+ "VPCPrivateSubnet1RouteTableAssociation347902D1": {
+ "Type": "AWS::EC2::SubnetRouteTableAssociation",
+ "Properties": {
+ "RouteTableId": {
+ "Ref": "VPCPrivateSubnet1RouteTableBE8A6027"
+ },
+ "SubnetId": {
+ "Ref": "VPCPrivateSubnet1Subnet8BCA10E0"
+ }
+ }
+ },
+ "VPCPrivateSubnet1DefaultRouteAE1D6490": {
+ "Type": "AWS::EC2::Route",
+ "Properties": {
+ "RouteTableId": {
+ "Ref": "VPCPrivateSubnet1RouteTableBE8A6027"
+ },
+ "DestinationCidrBlock": "0.0.0.0/0",
+ "NatGatewayId": {
+ "Ref": "VPCPublicSubnet1NATGatewayE0556630"
+ }
+ }
+ },
+ "VPCIGWB7E252D3": {
+ "Type": "AWS::EC2::InternetGateway",
+ "Properties": {
+ "Tags": [
+ {
+ "Key": "Name",
+ "Value": "resource-overrides/VPC"
+ }
+ ]
+ }
+ },
+ "VPCVPCGW99B986DC": {
+ "Type": "AWS::EC2::VPCGatewayAttachment",
+ "Properties": {
+ "VpcId": {
+ "Ref": "VPCB9E5F0B4"
+ },
+ "InternetGatewayId": {
+ "Ref": "VPCIGWB7E252D3"
+ }
+ }
+ },
+ "ASGInstanceSecurityGroup0525485D": {
+ "Type": "AWS::EC2::SecurityGroup",
+ "Properties": {
+ "GroupDescription": "resource-overrides/ASG/InstanceSecurityGroup",
+ "SecurityGroupEgress": [
+ {
+ "CidrIp": "0.0.0.0/0",
+ "Description": "Allow all outbound traffic by default",
+ "IpProtocol": "-1"
+ }
+ ],
+ "Tags": [
+ {
+ "Key": "Name",
+ "Value": "resource-overrides/ASG"
+ }
+ ],
+ "VpcId": {
+ "Ref": "VPCB9E5F0B4"
+ }
+ }
+ },
+ "ASGInstanceRoleE263A41B": {
+ "Type": "AWS::IAM::Role",
+ "Properties": {
+ "AssumeRolePolicyDocument": {
+ "Statement": [
+ {
+ "Action": "sts:AssumeRole",
+ "Effect": "Allow",
+ "Principal": {
+ "Service": {
+ "Fn::Join": [
+ "",
+ [
+ "ec2.",
+ {
+ "Ref": "AWS::URLSuffix"
+ }
+ ]
+ ]
+ }
+ }
+ }
+ ],
+ "Version": "2012-10-17"
+ },
+ "Tags": [
+ {
+ "Key": "Name",
+ "Value": "resource-overrides/ASG"
+ }
+ ]
+ }
+ },
+ "ASGInstanceProfile0A2834D7": {
+ "Type": "AWS::IAM::InstanceProfile",
+ "Properties": {
+ "Roles": [
+ {
+ "Ref": "ASGInstanceRoleE263A41B"
+ }
+ ]
+ }
+ },
+ "ASGLaunchConfigC00AF12B": {
+ "Type": "AWS::AutoScaling::LaunchConfiguration",
+ "Properties": {
+ "ImageId": {
+ "Ref": "SsmParameterValueawsserviceamiamazonlinuxlatestamznamihvmx8664gp2C96584B6F00A464EAD1953AFF4B05118Parameter"
+ },
+ "InstanceType": "r4.xlarge",
+ "IamInstanceProfile": {
+ "Ref": "ASGInstanceProfile0A2834D7"
+ },
+ "SecurityGroups": [
+ {
+ "Fn::GetAtt": [
+ "ASGInstanceSecurityGroup0525485D",
+ "GroupId"
+ ]
+ }
+ ],
+ "UserData": {
+ "Fn::Base64": "#!/bin/bash"
+ },
+ "Foo": {
+ "Bar": "Hello"
+ }
+ },
+ "DependsOn": [
+ "ASGInstanceRoleE263A41B"
+ ]
+ },
+ "ASG46ED3070": {
+ "Type": "AWS::AutoScaling::AutoScalingGroup",
+ "Properties": {
+ "MaxSize": "1",
+ "MinSize": "1",
+ "DesiredCapacity": "1",
+ "LaunchConfigurationName": {
+ "Ref": "ASGLaunchConfigC00AF12B"
+ },
+ "Tags": [
+ {
+ "Key": "Name",
+ "PropagateAtLaunch": true,
+ "Value": "resource-overrides/ASG"
+ }
+ ],
+ "VPCZoneIdentifier": [
+ {
+ "Ref": "VPCPrivateSubnet1Subnet8BCA10E0"
+ }
+ ]
+ },
+ "UpdatePolicy": {
+ "AutoScalingScheduledAction": {
+ "IgnoreUnmodifiedGroupSizeProperties": true
+ }
+ }
+ }
+ },
+ "Parameters": {
+ "SsmParameterValueawsserviceamiamazonlinuxlatestamznamihvmx8664gp2C96584B6F00A464EAD1953AFF4B05118Parameter": {
+ "Type": "AWS::SSM::Parameter::Value",
+ "Default": "/aws/service/ami-amazon-linux-latest/amzn-ami-hvm-x86_64-gp2"
+ }
+ }
+}