From 263df67197e22420d950bbf04306ed545108b892 Mon Sep 17 00:00:00 2001 From: kstich Date: Wed, 21 Oct 2020 10:21:50 -0700 Subject: [PATCH] Add JSON Schema support for patternProperties --- .../1.0/guides/converting-to-openapi.rst | 25 ++++++++ .../smithy/jsonschema/JsonSchemaConfig.java | 45 ++++++++++++++ .../jsonschema/JsonSchemaShapeVisitor.java | 20 ++++++- .../amazon/smithy/jsonschema/Schema.java | 34 ++++++++++- .../jsonschema/JsonSchemaConverterTest.java | 58 +++++++++++++++++++ 5 files changed, 178 insertions(+), 4 deletions(-) diff --git a/docs/source/1.0/guides/converting-to-openapi.rst b/docs/source/1.0/guides/converting-to-openapi.rst index fb63745a335..60f2eebbdea 100644 --- a/docs/source/1.0/guides/converting-to-openapi.rst +++ b/docs/source/1.0/guides/converting-to-openapi.rst @@ -514,6 +514,31 @@ unionStrategy (``string``) } } +mapStrategy (``string``) + Configures how Smithy map shapes are converted to JSON Schema. + + This property must be a string set to one of the following values: + + * ``propertyNames``: Converts to a schema that uses a combination of + "propertyNames" and "additionalProperties". This is the default setting + used if not configured. + * ``patternProperties``: Converts to a schema that uses + "patternProperties". If a map's key member or its target does not have a + "pattern" trait, a default indicating one or more of any character (".+") + is applied. + + .. code-block:: json + + { + "version": "1.0", + "plugins": { + "openapi": { + "service": "smithy.example#Weather", + "mapStrategy": "propertyNames" + } + } + } + schemaDocumentExtensions (``Map``) Adds custom top-level key-value pairs to the created OpenAPI specification. Any existing value is overwritten. 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 98d7a81bc62..036444f8a01 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 @@ -62,10 +62,42 @@ public String toString() { } } + /** + * Configures how Smithy map shapes are converted to JSON Schema. + */ + public enum MapStrategy { + /** + * Converts to a schema that uses a combination of "propertyNames" + * and "additionalProperties". + * + *

This is the default setting used if not configured. + */ + PROPERTY_NAMES("propertyNames"), + + /** + * Converts to a schema that uses "patternProperties". If a map's key + * member or its target does not have a {@code pattern} trait, a default + * indicating one or more of any character (".+") is applied. + */ + PATTERN_PROPERTIES("patternProperties"); + + private String stringValue; + + MapStrategy(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 String definitionPointer = "#/definitions"; private ObjectNode schemaDocumentExtensions = Node.objectNode(); private ObjectNode extensions = Node.objectNode(); @@ -140,6 +172,19 @@ public void setUnionStrategy(UnionStrategy unionStrategy) { this.unionStrategy = unionStrategy; } + public MapStrategy getMapStrategy() { + return mapStrategy; + } + + /** + * Configures how Smithy map shapes are converted to JSON Schema. + * + * @param mapStrategy The map strategy to use. + */ + public void setMapStrategy(MapStrategy mapStrategy) { + this.mapStrategy = mapStrategy; + } + public String getDefinitionPointer() { return definitionPointer; } 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 e7dc7ef08fb..6c46addcc61 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 @@ -109,9 +109,23 @@ private Schema createRef(MemberShape member) { @Override public Schema mapShape(MapShape shape) { - return buildSchema(shape, createBuilder(shape, "object") - .propertyNames(createRef(shape.getKey())) - .additionalProperties(createRef(shape.getValue()))); + JsonSchemaConfig.MapStrategy mapStrategy = converter.getConfig().getMapStrategy(); + + switch (mapStrategy) { + case PROPERTY_NAMES: + return buildSchema(shape, createBuilder(shape, "object") + .propertyNames(createRef(shape.getKey())) + .additionalProperties(createRef(shape.getValue()))); + case PATTERN_PROPERTIES: + String keyPattern = shape.getKey().getMemberTrait(model, PatternTrait.class) + .map(PatternTrait::getPattern) + .map(Pattern::pattern) + .orElse(".+"); + return buildSchema(shape, createBuilder(shape, "object") + .putPatternProperty(keyPattern, createRef(shape.getValue()))); + default: + throw new SmithyJsonSchemaException(String.format("Unsupported map strategy: %s", mapStrategy)); + } } @Override diff --git a/smithy-jsonschema/src/main/java/software/amazon/smithy/jsonschema/Schema.java b/smithy-jsonschema/src/main/java/software/amazon/smithy/jsonschema/Schema.java index 5d6b61b5c25..12e5fa67872 100644 --- a/smithy-jsonschema/src/main/java/software/amazon/smithy/jsonschema/Schema.java +++ b/smithy-jsonschema/src/main/java/software/amazon/smithy/jsonschema/Schema.java @@ -41,7 +41,6 @@ * version of JSON Schema. The following properties are not supported: * *