diff --git a/smithy-jsonschema/src/main/java/software/amazon/smithy/jsonschema/JsonSchemaConfig.java b/smithy-jsonschema/src/main/java/software/amazon/smithy/jsonschema/JsonSchemaConfig.java
index a51ceca2e09..4f034610dd7 100644
--- a/smithy-jsonschema/src/main/java/software/amazon/smithy/jsonschema/JsonSchemaConfig.java
+++ b/smithy-jsonschema/src/main/java/software/amazon/smithy/jsonschema/JsonSchemaConfig.java
@@ -85,11 +85,42 @@ public String toString() {
}
}
+ /**
+ * Configures how Smithy enum shapes are converted to JSON Schema
+ */
+ public enum EnumStrategy {
+
+ /**
+ * Converts to a schema that uses enum, which contains an array of strings
+ *
+ *
This is the default setting used if not configured.
+ */
+ ENUM("enum"),
+
+ /**
+ * Converts to a schema that uses oneOf, with an array of const strings and optional
+ * descriptions for documentation purposes
+ */
+ ONE_OF("oneOf");
+
+ private final String stringValue;
+
+ EnumStrategy(String stringValue) {
+ this.stringValue = stringValue;
+ }
+
+ @Override
+ public String toString() {
+ return stringValue;
+ }
+ }
+
private boolean alphanumericOnlyRefs;
private boolean useJsonName;
private TimestampFormatTrait.Format defaultTimestampFormat = TimestampFormatTrait.Format.DATE_TIME;
private UnionStrategy unionStrategy = UnionStrategy.ONE_OF;
private MapStrategy mapStrategy = MapStrategy.PROPERTY_NAMES;
+ private EnumStrategy enumStrategy = EnumStrategy.ENUM;
private String definitionPointer;
private ObjectNode schemaDocumentExtensions = Node.objectNode();
private ObjectNode extensions = Node.objectNode();
@@ -186,6 +217,18 @@ public void setMapStrategy(MapStrategy mapStrategy) {
this.mapStrategy = mapStrategy;
}
+ public EnumStrategy getEnumStrategy() {
+ return enumStrategy;
+ }
+
+ /**
+ * Configures how Smithy enum shapes ae converted to JSON Schema
+ * @param enumStrategy The enum strategy to use
+ */
+ public void setEnumStrategy(EnumStrategy enumStrategy) {
+ this.enumStrategy = enumStrategy;
+ }
+
public String getDefinitionPointer() {
return definitionPointer != null ? definitionPointer : jsonSchemaVersion.getDefaultDefinitionPointer();
}
diff --git a/smithy-jsonschema/src/main/java/software/amazon/smithy/jsonschema/JsonSchemaShapeVisitor.java b/smithy-jsonschema/src/main/java/software/amazon/smithy/jsonschema/JsonSchemaShapeVisitor.java
index d10064f068c..1c4276d5e53 100644
--- a/smithy-jsonschema/src/main/java/software/amazon/smithy/jsonschema/JsonSchemaShapeVisitor.java
+++ b/smithy-jsonschema/src/main/java/software/amazon/smithy/jsonschema/JsonSchemaShapeVisitor.java
@@ -7,11 +7,13 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
+import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.regex.Pattern;
import software.amazon.smithy.model.Model;
import software.amazon.smithy.model.node.Node.NonNumericFloat;
+import software.amazon.smithy.model.node.StringNode;
import software.amazon.smithy.model.shapes.BigDecimalShape;
import software.amazon.smithy.model.shapes.BigIntegerShape;
import software.amazon.smithy.model.shapes.BlobShape;
@@ -19,6 +21,7 @@
import software.amazon.smithy.model.shapes.ByteShape;
import software.amazon.smithy.model.shapes.DocumentShape;
import software.amazon.smithy.model.shapes.DoubleShape;
+import software.amazon.smithy.model.shapes.EnumShape;
import software.amazon.smithy.model.shapes.FloatShape;
import software.amazon.smithy.model.shapes.IntegerShape;
import software.amazon.smithy.model.shapes.ListShape;
@@ -248,6 +251,43 @@ public Schema unionShape(UnionShape shape) {
}
}
+ @Override
+ public Schema enumShape(EnumShape shape) {
+ JsonSchemaConfig.EnumStrategy enumStrategy = converter.getConfig().getEnumStrategy();
+
+ switch (enumStrategy) {
+ case ENUM:
+ return super.enumShape(shape);
+ case ONE_OF:
+ Map enumValues = shape.getEnumValues();
+ List schemas = new ArrayList<>();
+
+ for (Map.Entry entry : shape.getAllMembers().entrySet()) {
+ String memberName = entry.getKey();
+ MemberShape member = entry.getValue();
+ Schema enumSchema = Schema.builder()
+ .constValue(StringNode.from(enumValues.get(memberName)))
+ .description(member.getTrait(DocumentationTrait.class)
+ .map(DocumentationTrait::getValue)
+ .orElse(null))
+ .build();
+
+ schemas.add(enumSchema);
+ }
+
+ return buildSchema(shape,
+ Schema.builder()
+ .description(shape.getTrait(DocumentationTrait.class)
+ .map(DocumentationTrait::getValue)
+ .orElse(null))
+ .type("string")
+ .oneOf(schemas));
+ default: {
+ throw new SmithyJsonSchemaException(String.format("Unsupported enum strategy: %s", enumStrategy));
+ }
+ }
+ }
+
@Override
public Schema timestampShape(TimestampShape shape) {
return buildSchema(shape, createBuilder(shape, "string"));
diff --git a/smithy-jsonschema/src/test/java/software/amazon/smithy/jsonschema/JsonSchemaConverterTest.java b/smithy-jsonschema/src/test/java/software/amazon/smithy/jsonschema/JsonSchemaConverterTest.java
index e4b4b00bbd4..c0432128934 100644
--- a/smithy-jsonschema/src/test/java/software/amazon/smithy/jsonschema/JsonSchemaConverterTest.java
+++ b/smithy-jsonschema/src/test/java/software/amazon/smithy/jsonschema/JsonSchemaConverterTest.java
@@ -817,6 +817,43 @@ public void supportsIntEnumsByDefault() {
Node.assertEquals(document.toNode(), expected);
}
+ @Test
+ public void supportsDefaultEnumStrategy() {
+ Model model = Model.assembler()
+ .addImport(getClass().getResource("string-enums.smithy"))
+ .assemble()
+ .unwrap();
+
+ SchemaDocument document = JsonSchemaConverter.builder()
+ .model(model)
+ .build()
+ .convert();
+
+ Node expected = Node.parse(
+ IoUtils.toUtf8String(getClass().getResourceAsStream("string-enums.jsonschema.v07.json")));
+ Node.assertEquals(document.toNode(), expected);
+ }
+
+ @Test
+ public void supportsOneOfEnumStrategy() {
+ Model model = Model.assembler()
+ .addImport(getClass().getResource("string-enums.smithy"))
+ .assemble()
+ .unwrap();
+
+ JsonSchemaConfig config = new JsonSchemaConfig();
+ config.setEnumStrategy(JsonSchemaConfig.EnumStrategy.ONE_OF);
+ SchemaDocument document = JsonSchemaConverter.builder()
+ .model(model)
+ .config(config)
+ .build()
+ .convert();
+
+ Node expected = Node.parse(
+ IoUtils.toUtf8String(getClass().getResourceAsStream("string-enums-one-of.jsonschema.v07.json")));
+ Node.assertEquals(document.toNode(), expected);
+ }
+
@Test
public void intEnumsCanBeDisabled() {
Model model = Model.assembler()
diff --git a/smithy-jsonschema/src/test/resources/software/amazon/smithy/jsonschema/string-enums-one-of.jsonschema.v07.json b/smithy-jsonschema/src/test/resources/software/amazon/smithy/jsonschema/string-enums-one-of.jsonschema.v07.json
new file mode 100644
index 00000000000..2bda54d8eeb
--- /dev/null
+++ b/smithy-jsonschema/src/test/resources/software/amazon/smithy/jsonschema/string-enums-one-of.jsonschema.v07.json
@@ -0,0 +1,25 @@
+{
+ "definitions": {
+ "Foo": {
+ "type": "object",
+ "properties": {
+ "bar": {
+ "$ref": "#/definitions/TestEnum"
+ }
+ }
+ },
+ "TestEnum": {
+ "type": "string",
+ "description": "This is a test enum",
+ "oneOf": [
+ {
+ "const": "Foo",
+ "description": "it really does foo"
+ },
+ {
+ "const": "Bar"
+ }
+ ]
+ }
+ }
+}
diff --git a/smithy-jsonschema/src/test/resources/software/amazon/smithy/jsonschema/string-enums.jsonschema.v07.json b/smithy-jsonschema/src/test/resources/software/amazon/smithy/jsonschema/string-enums.jsonschema.v07.json
new file mode 100644
index 00000000000..905f26a4a93
--- /dev/null
+++ b/smithy-jsonschema/src/test/resources/software/amazon/smithy/jsonschema/string-enums.jsonschema.v07.json
@@ -0,0 +1,20 @@
+{
+ "definitions": {
+ "Foo": {
+ "type": "object",
+ "properties": {
+ "bar": {
+ "$ref": "#/definitions/TestEnum"
+ }
+ }
+ },
+ "TestEnum": {
+ "type": "string",
+ "enum": [
+ "Foo",
+ "Bar"
+ ],
+ "description": "This is a test enum"
+ }
+ }
+}
diff --git a/smithy-jsonschema/src/test/resources/software/amazon/smithy/jsonschema/string-enums.smithy b/smithy-jsonschema/src/test/resources/software/amazon/smithy/jsonschema/string-enums.smithy
new file mode 100644
index 00000000000..798281d6558
--- /dev/null
+++ b/smithy-jsonschema/src/test/resources/software/amazon/smithy/jsonschema/string-enums.smithy
@@ -0,0 +1,14 @@
+$version: "2.0"
+
+namespace smithy.example
+
+structure Foo {
+ bar: TestEnum
+}
+
+@documentation("This is a test enum")
+enum TestEnum {
+ @documentation("it really does foo")
+ FOO = "Foo"
+ BAR = "Bar"
+}