Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support deprecated on fields in the OpenAPI conversion #2221

Merged
merged 14 commits into from
Apr 11, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
import software.amazon.smithy.model.shapes.TimestampShape;
import software.amazon.smithy.model.shapes.UnionShape;
import software.amazon.smithy.model.traits.DefaultTrait;
import software.amazon.smithy.model.traits.DeprecatedTrait;
import software.amazon.smithy.model.traits.DocumentationTrait;
import software.amazon.smithy.model.traits.EnumTrait;
import software.amazon.smithy.model.traits.LengthTrait;
Expand Down Expand Up @@ -100,13 +101,16 @@ private Schema createRef(MemberShape member) {
if (converter.isInlined(member)) {
return member.accept(this);
} else {
Schema.Builder refBuilder = Schema.builder().ref(converter.toPointer(member.getTarget()));
if (member.hasTrait(DeprecatedTrait.class) && getJsonSchemaVersion() != JsonSchemaVersion.DRAFT07) {
refBuilder.deprecated(true);
}
// Wrap the ref and default in an allOf if disableDefaultValues has been not been disabled on config.
if (member.hasTrait(DefaultTrait.class) && !converter.getConfig().getDisableDefaultValues()) {
Schema ref = Schema.builder().ref(converter.toPointer(member.getTarget())).build();
Schema def = Schema.builder().defaultValue(member.expectTrait(DefaultTrait.class).toNode()).build();
return Schema.builder().allOf(ListUtils.of(ref, def)).build();
return Schema.builder().allOf(ListUtils.of(refBuilder.build(), def)).build();
}
return Schema.builder().ref(converter.toPointer(member.getTarget())).build();
return refBuilder.build();
}
}

Expand Down Expand Up @@ -329,6 +333,10 @@ private Schema.Builder updateBuilder(Shape shape, Schema.Builder builder) {
builder.defaultValue(shape.expectTrait(DefaultTrait.class).toNode());
}

if (shape.hasTrait(DeprecatedTrait.class) && getJsonSchemaVersion() != JsonSchemaVersion.DRAFT07) {
builder.deprecated(true);
}

return builder;
}

Expand All @@ -351,4 +359,8 @@ private Schema buildSchema(Shape shape, Schema.Builder builder) {

return builder.build();
}

private JsonSchemaVersion getJsonSchemaVersion() {
return converter.getConfig().getJsonSchemaVersion();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ public final class Schema implements ToNode, ToSmithyBuilder<Schema> {
private final boolean writeOnly;
private final String comment;
private final Node examples;
private final boolean deprecated;

private final String contentEncoding;
private final String contentMediaType;
Expand Down Expand Up @@ -153,6 +154,7 @@ private Schema(Builder builder) {
writeOnly = builder.writeOnly;
comment = builder.comment;
examples = builder.examples;
deprecated = builder.deprecated;

contentEncoding = builder.contentEncoding;
contentMediaType = builder.contentMediaType;
Expand Down Expand Up @@ -312,6 +314,10 @@ public Optional<Node> getExamples() {
return Optional.ofNullable(examples);
}

public boolean isDeprecated() {
return deprecated;
}

public Optional<String> getContentEncoding() {
return Optional.ofNullable(contentEncoding);
}
Expand Down Expand Up @@ -364,6 +370,7 @@ public Node toNode() {

.withOptionalMember("comment", getComment().map(Node::from))
.withOptionalMember("examples", getExamples())
.withOptionalMember("deprecated", this.deprecated ? Optional.of(Node.from(true)) : Optional.empty())
.withOptionalMember("title", getTitle().map(Node::from))
.withOptionalMember("description", getDescription().map(Node::from))
.withOptionalMember("format", getFormat().map(Node::from))
Expand Down Expand Up @@ -421,6 +428,10 @@ public Node toNode() {
result.withMember("writeOnly", Node.from(true));
}

if (deprecated) {
result.withMember("deprecated", Node.from(true));
}

for (Map.Entry<String, ToNode> entry : extensions.entrySet()) {
result.withMember(entry.getKey(), entry.getValue().toNode());
}
Expand Down Expand Up @@ -540,6 +551,7 @@ public Builder toBuilder() {
.writeOnly(writeOnly)
.comment(comment)
.examples(examples)
.deprecated(deprecated)

.contentEncoding(contentEncoding)
.contentMediaType(contentMediaType);
Expand Down Expand Up @@ -611,6 +623,7 @@ public static final class Builder implements SmithyBuilder<Schema> {
private boolean writeOnly;
private String comment;
private Node examples;
private boolean deprecated;

private String contentEncoding;
private String contentMediaType;
Expand Down Expand Up @@ -853,6 +866,11 @@ public Builder examples(Node examples) {
return this;
}

public Builder deprecated(boolean deprecated) {
this.deprecated = deprecated;
return this;
}

public Builder extensions(Map<String, Node> extensions) {
this.extensions.clear();
this.extensions.putAll(extensions);
Expand Down Expand Up @@ -945,6 +963,8 @@ public Builder disableProperty(String propertyName) {
return this.contentMediaType(null);
case "examples":
return this.examples(null);
case "deprecated":
return this.deprecated(false);
default:
LOGGER.warning("Unknown JSON Schema config 'disable' property: " + propertyName);
return this;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
import software.amazon.smithy.model.shapes.StringShape;
import software.amazon.smithy.model.shapes.StructureShape;
import software.amazon.smithy.model.shapes.UnionShape;
import software.amazon.smithy.model.traits.DeprecatedTrait;
import software.amazon.smithy.model.traits.DocumentationTrait;
import software.amazon.smithy.model.traits.EnumDefinition;
import software.amazon.smithy.model.traits.EnumTrait;
Expand Down Expand Up @@ -780,4 +781,110 @@ public void intEnumsCanBeDisabled() {
IoUtils.toUtf8String(getClass().getResourceAsStream("int-enums-disabled.jsonschema.v07.json")));
Node.assertEquals(document.toNode(), expected);
}

@Test
miguel-vila marked this conversation as resolved.
Show resolved Hide resolved
public void supportsDeprecatedTraitOnAStruct() {
StringShape string = StringShape.builder().id("smithy.api#String").build();
StructureShape shape = StructureShape.builder()
.id(ShapeId.from("a.b#C"))
.addMember(MemberShape.builder()
.id(ShapeId.from("a.b#C$member"))
.target(string.getId())
.build())
.addTrait(DeprecatedTrait.builder()
.message("I'm deprecated")
.since("sinceVersion")
.build())
.build();
Model model = Model.builder().addShapes(shape, string).build();
JsonSchemaConfig config = new JsonSchemaConfig();
config.setJsonSchemaVersion(JsonSchemaVersion.DRAFT2020_12);
SchemaDocument document = JsonSchemaConverter.builder()
.model(model)
.config(config)
.build()
.convertShape(shape);

assertThat(document.getRootSchema().isDeprecated(), equalTo(true));
}

@Test
public void dontAddDeprecatedTraitOnAStructWhenOldVersion() {
StringShape string = StringShape.builder().id("smithy.api#String").build();
StructureShape shape = StructureShape.builder()
.id(ShapeId.from("a.b#C"))
.addMember(MemberShape.builder()
.id(ShapeId.from("a.b#C$member"))
.target(string.getId())
.build())
.addTrait(DeprecatedTrait.builder()
.message("I'm deprecated")
.since("sinceVersion")
.build())
.build();
Model model = Model.builder().addShapes(shape, string).build();
JsonSchemaConfig config = new JsonSchemaConfig();
config.setJsonSchemaVersion(JsonSchemaVersion.DRAFT07);
SchemaDocument document = JsonSchemaConverter.builder()
.model(model)
.config(config)
.build()
.convertShape(shape);

assertThat(document.getRootSchema().isDeprecated(), equalTo(false));
}

@Test
public void supportsDeprecatedTraitOnAMember() {
StringShape string = StringShape.builder().id("smithy.api#String").build();
StructureShape shape = StructureShape.builder()
.id(ShapeId.from("a.b#C"))
.addMember(MemberShape.builder()
.id(ShapeId.from("a.b#C$member"))
.target(string.getId())
.addTrait(DeprecatedTrait.builder()
.message("I'm deprecated")
.since("sinceVersion")
.build())
.build())
.build();
Model model = Model.builder().addShapes(shape, string).build();
JsonSchemaConfig config = new JsonSchemaConfig();
config.setJsonSchemaVersion(JsonSchemaVersion.DRAFT2020_12);
SchemaDocument document = JsonSchemaConverter.builder()
.model(model)
.config(config)
.build()
.convertShape(shape);

Schema memberSchema = document.getRootSchema().getProperties().get("member");
assertThat(memberSchema.isDeprecated(), equalTo(true));
}

@Test
public void dontAddDeprecatedTraitOnAMemberWhenOldVersion() {
StringShape string = StringShape.builder().id("smithy.api#String").build();
StructureShape shape = StructureShape.builder()
.id(ShapeId.from("a.b#C"))
.addMember(MemberShape.builder()
.id(ShapeId.from("a.b#C$member"))
.target(string.getId())
.addTrait(DeprecatedTrait.builder()
.message("I'm deprecated")
.since("sinceVersion")
.build())
.build())
.build();
Model model = Model.builder().addShapes(shape, string).build();
JsonSchemaConfig config = new JsonSchemaConfig();
config.setJsonSchemaVersion(JsonSchemaVersion.DRAFT07);
SchemaDocument document = JsonSchemaConverter.builder()
.model(model)
.config(config)
.build()
.convertShape(shape);

Schema memberSchema = document.getRootSchema().getProperties().get("member");
assertThat(memberSchema.isDeprecated(), equalTo(false));
}
}