Skip to content

Commit

Permalink
Add round-trip convertibility of resource schemas
Browse files Browse the repository at this point in the history
  • Loading branch information
haydenbaker committed Nov 7, 2024
1 parent 37e0dec commit 7fbe10e
Show file tree
Hide file tree
Showing 6 changed files with 836 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@
import software.amazon.smithy.jsonschema.Schema;
import software.amazon.smithy.model.node.Node;
import software.amazon.smithy.model.node.ObjectNode;
import software.amazon.smithy.model.node.StringNode;
import software.amazon.smithy.model.node.ToNode;
import software.amazon.smithy.utils.ListUtils;
import software.amazon.smithy.utils.SmithyBuilder;
import software.amazon.smithy.utils.ToSmithyBuilder;

Expand All @@ -41,24 +41,30 @@ public final class Property implements ToNode, ToSmithyBuilder<Property> {
// * writeOnly

private Property(Builder builder) {
this.insertionOrder = builder.insertionOrder;
this.dependencies = ListUtils.copyOf(builder.dependencies);
this.schema = builder.schema;
}
Schema.Builder schemaBuilder;

@Override
public Node toNode() {
ObjectNode.Builder builder = schema.toNode().expectObjectNode().toBuilder();
if (builder.schema == null) {
schemaBuilder = Schema.builder();
} else {
schemaBuilder = builder.schema.toBuilder();
}

// Only serialize these properties if set to non-defaults.
if (insertionOrder) {
builder.withMember("insertionOrder", Node.from(insertionOrder));
this.insertionOrder = builder.insertionOrder;
if (this.insertionOrder) {
schemaBuilder.putExtension("insertionOrder", Node.from(true));
}
if (!dependencies.isEmpty()) {
builder.withMember("dependencies", Node.fromStrings(dependencies));

this.dependencies = builder.dependencies;
if (!this.dependencies.isEmpty()) {
schemaBuilder.putExtension("dependencies", Node.fromStrings(this.dependencies));
}

return builder.build();
this.schema = schemaBuilder.build();
}

@Override
public Node toNode() {
return schema.toNode().expectObjectNode();
}

@Override
Expand All @@ -69,6 +75,22 @@ public Builder toBuilder() {
.schema(schema);
}

public static Property fromNode(Node node) {
ObjectNode objectNode = node.expectObjectNode();
Builder builder = builder();

objectNode.getBooleanMember("insertionOrder", builder::insertionOrder);
objectNode.getArrayMember("dependencies", StringNode::getValue, builder::dependencies);

builder.schema(Schema.fromNode(objectNode));

return builder.build();
}

public static Property fromSchema(Schema schema) {
return builder().schema(schema).build();
}

public static Builder builder() {
return new Builder();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ public final class ResourceSchema implements ToNode, ToSmithyBuilder<ResourceSch
private final Map<String, Handler> handlers = new TreeMap<>(Comparator.comparing(Handler::getHandlerNameOrder));
private final Map<String, Remote> remotes = new TreeMap<>();
private final Tagging tagging;
private final Schema additionalProperties;

private ResourceSchema(Builder builder) {
typeName = SmithyBuilder.requiredState("typeName", builder.typeName);
Expand All @@ -84,6 +85,7 @@ private ResourceSchema(Builder builder) {
handlers.putAll(builder.handlers);
remotes.putAll(builder.remotes);
tagging = builder.tagging;
additionalProperties = builder.additionalProperties;
}

@Override
Expand Down Expand Up @@ -136,6 +138,9 @@ public Node toNode() {
if (tagging != null) {
builder.withMember("tagging", mapper.serialize(tagging));
}
if (additionalProperties != null) {
builder.withMember("additionalProperties", mapper.serialize(additionalProperties));
}

return builder.build();
}
Expand Down Expand Up @@ -242,6 +247,7 @@ public static final class Builder implements SmithyBuilder<ResourceSchema> {
private final Map<String, Handler> handlers = new TreeMap<>();
private final Map<String, Remote> remotes = new TreeMap<>();
private Tagging tagging;
private Schema additionalProperties;

private Builder() {}

Expand Down Expand Up @@ -470,5 +476,10 @@ public Builder clearRemotes() {
this.remotes.clear();
return this;
}

public Builder additionalProperties(Schema additionalProperties) {
this.additionalProperties = additionalProperties;
return this;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Copyright 2020 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;

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import software.amazon.smithy.aws.cloudformation.schema.model.ResourceSchema;
import software.amazon.smithy.model.node.Node;
import software.amazon.smithy.model.node.NodeMapper;
import software.amazon.smithy.utils.IoUtils;

import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.stream.Collectors;

public class ResourceSchemaTest {

@ParameterizedTest
@MethodSource("resourceSchemaFiles")
public void validateResourceSchemaFromNodeToNode(String resourceSchemaFile) {
NodeMapper mapper = new NodeMapper();
String json = IoUtils.readUtf8File(resourceSchemaFile);

Node actual = Node.parse(json);
ResourceSchema schemaFromNode = mapper.deserialize(actual, ResourceSchema.class);
Node nodeFromSchema = schemaFromNode.toNode();

Node.assertEquals(nodeFromSchema.withDeepSortedKeys(), actual.withDeepSortedKeys());
}

public static List<String> resourceSchemaFiles() {
try {
Path definitionPath = Paths.get(ResourceSchemaTest.class.getResource("aws-sagemaker-domain.json").toURI());

return Files.walk(Paths.get(definitionPath.getParent().toUri()))
.filter(Files::isRegularFile)
.filter(file -> file.toString().endsWith(".cfn.json"))
.map(Object::toString)
.collect(Collectors.toList());
} catch (IOException | URISyntaxException e) {
throw new RuntimeException(e);
}
}
}
Loading

0 comments on commit 7fbe10e

Please sign in to comment.