From aa5e727a8a6db526d583d1c93549586a4604b93c Mon Sep 17 00:00:00 2001 From: Andrew Rouse Date: Fri, 26 Jan 2024 16:57:49 +0000 Subject: [PATCH 01/25] Schema model: add new properties - if/then/else - $dialect - comment - depedentSchemas - prefixItems - contains - patternProperties - propertyNames - unevaluatedItems - unevaluatedProperties - const - maxContains - minContains - dependentRequired - contentEncoding - contentMediaType - contentSchema Co-authored-by: Michael Edgar --- api/pom.xml | 2 +- .../openapi/models/media/Schema.java | 757 ++++++++++++++++++ .../openapi/models/media/package-info.java | 2 +- pom.xml | 2 +- spec/pom.xml | 2 +- spi/pom.xml | 2 +- tck/pom.xml | 2 +- 7 files changed, 763 insertions(+), 6 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index 466875d4..30e82d08 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -20,7 +20,7 @@ org.eclipse.microprofile.openapi microprofile-openapi-parent - 3.2-SNAPSHOT + 4.0-SNAPSHOT microprofile-openapi-api diff --git a/api/src/main/java/org/eclipse/microprofile/openapi/models/media/Schema.java b/api/src/main/java/org/eclipse/microprofile/openapi/models/media/Schema.java index 7af94377..9cb8582d 100644 --- a/api/src/main/java/org/eclipse/microprofile/openapi/models/media/Schema.java +++ b/api/src/main/java/org/eclipse/microprofile/openapi/models/media/Schema.java @@ -1192,4 +1192,761 @@ default Schema oneOf(List oneOf) { */ void removeOneOf(Schema oneOf); + /** + * Returns the schema dialect in use. This is the value of the {@code $schema} property. + * + * @return the schema dialect name, or {@code null} for the default + * @since 4.0 + */ + String getSchemaDialect(); + + /** + * Sets the schema dialect in use. This is the value of the {@code $schema} property. + * + * @param schemaDialect + * the schema dialect name, or {@code null} for the default + * @since 4.0 + */ + void setSchemaDialect(String schemaDialect); + + /** + * Sets the schema dialect in use. This is the value of the {@code $schema} property. + * + * @param schemaDialect + * the schema dialect name, or {@code null} for the default + * @return the current Schema instance + * @since 4.0 + */ + default Schema schemaDialect(String schemaDialect) { + setSchemaDialect(schemaDialect); + return this; + } + + /** + * Returns the comment to be included in the {@code $comment} property of the schema. + * + * @return the comment, or {@code null} if no comment is set + * @since 4.0 + */ + String getComment(); + + /** + * Sets the comment to be included in the {@code $comment} property of the schema. + * + * @param comment + * the comment, or {@code null} to remove any comment + * @since 4.0 + */ + void setComment(String comment); + + /** + * Sets the comment to be included in the {@code $comment} property of the schema. + * + * @param comment + * the comment, or {@code null} to remove any comment + * @return the current Schema instance + * @since 4.0 + */ + default Schema comment(String comment) { + setComment(comment); + return this; + } + + /** + * Returns the "if" schema. If an object is valid against the "if" schema, then it must also be valid against the + * "then" schema, otherwise it must be valid against the "else" schema. + * + * @return the if schema + * @since 4.0 + */ + Schema getIfSchema(); + + /** + * Sets the "if" schema. If an object is valid against the "if" schema, then it must also be valid against the + * "then" schema, otherwise it must be valid against the "else" schema. + * + * @param ifSchema + * the if schema + * @since 4.0 + */ + void setIfSchema(Schema ifSchema); + + /** + * Sets the "if" schema. If an object is valid against the "if" schema, then it must also be valid against the + * "then" schema, otherwise it must be valid against the "else" schema. + * + * @param ifSchema + * the if schema + * @return the current Schema instance + * @since 4.0 + */ + default Schema ifSchema(Schema ifSchema) { + setIfSchema(ifSchema); + return this; + } + + /** + * Returns the "then" schema. If an object is valid against the "if" schema, then it must also be valid against the + * "then" schema. + * + * @return the then schema + * @since 4.0 + */ + Schema getThenSchema(); + + /** + * Sets the "then" schema. If an object is valid against the "if" schema, then it must also be valid against the + * "then" schema. + * + * @param thenSchema + * the then schema + * @since 4.0 + */ + void setThenSchema(Schema thenSchema); + + /** + * Sets the "then" schema. If an object is valid against the "if" schema, then it must also be valid against the + * "then" schema. + * + * @param thenSchema + * the then schema + * @return the current Schema instance + * @since 4.0 + */ + default Schema thenSchema(Schema thenSchema) { + setThenSchema(thenSchema); + return this; + } + + /** + * Returns the "else" schema. If an object is not valid against the "if" schema, then it must be valid against the + * "else" schema. + * + * @return the else schema + * @since 4.0 + */ + Schema getElseSchema(); + + /** + * Sets the "else" schema. If an object is not valid against the "if" schema, then it must be valid against the + * "else" schema. + * + * @param elseSchema + * the else schema + * @since 4.0 + */ + void setElseSchema(Schema elseSchema); + + /** + * Sets the "else" schema. If an object is not valid against the "if" schema, then it must be valid against the + * "else" schema. + * + * @param elseSchema + * the else schema + * @return the current Schema instance + * @since 4.0 + */ + default Schema elseSchema(Schema elseSchema) { + setElseSchema(elseSchema); + return this; + } + + /** + * Returns the dependentSchemas property of this Schema instance. + *

+ * For each name and property pair in the map, if the object contains a property with the given name, it must match + * the corresponding schema. + * + * @return a copy Map (potentially immutable) of properties and their dependent schemas + * @since 4.0 + */ + Map getDependentSchemas(); + + /** + * Sets the dependentSchemas property of this Schema instance. + *

+ * For each name and property pair in the map, if the object contains a property with the given name, it must match + * the corresponding schema. + * + * @param dependentSchemas + * a map of properties and their dependent schemas + * @since 4.0 + */ + void setDependentSchemas(Map dependentSchemas); + + /** + * Sets the dependentSchemas property of this Schema instance. + *

+ * For each name and property pair in the map, if the object contains a property with the given name, it must match + * the corresponding schema. + * + * @param dependentSchemas + * a map of properties and their dependent schemas + * @return the current Schema instance + * @since 4.0 + */ + default Schema dependentSchemas(Map dependentSchemas) { + setDependentSchemas(dependentSchemas); + return this; + } + + /** + * Sets the dependent schema for a property name. + *

+ * If the object contains a property with the given name, it must match the dependent schema. + * + * @param propertyName + * the property name + * @param schema + * the dependent schema + * @return the current Schema instance + * @since 4.0 + */ + Schema addDependentSchema(String propertyName, Schema schema); + + /** + * Removes the dependent schema for a property name. + * + * @param propertyName + * the property name + * @since 4.0 + */ + void removeDependentSchema(String propertyName); + + /** + * Returns the prefixItems property of this Schema instance. + *

+ * If the object is an array, the nth item in the array must match the nth schema in this list. + * + * @return a copy List (potentially immutable) of prefix item schemas + * @since 4.0 + */ + List getPrefixItems(); + + /** + * Sets the prefixItems property of this Schema instance. + *

+ * If the object is an array, the nth item in the array must match the nth schema in this list. + * + * @param prefixItems + * a list of prefix item schemas + * @since 4.0 + */ + void setPrefixItems(List prefixItems); + + /** + * Sets the prefixItems property of this Schema instance. + *

+ * If the object is an array, the nth item in the array must match the nth schema in this list. + * + * @param prefixItems + * a list of prefix item schemas + * @return current Schema instance + * @since 4.0 + */ + default Schema prefixItems(List prefixItems) { + setPrefixItems(prefixItems); + return this; + } + + /** + * Adds a schema to the end of the prefixItems list. + * + * @param prefixItem + * the schema to add to the prefixItems list + * @return current Schema instance + * @since 4.0 + */ + Schema addPrefixItem(Schema prefixItem); + + /** + * Removes a schema from the prefixItems list. + * + * @param prefixItem + * the schema to remove from the prefixItems list + * @since 4.0 + */ + void removePrefixItem(Schema prefixItem); + + /** + * Returns the contains property of this Schema instance. + *

+ * If the object is an array, at least one item in the array must match the returned schema. + * + * @return a schema that one item in the array should match + * @since 4.0 + */ + Schema getContains(); + + /** + * Sets the contains property of this Schema instance. + *

+ * If the object is an array, at least one item in the array must match the returned schema. + * + * @param contains + * a schema that one item in the array should match + * @since 4.0 + */ + void setContains(Schema contains); + + /** + * Sets the contains property of this Schema instance. + *

+ * If the object is an array, at least one item in the array must match the returned schema. + * + * @param contains + * a schema that one item in the array should match + * @return the current Schema instance + * @since 4.0 + */ + default Schema contains(Schema contains) { + setContains(contains); + return this; + } + + /** + * Returns the patternProperties property from this Schema instance. + *

+ * The value of patternProperties is a map from a regular expression to a schema. For each string and schema pair in + * the map, if a property name is matched by the regular expression then the value of that property must validate + * against the schema. + * + * @return a copy Map (potentially immutable) of regular expression and schema pairs + * @since 4.0 + */ + Map getPatternProperties(); + + /** + * Sets the patternProperties property from this Schema instance. + *

+ * The value of patternProperties is a map from a regular expression to a schema. For each string and schema pair in + * the map, if a property name is matched by the regular expression then the value of that property must validate + * against the schema. + * + * @param patternProperties + * a map of regular expression and schema pairs + * @since 4.0 + */ + void setPatternProperties(Map patternProperties); + + /** + * Sets the patternProperties property from this Schema instance. + *

+ * The value of patternProperties is a map from a regular expression to a schema. For each string and schema pair in + * the map, if a property name is matched by the regular expression then the value of that property must validate + * against the schema. + * + * @param patternProperties + * a map of regular expression and schema pairs + * @return the current Schema instance + * @since 4.0 + */ + default Schema patternProperties(Map patternProperties) { + setPatternProperties(patternProperties); + return this; + } + + /** + * Adds a regular expression and schema pair to the list of pattern properties. + *

+ * The value of patternProperties is a map from a regular expression to a schema. For each string and schema pair in + * the map, if a property name is matched by the regular expression then the value of that property must validate + * against the schema. + * + * @param regularExpression + * the regular expression to add + * @param schema + * the schema that a property value must validate against if its name matches {@code regularExpression} + * @return the current Schema instance + * @since 4.0 + */ + Schema addPatternProperty(String regularExpression, Schema schema); + + /** + * Removes a regular expression and its corresponding schema pair from the list of pattern properties. + * + * @param regularExpression + * the regular expression to remove + * @since 4.0 + */ + void removePatternProperty(String regularExpression); + + /** + * Returns the propertyNames property from this Schema instance. Each property name in the object must + * validate against this schema. + * + * @return the schema which each property name must validate against + * @since 4.0 + */ + Schema getPropertyNames(); + + /** + * Sets the propertyNames property from this Schema instance. Each property name in the object must + * validate against this schema. + * + * @param propertyNameSchema + * the schema which each property name must validate against + * @since 4.0 + */ + void setPropertyNames(Schema propertyNameSchema); + + /** + * Sets the propertyNames property from this Schema instance. Each property name in the object must + * validate against this schema. + * + * @param propertyNameSchema + * the schema which each property name must validate against + * @return the current Schema instance + * @since 4.0 + */ + default Schema propertyNames(Schema propertyNameSchema) { + setPropertyNames(propertyNameSchema); + return this; + } + + /** + * Returns the unevaluatedItems property of this Schema instance. + *

+ * Items which have not successfully validated against {@code prefixItems}, {@code items}, or {@code contains} must + * validate against this schema. + * + * @return a schema that unevaluated array items must validate against + * @since 4.0 + */ + Schema getUnevaluatedItems(); + + /** + * Sets the unevaluatedItems property of this Schema instance. + *

+ * Items which have not successfully validated against {@code prefixItems}, {@code items}, or {@code contains} must + * validate against this schema. + * + * @param unevaluatedItems + * a schema that unevaluated array items must validate against + * @since 4.0 + */ + void setUnevaluatedItems(Schema unevaluatedItems); + + /** + * Sets the unevaluatedItems property of this Schema instance. + *

+ * Items which have not successfully validated against {@code prefixItems}, {@code items}, or {@code contains} must + * validate against this schema. + * + * @param unevaluatedItems + * a schema that unevaluated array items must validate against + * @return the current Schema instance + * @since 4.0 + */ + default Schema unevaluatedItems(Schema unevaluatedItems) { + setUnevaluatedItems(unevaluatedItems); + return this; + } + + /** + * Returns the unevaluatedProperties property of this Schema instance. + *

+ * Property values which have not successfully validated against {@code properties}, {@code patternProperties}, or + * {@code additionalProperties} must validate against this schema. + * + * @return a schema that unevaluated object properties must validate against + * @since 4.0 + */ + Schema getUnevaluatedProperties(); + + /** + * Sets the unevaluatedProperties property of this Schema instance. + *

+ * Property values which have not successfully validated against {@code properties}, {@code patternProperties}, or + * {@code additionalProperties} must validate against this schema. + * + * @param unevaluatedProperties + * a schema that unevaluated object properties must validate against + * @since 4.0 + */ + void setUnevaluatedProperties(Schema unevaluatedProperties); + + /** + * Sets the unevaluatedProperties property of this Schema instance. + *

+ * Property values which have not successfully validated against {@code properties}, {@code patternProperties}, or + * {@code additionalProperties} must validate against this schema. + * + * @param unevaluatedProperties + * a schema that unevaluated object properties must validate against + * @return the current Schema instance + * @since 4.0 + */ + default Schema unevaluatedProperties(Schema unevaluatedProperties) { + setUnevaluatedProperties(unevaluatedProperties); + return this; + } + + /** + * Returns the const property from this Schema instance. Indicates that the object must have a specific value. + * + * @return the value that the object must have + * @since 4.0 + */ + Object getConstValue(); + + /** + * Sets the const property from this Schema instance. Indicates that the object must have a specific value. + * + * @param constValue + * the value that the object must have + * @since 4.0 + */ + void setConstValue(Object constValue); + + /** + * Sets the const property from this Schema instance. Indicates that the object must have a specific value. + * + * @param constValue + * the value that the object must have + * @return the current Schema instance + * @since 4.0 + */ + default Schema constValue(Object constValue) { + setConstValue(constValue); + return this; + } + + /** + * Returns the maxContains property from this Schema instance. Specifies that {@code contains} must match no more + * than this many items in the array. + * + * @return the max number of items which may be matched by {@code contains} + * @since 4.0 + */ + Integer getMaxContains(); + + /** + * Sets the maxContains property from this Schema instance. Specifies that {@code contains} must match no more than + * this many items in the array. + * + * @param maxContains + * the max number of items which may be matched by {@code contains} + * @since 4.0 + */ + void setMaxContains(Integer maxContains); + + /** + * Sets the maxContains property from this Schema instance. Specifies that {@code contains} must match no more than + * this many items in the array. + * + * @param maxContains + * the maximum number of items which may be matched by {@code contains} + * @return the current Schema instance + * @since 4.0 + */ + default Schema maxContains(Integer maxContains) { + setMaxContains(maxContains); + return this; + } + + /** + * Returns the minContains property from this Schema instance. Specifies that {@code contains} must match at least + * this many items in the array. + * + * @return the minimum number of items which may be matched by {@code contains} + * @since 4.0 + */ + Integer getMinContains(); + + /** + * Sets the minContains property from this Schema instance. Specifies that {@code contains} must match at least this + * many items in the array. + * + * @param minContains + * the minimum number of items which may be matched by {@code contains} + * @since 4.0 + */ + void setMinContains(Integer minContains); + + /** + * Sets the minContains property from this Schema instance. Specifies that {@code contains} must match at least this + * many items in the array. + * + * @param minContains + * the minimum number of items which may be matched by {@code contains} + * @return the current Schema instance + * @since 4.0 + */ + default Schema minContains(Integer minContains) { + setMinContains(minContains); + return this; + } + + /** + * Returns the dependentRequired property of this Schema instance. + *

+ * For each entry in the map, if the key exists as a property name in the object, then the list of names in the + * value must also exist as property names in the object. + * + * @return a copy Map (potentially immutable) of property names to lists of additional required property names + * @since 4.0 + */ + Map> getDependentRequired(); + + /** + * Sets the dependentRequired property of this Schema instance. + *

+ * For each entry in the map, if the key exists as a property name in the object, then the list of names in the + * value must also exist as property names in the object. + * + * @param dependentRequired + * a map of property names to lists of additional required property names + * @since 4.0 + */ + void setDependentRequired(Map> dependentRequired); + + /** + * Sets the dependentRequired property of this Schema instance. + *

+ * For each entry in the map, if the key exists as a property name in the object, then the list of names in the + * value must also exist as property names in the object. + * + * @param dependentRequired + * a map of property names to lists of additional required property names + * @return the current Schema instance + * @since 4.0 + */ + default Schema dependentRequired(Map> dependentRequired) { + setDependentRequired(dependentRequired); + return this; + } + + /** + * Sets the list of additional property names that are required if a property named {@code propertyName} exists. + * + * @param propertyName + * the property name + * @param additionalRequiredPropertyNames + * the names of additional properties which are required if {@code propertyName} exists to add + * @return the current Schema instance + * @since 4.0 + */ + Schema addDependentRequired(String propertyName, List additionalRequiredPropertyNames); + + /** + * Removes the list of additional property names that are required if a property named {@code propertyName} exists. + * + * @param propertyName + * the property name + * @since 4.0 + */ + void removeDependentRequired(String propertyName); + + /** + * Returns the contentEncoding property from this Schema instance. + *

+ * Specifies the encoding used to represent binary data as a string (e.g. base64). + * + * @return the encoding type + * @since 4.0 + */ + String getContentEncoding(); + + /** + * Sets the contentEncoding property from this Schema instance. + *

+ * Specifies the encoding used to represent binary data as a string (e.g. base64). + * + * @param contentEncoding + * the encoding type + * @since 4.0 + */ + void setContentEncoding(String contentEncoding); + + /** + * Sets the contentEncoding property from this Schema instance. + *

+ * Specifies the encoding used to represent binary data as a string (e.g. base64). + * + * @param contentEncoding + * the encoding type + * @return the current Schema instance + * @since 4.0 + */ + default Schema contentEncoding(String contentEncoding) { + setContentEncoding(contentEncoding); + return this; + } + + /** + * Returns the contentMediaType property from this Schema instance. + *

+ * Specifies the media type of the content of a string. + * + * @return the media type + * @since 4.0 + */ + String getContentMediaType(); + + /** + * Sets the contentMediaType property from this Schema instance. + *

+ * Specifies the media type of the content of a string. + * + * @param contentMediaType + * the media type + * @since 4.0 + */ + void setContentMediaType(String contentMediaType); + + /** + * Sets the contentMediaType property from this Schema instance. + *

+ * Specifies the media type of the content of a string. + * + * @param contentMediaType + * the media type + * @return the current Schema instance + * @since 4.0 + */ + default Schema contentMediaType(String contentMediaType) { + setContentMediaType(contentMediaType); + return this; + } + + /** + * Returns the contentSchema property from this Schema instance. + *

+ * If {@code contentMediaType} is a media type that maps into JSON Schema's data model, this property specifies a + * schema that the data in the string must conform to. + * + * @return the schema for the data within the string + * @since 4.0 + */ + Schema getContentSchema(); + + /** + * Sets the contentSchema property from this Schema instance. + *

+ * If {@code contentMediaType} is a media type that maps into JSON Schema's data model, this property specifies a + * schema that the data in the string must conform to. + * + * @param contentSchema + * the schema for the data within the string + * @since 4.0 + */ + void setContentSchema(Schema contentSchema); + + /** + * Sets the contentSchema property from this Schema instance. + *

+ * If {@code contentMediaType} is a media type that maps into JSON Schema's data model, this property specifies a + * schema that the data in the string must conform to. + * + * @param contentSchema + * the schema for the data within the string + * @return the current Schema instance + * @since 4.0 + */ + default Schema contentSchema(Schema contentSchema) { + setContentSchema(contentSchema); + return this; + } + } diff --git a/api/src/main/java/org/eclipse/microprofile/openapi/models/media/package-info.java b/api/src/main/java/org/eclipse/microprofile/openapi/models/media/package-info.java index a974424c..657bd9a7 100644 --- a/api/src/main/java/org/eclipse/microprofile/openapi/models/media/package-info.java +++ b/api/src/main/java/org/eclipse/microprofile/openapi/models/media/package-info.java @@ -30,6 +30,6 @@ * */ -@org.osgi.annotation.versioning.Version("2.1") +@org.osgi.annotation.versioning.Version("2.2") @org.osgi.annotation.versioning.ProviderType package org.eclipse.microprofile.openapi.models.media; \ No newline at end of file diff --git a/pom.xml b/pom.xml index 84e67b00..7f40622c 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,7 @@ org.eclipse.microprofile.openapi microprofile-openapi-parent - 3.2-SNAPSHOT + 4.0-SNAPSHOT pom MicroProfile OpenAPI Eclipse MicroProfile OpenAPI diff --git a/spec/pom.xml b/spec/pom.xml index 05d67944..33695577 100644 --- a/spec/pom.xml +++ b/spec/pom.xml @@ -20,7 +20,7 @@ org.eclipse.microprofile.openapi microprofile-openapi-parent - 3.2-SNAPSHOT + 4.0-SNAPSHOT microprofile-openapi-spec diff --git a/spi/pom.xml b/spi/pom.xml index 3d7f7a15..bc08375e 100644 --- a/spi/pom.xml +++ b/spi/pom.xml @@ -20,7 +20,7 @@ org.eclipse.microprofile.openapi microprofile-openapi-parent - 3.2-SNAPSHOT + 4.0-SNAPSHOT microprofile-openapi-spi diff --git a/tck/pom.xml b/tck/pom.xml index 85370aba..f2e5dfbe 100644 --- a/tck/pom.xml +++ b/tck/pom.xml @@ -20,7 +20,7 @@ org.eclipse.microprofile.openapi microprofile-openapi-parent - 3.2-SNAPSHOT + 4.0-SNAPSHOT microprofile-openapi-tck From 023f45639a6511a6f63f2dbca5d3b3c92aeb7b8f Mon Sep 17 00:00:00 2001 From: Andrew Rouse Date: Fri, 2 Feb 2024 14:10:16 +0000 Subject: [PATCH 02/25] Schema model: add booleanSchema Signifies that this schema represents a single boolean value, rather than a schema object. --- .../openapi/models/media/Schema.java | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/api/src/main/java/org/eclipse/microprofile/openapi/models/media/Schema.java b/api/src/main/java/org/eclipse/microprofile/openapi/models/media/Schema.java index 9cb8582d..aea611c1 100644 --- a/api/src/main/java/org/eclipse/microprofile/openapi/models/media/Schema.java +++ b/api/src/main/java/org/eclipse/microprofile/openapi/models/media/Schema.java @@ -1949,4 +1949,43 @@ default Schema contentSchema(Schema contentSchema) { return this; } + /** + * Returns whether this Schema is a boolean schema. + *

+ * If this property is not {@code null}, then all other properties are ignored and the schema will be represented by + * a boolean {@code true} or {@code false} value. + * + * @return the boolean value of this schema, or {@code null} if it is not a boolean schema + * @since 4.0 + */ + Boolean getBooleanSchema(); + + /** + * Sets this schema to a boolean value. + *

+ * If this property is not {@code null}, then all other properties are ignored and the schema will be represented by + * a boolean {@code true} or {@code false} value. + * + * @param booleanSchema + * the boolean value of this schema, or {@code null} if it is not a boolean schema + * @since 4.0 + */ + void setBooleanSchema(Boolean booleanSchema); + + /** + * Sets this schema to a boolean value. + *

+ * If this property is not {@code null}, then all other properties are ignored and the schema will be represented by + * a boolean {@code true} or {@code false} value. + * + * @param booleanSchema + * the boolean value of this schema, or {@code null} if it is not a boolean schema + * @return the current Schema instance + * @since 4.0 + */ + default Schema booleanSchema(Boolean booleanSchema) { + setBooleanSchema(booleanSchema); + return this; + } + } From 16c53294c6ba6a9209bb735deccccd686e1e0885 Mon Sep 17 00:00:00 2001 From: Andrew Rouse Date: Fri, 2 Feb 2024 15:16:02 +0000 Subject: [PATCH 03/25] Schema model: deprecate bool additionalProperties Now that OpenAPI allows boolean schemas in general, we don't need a special case for additionalProperties. --- .../eclipse/microprofile/openapi/models/media/Schema.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/api/src/main/java/org/eclipse/microprofile/openapi/models/media/Schema.java b/api/src/main/java/org/eclipse/microprofile/openapi/models/media/Schema.java index aea611c1..11e2a524 100644 --- a/api/src/main/java/org/eclipse/microprofile/openapi/models/media/Schema.java +++ b/api/src/main/java/org/eclipse/microprofile/openapi/models/media/Schema.java @@ -727,7 +727,9 @@ default Schema properties(Map properties) { * * * @return this Schema's additionalProperties property (as {@link Boolean}) + * @deprecated use {@link #getAdditionalPropertiesSchema()} which may return a boolean-valued schema */ + @Deprecated(since = "4.0") Boolean getAdditionalPropertiesBoolean(); /** @@ -749,7 +751,9 @@ default Schema properties(Map properties) { * * @param additionalProperties * a Schema which defines additional properties + * @deprecated use {@link #setAdditionalPropertiesSchema(Schema)} with a boolean-valued schema */ + @Deprecated(since = "4.0") void setAdditionalPropertiesBoolean(Boolean additionalProperties); /** @@ -775,7 +779,9 @@ default Schema additionalPropertiesSchema(Schema additionalProperties) { * @param additionalProperties * a Schema which defines additional properties * @return the current Schema instance + * @deprecated use {@link #additionalPropertiesSchema(Schema)} with a boolean-valued schema */ + @Deprecated(since = "4.0") default Schema additionalPropertiesBoolean(Boolean additionalProperties) { setAdditionalPropertiesBoolean(additionalProperties); return this; From b64000381779a3b6a34c3cc2c1ff4f351c8e4765 Mon Sep 17 00:00:00 2001 From: Andrew Rouse Date: Fri, 2 Feb 2024 15:49:27 +0000 Subject: [PATCH 04/25] Schema model: update readWrite and readOnly These properties are now valid on all schemas. --- .../openapi/models/media/Schema.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/api/src/main/java/org/eclipse/microprofile/openapi/models/media/Schema.java b/api/src/main/java/org/eclipse/microprofile/openapi/models/media/Schema.java index 11e2a524..02526cc3 100644 --- a/api/src/main/java/org/eclipse/microprofile/openapi/models/media/Schema.java +++ b/api/src/main/java/org/eclipse/microprofile/openapi/models/media/Schema.java @@ -879,18 +879,18 @@ default Schema nullable(Boolean nullable) { Boolean getReadOnly(); /** - * Sets the readOnly property of this Schema. Only valid when the Schema is the property in an object. + * Sets the readOnly property of this Schema. * * @param readOnly - * true indicates the Schema should not be sent as part of a request message + * {@code true} indicates the Schema should not be sent as part of a request message */ void setReadOnly(Boolean readOnly); /** - * Sets the readOnly property of this Schema. Only valid when the Schema is the property in an object. + * Sets the readOnly property of this Schema. * * @param readOnly - * true indicates the Schema should not be sent as part of a request message + * {@code true} indicates the Schema should not be sent as part of a request message * @return the current Schema instance */ default Schema readOnly(Boolean readOnly) { @@ -906,18 +906,18 @@ default Schema readOnly(Boolean readOnly) { Boolean getWriteOnly(); /** - * Sets the writeOnly property of this Schema. Only valid when the Schema is the property in an object. + * Sets the writeOnly property of this Schema. * * @param writeOnly - * true indicates the Schema should not be sent as part of a response message + * {@code true} indicates the Schema should not be sent as part of a response message */ void setWriteOnly(Boolean writeOnly); /** - * Sets the writeOnly property of this Schema. Only valid when the Schema is the property in an object. + * Sets the writeOnly property of this Schema. * * @param writeOnly - * true indicates the Schema should not be sent as part of a response message + * {@code true} indicates the Schema should not be sent as part of a response message * @return the current Schema instance */ default Schema writeOnly(Boolean writeOnly) { From 4e22dedd21b239193e1d9d10979f5c098f92d822 Mon Sep 17 00:00:00 2001 From: Andrew Rouse Date: Fri, 2 Feb 2024 16:13:13 +0000 Subject: [PATCH 05/25] Schema model: add examples, deprecate example Example is still a valid keyword in OpenAPI 3.1, though it is deprecated in favor of examples. --- .../openapi/models/media/Schema.java | 57 ++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/api/src/main/java/org/eclipse/microprofile/openapi/models/media/Schema.java b/api/src/main/java/org/eclipse/microprofile/openapi/models/media/Schema.java index 02526cc3..4a5b221b 100644 --- a/api/src/main/java/org/eclipse/microprofile/openapi/models/media/Schema.java +++ b/api/src/main/java/org/eclipse/microprofile/openapi/models/media/Schema.java @@ -929,7 +929,9 @@ default Schema writeOnly(Boolean writeOnly) { * Returns the example property from this Schema instance. * * @return an object which is an example of an instance of this Schema - **/ + * @deprecated use {@link #getExamples()} + */ + @Deprecated(since = "4.0") Object getExample(); /** @@ -938,7 +940,9 @@ default Schema writeOnly(Boolean writeOnly) { * * @param example * an object which is an instance of this Schema + * @deprecated use {@link #setExamples(List)} */ + @Deprecated(since = "4.0") void setExample(Object example); /** @@ -948,7 +952,9 @@ default Schema writeOnly(Boolean writeOnly) { * @param example * an object which is an instance of this Schema * @return the current Schema instance + * @deprecated use {@link #examples(List)} */ + @Deprecated(since = "4.0") default Schema example(Object example) { setExample(example); return this; @@ -1994,4 +2000,53 @@ default Schema booleanSchema(Boolean booleanSchema) { return this; } + /** + * Returns the examples property of this Schema instance. + * + * @return a copy List (potentially immutable) of example objects which this schema could describe + * @since 4.0 + */ + List getExamples(); + + /** + * Sets the examples property of this Schema instance. + * + * @param examples + * a list of example objects which this schema could describe + * @since 4.0 + */ + void setExamples(List examples); + + /** + * Sets the examples property of this Schema instance. + * + * @param examples + * a list of example objects which this schema could describe + * @return current Schema instance + * @since 4.0 + */ + default Schema examples(List examples) { + setExamples(examples); + return this; + } + + /** + * Adds an example to the examples list. + * + * @param example + * the example to add to the examples list + * @return current Schema instance + * @since 4.0 + */ + Schema addExample(Object example); + + /** + * Removes an example from the examples list. + * + * @param example + * the example to remove from the examples list + * @since 4.0 + */ + void removeExample(Object example); + } From 8d991ef6dd9fd085818080d631cade1c6a250c94 Mon Sep 17 00:00:00 2001 From: Andrew Rouse Date: Fri, 2 Feb 2024 16:15:31 +0000 Subject: [PATCH 06/25] Update package version for breaking model changes --- .../eclipse/microprofile/openapi/models/media/package-info.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/main/java/org/eclipse/microprofile/openapi/models/media/package-info.java b/api/src/main/java/org/eclipse/microprofile/openapi/models/media/package-info.java index 657bd9a7..3e143df6 100644 --- a/api/src/main/java/org/eclipse/microprofile/openapi/models/media/package-info.java +++ b/api/src/main/java/org/eclipse/microprofile/openapi/models/media/package-info.java @@ -30,6 +30,6 @@ * */ -@org.osgi.annotation.versioning.Version("2.2") +@org.osgi.annotation.versioning.Version("3.0") @org.osgi.annotation.versioning.ProviderType package org.eclipse.microprofile.openapi.models.media; \ No newline at end of file From 6e495c593b07f7504ec61f46b9fccf8d0c5ce1d3 Mon Sep 17 00:00:00 2001 From: Andrew Rouse Date: Fri, 2 Feb 2024 16:22:36 +0000 Subject: [PATCH 07/25] Schema model: numeric exclusive min and max Change exclusiveMinimum and exclusiveMaximum from boolean to BigDecimal. Also update the javadoc for minimum and maximum to make the difference in meaning between the properties more clear. --- .../openapi/models/media/Schema.java | 50 ++++++++++--------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/api/src/main/java/org/eclipse/microprofile/openapi/models/media/Schema.java b/api/src/main/java/org/eclipse/microprofile/openapi/models/media/Schema.java index 4a5b221b..0b618dd4 100644 --- a/api/src/main/java/org/eclipse/microprofile/openapi/models/media/Schema.java +++ b/api/src/main/java/org/eclipse/microprofile/openapi/models/media/Schema.java @@ -212,7 +212,7 @@ default Schema multipleOf(BigDecimal multipleOf) { /** * Returns the maximum property from this Schema instance. * - * @return the maximum value of a numeric object + * @return the value that a numeric object must be less than or equal to **/ BigDecimal getMaximum(); @@ -220,7 +220,7 @@ default Schema multipleOf(BigDecimal multipleOf) { * Sets the maximum property of this Schema instance to the value given. * * @param maximum - * specifies the maximum numeric value of objects defined by this Schema + * the value that a numeric object must be less than or equal to */ void setMaximum(BigDecimal maximum); @@ -228,7 +228,7 @@ default Schema multipleOf(BigDecimal multipleOf) { * Sets the maximum property of this Schema instance to the value given. * * @param maximum - * specifies the maximum numeric value of objects defined by this Schema + * the value that a numeric object must be less than or equal to * @return the current Schema instance */ default Schema maximum(BigDecimal maximum) { @@ -239,28 +239,29 @@ default Schema maximum(BigDecimal maximum) { /** * Returns the exclusiveMaximum property from this Schema instance. * - * @return whether the numeric value of objects must be less than the maximum property - **/ - Boolean getExclusiveMaximum(); + * @return the value that a numeric object must be less than + * @since 4.0 + */ + BigDecimal getExclusiveMaximum(); /** * Sets the exclusiveMaximum property of this Schema instance to the value given. * * @param exclusiveMaximum - * when true the numeric value of objects defined by this Schema must be less than indicated by the - * maximum property + * the value that a numeric object must be less than + * @since 4.0 */ - void setExclusiveMaximum(Boolean exclusiveMaximum); + void setExclusiveMaximum(BigDecimal exclusiveMaximum); /** * Sets the exclusiveMaximum property of this Schema instance to the value given. * * @param exclusiveMaximum - * when true the numeric value of objects defined by this Schema must be less than indicated by the - * maximum property + * the value that a numeric object must be less than * @return the current Schema instance + * @since 4.0 */ - default Schema exclusiveMaximum(Boolean exclusiveMaximum) { + default Schema exclusiveMaximum(BigDecimal exclusiveMaximum) { setExclusiveMaximum(exclusiveMaximum); return this; } @@ -268,7 +269,7 @@ default Schema exclusiveMaximum(Boolean exclusiveMaximum) { /** * Returns the minimum property from this Schema instance. * - * @return the minimum value of a numeric object + * @return the value that a numeric object must be greater than or equal to **/ BigDecimal getMinimum(); @@ -276,7 +277,7 @@ default Schema exclusiveMaximum(Boolean exclusiveMaximum) { * Sets the minimum property of this Schema instance to the value given. * * @param minimum - * specifies the minimum numeric value of objects defined by this Schema + * the value that a numeric object must be greater than or equal to */ void setMinimum(BigDecimal minimum); @@ -284,7 +285,7 @@ default Schema exclusiveMaximum(Boolean exclusiveMaximum) { * Sets the minimum property of this Schema instance to the value given. * * @param minimum - * specifies the minimum numeric value of objects defined by this Schema + * the value that a numeric object must be greater than or equal to * @return the current Schema instance */ default Schema minimum(BigDecimal minimum) { @@ -295,28 +296,29 @@ default Schema minimum(BigDecimal minimum) { /** * Returns the exclusiveMinimum property from this Schema instance. * - * @return whether the numeric value of objects must be greater than the minimum property - **/ - Boolean getExclusiveMinimum(); + * @return the value that a numeric object must be greater than + * @since 4.0 + */ + BigDecimal getExclusiveMinimum(); /** * Sets the exclusiveMinimum property of this Schema instance to the value given. * * @param exclusiveMinimum - * when true the numeric value of objects defined by this Schema must be greater than indicated by the - * minimum property + * the value that a numeric object must be greater than + * @since 4.0 */ - void setExclusiveMinimum(Boolean exclusiveMinimum); + void setExclusiveMinimum(BigDecimal exclusiveMinimum); /** * Sets the exclusiveMinimum property of this Schema instance to the value given. * * @param exclusiveMinimum - * when true the numeric value of objects defined by this Schema must be greater than indicated by the - * minimum property + * the value that a numeric object must be greater than * @return the current Schema instance + * @since 4.0 */ - default Schema exclusiveMinimum(Boolean exclusiveMinimum) { + default Schema exclusiveMinimum(BigDecimal exclusiveMinimum) { setExclusiveMinimum(exclusiveMinimum); return this; } From 5279bb4a3557d553c496dec49b428bde558f2da3 Mon Sep 17 00:00:00 2001 From: Andrew Rouse Date: Fri, 2 Feb 2024 17:57:04 +0000 Subject: [PATCH 08/25] Schema model: update type and nullable Nullable has been removed, type is now permitted to be an array of permitted types and may include null. Attempt to keep the old methods as far as they don't clash with the new ones and can still be defined in a way that makes sense. --- .../openapi/models/media/Schema.java | 82 +++++++++++++++---- 1 file changed, 68 insertions(+), 14 deletions(-) diff --git a/api/src/main/java/org/eclipse/microprofile/openapi/models/media/Schema.java b/api/src/main/java/org/eclipse/microprofile/openapi/models/media/Schema.java index 0b618dd4..3b28e403 100644 --- a/api/src/main/java/org/eclipse/microprofile/openapi/models/media/Schema.java +++ b/api/src/main/java/org/eclipse/microprofile/openapi/models/media/Schema.java @@ -47,7 +47,8 @@ public interface Schema extends Extensible, Constructible, Reference required) { void removeRequired(String required); /** - * Returns the type property from this Schema. + * Returns the type property of this Schema instance. Defines the types which are valid. * - * @return the type used in this Schema. Default value must be null - **/ - SchemaType getType(); + * @return a copy List (potentially immutable) of the allowed types + */ + List getType(); /** - * Sets the type used by this Schema to the string given. + * Sets the type property of this Schema instance. Defines the types which are valid. + * + * @param types + * a list of the allowed types + */ + void setType(List types); + + /** + * Sets the type property of this Schema instance. Defines the types which are valid. + * + * @param types + * a list of the allowed types + * @return current Schema instance + * @since "4.0" + */ + default Schema type(List types) { + setType(types); + return this; + } + + /** + * Adds a type to the type list. * * @param type - * the type used by this Schema or null for reference schemas + * the type to add to the type list + * @return current Schema instance + * @since "4.0" */ + Schema addType(SchemaType type); + + /** + * Removes a type from the type list. + * + * @param type + * the type to remove from the type list + * @since "4.0" + */ + void removeType(SchemaType type); + + /** + * Sets the type property of this Schema instance to a single type. + * + * @param type + * the required type + * @since "4.0" + * @deprecated use {@link #setType(List)} + */ + @Deprecated(since = "4.0") void setType(SchemaType type); /** - * Sets the type used by this Schema to the string given. + * Sets the type property of this Schema instance to a single type. * * @param type - * the type used by this Schema or null for reference schemas + * the required type * @return the current Schema instance + * @deprecated use {@link #setType(List)} */ + @Deprecated(since = "4.0") default Schema type(SchemaType type) { setType(type); return this; @@ -847,18 +893,23 @@ default Schema format(String format) { } /** - * Returns the nullable property from this Schema instance which indicates whether null is a valid value. + * Returns whether the type property allows the object to be {@code null} * - * @return the nullable property - **/ + * @return whether null is allowed + * @deprecated use {@link #getType()} and check if the result contains {@link SchemaType#NULL} + */ + @Deprecated(since = "4.0") Boolean getNullable(); /** - * Sets the nullable property of this Schema instance. Specify true if this Schema will allow null values. + * Updates the type property to either permit or disallow {@code null} * * @param nullable - * a boolean value indicating this Schema allows a null value. + * a boolean value indicating whether this Schema allows a null value. + * @deprecated use {@link #setType(List)}, {@link #addType(SchemaType)}, or {@link #removeType(SchemaType)} to add + * or remove {@link SchemaType#NULL} */ + @Deprecated(since = "4.0") void setNullable(Boolean nullable); /** @@ -867,7 +918,10 @@ default Schema format(String format) { * @param nullable * a boolean value indicating this Schema allows a null value. * @return the current Schema instance + * @deprecated use {@link #setType(List)}, {@link #addType(SchemaType)}, or {@link #removeType(SchemaType)} to add + * or remove {@link SchemaType#NULL} */ + @Deprecated(since = "4.0") default Schema nullable(Boolean nullable) { setNullable(nullable); return this; From baf86f877f535e8f3b1038646c744fe1a8d9661b Mon Sep 17 00:00:00 2001 From: Andrew Rouse Date: Thu, 28 Mar 2024 15:30:56 +0000 Subject: [PATCH 09/25] Schema model: support arbitrary properties --- .../openapi/models/media/Schema.java | 82 +++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/api/src/main/java/org/eclipse/microprofile/openapi/models/media/Schema.java b/api/src/main/java/org/eclipse/microprofile/openapi/models/media/Schema.java index 3b28e403..b7b686dd 100644 --- a/api/src/main/java/org/eclipse/microprofile/openapi/models/media/Schema.java +++ b/api/src/main/java/org/eclipse/microprofile/openapi/models/media/Schema.java @@ -21,6 +21,7 @@ import java.util.List; import java.util.Map; +import org.eclipse.microprofile.openapi.OASFactory; import org.eclipse.microprofile.openapi.models.Constructible; import org.eclipse.microprofile.openapi.models.Extensible; import org.eclipse.microprofile.openapi.models.ExternalDocumentation; @@ -2105,4 +2106,85 @@ default Schema examples(List examples) { */ void removeExample(Object example); + /** + * Gets a schema property by name. + *

+ * Allows access to arbitrary properties in a schema object, allowing use of alternative schema dialects which use + * different property names (or the same property names with different data types). + *

+ * When using the standard schema dialect, this method can be used to retrieve values set by other methods. E.g. + * + *

+     * {@code
+     * schema.setMinimum(new BigDecimal(3));
+     * BigDecimal minimum = (BigDecimal) schema.get("minimum"); // returns 3
+     * }
+     * 
+ * + * @param propertyName + * the property name + * @return the value of the named property, or {@code null} if a property with the given name is not set + */ + Object get(String propertyName); + + /** + * Sets a schema property. + *

+ * Allows the modifications of arbitrary schema properties in a schema properties, allowing use of alternative + * schema dialects which use different property names (or the same property names with different data types). + *

+ * Passing {@code null} as the {@code value} removes the property from the schema object. + *

+ * {@code value} must be one of the following types, otherwise non-portable behavior results: + *

    + *
  • Any primitive type + *
  • Any primitive wrapper class + *
  • {@code null} + *
  • {@code String} + *
  • {@code BigDecimal} + *
  • {@code BigInteger} + *
  • Any type which {@link OASFactory} can create + *
  • Any Enumeration + *
  • {@code List} where every value is a permitted type + *
  • {@code Map} where every key is a {@code String} and every value is a permitted type + *
+ * + *

+ * When using the standard schema dialect, values set by this method can be retrieved by other methods. E.g. + * + *

+     * {@code
+     * schema.set("minimum", new BigDecimal(3));
+     * BigDecimal minimum = schema.getMinimum(); // returns 3
+     * }
+     * 
+ * + * @param propertyName + * the property name + * @param value + * the value to set, or {@code null} to remove the property + * @return the current Schema instance + */ + Schema set(String propertyName, Object value); + + /** + * Gets all properties of a schema. + *

+ * Equivalent to calling {@link #get(String)} for each property set to a non-{@code null} value and putting them all + * into a {@code Map}. + * + * @return a {@code Map} of property names to their corresponding values + */ + Map getAll(); + + /** + * Sets all properties of a schema. + *

+ * Equivalent to clearing all properties and then setting each property with {@link #set(String, Object)}. + * + * @param allProperties + * the properties to set. Each value in the map must be valid according to the rules in + * {@link #set(String, Object)} + */ + void setAll(Map allProperties); } From ece7068c99a001bbdde219cd86addadaaba81836 Mon Sep 17 00:00:00 2001 From: Andrew Rouse Date: Tue, 13 Feb 2024 11:27:12 +0000 Subject: [PATCH 10/25] Update TCKs for Schema.examples Example changed to examples and now must be an array. --- .../openapi/tck/AirlinesAppTest.java | 16 ++++++++-------- tck/src/main/resources/openapi.yaml | 6 ++++-- tck/src/main/resources/simpleapi.yaml | 18 ++++++++++++------ 3 files changed, 24 insertions(+), 16 deletions(-) diff --git a/tck/src/main/java/org/eclipse/microprofile/openapi/tck/AirlinesAppTest.java b/tck/src/main/java/org/eclipse/microprofile/openapi/tck/AirlinesAppTest.java index c938d71c..42207e17 100644 --- a/tck/src/main/java/org/eclipse/microprofile/openapi/tck/AirlinesAppTest.java +++ b/tck/src/main/java/org/eclipse/microprofile/openapi/tck/AirlinesAppTest.java @@ -704,7 +704,7 @@ public void testSchema(String type) { vr.body("components.schemas.id.format", equalTo("int32")); vr.body("paths.'/bookings'.post.responses.'201'.content.'application/json'.schema.description", equalTo("id of the new booking")); - vr.body("components.schemas.User.properties.password.example", equalTo("bobSm37")); + vr.body("components.schemas.User.properties.password.examples", contains("bobSm37")); // Object properties vr.body("paths.'/user'.post.requestBody.content.'application/json'.schema.maxProperties", equalTo(1024)); @@ -726,7 +726,7 @@ public void testSchema(String type) { public void testSchemaProperty(String type) { ValidatableResponse vr = callEndpoint(type); vr.body("components.schemas.User.properties", IsMapWithSize.aMapWithSize(10)); - vr.body("components.schemas.User.properties.phone.example", equalTo("123-456-7891")); + vr.body("components.schemas.User.properties.phone.examples", contains("123-456-7891")); vr.body("components.schemas.User.properties.phone.description", equalTo("Telephone number to contact the user")); vr.body("components.schemas.User.properties.phone.x-schema-property", equalTo("test-schema-property")); @@ -736,8 +736,8 @@ public void testSchemaProperty(String type) { public void testSchemaPropertyValuesOverrideClassPropertyValues(String type) { ValidatableResponse vr = callEndpoint(type); vr.body("components.schemas.User.properties", IsMapWithSize.aMapWithSize(10)); - vr.body("components.schemas.User.properties.phone.example", not("123-456-7890")); - vr.body("components.schemas.User.properties.phone.example", equalTo("123-456-7891")); + vr.body("components.schemas.User.properties.phone.examples", not(contains("123-456-7890"))); + vr.body("components.schemas.User.properties.phone.examples", contains("123-456-7891")); } @Test(dataProvider = "formatProvider") @@ -992,8 +992,8 @@ public void testStaticFileDefinitions(String type) { containsString("the location where data will be sent.")); vr.body(parametersPath + ".find{ it.name == 'callbackUrl' }.schema.type", equalTo("string")); vr.body(parametersPath + ".find{ it.name == 'callbackUrl' }.schema.format", equalTo("uri")); - vr.body(parametersPath + ".find{ it.name == 'callbackUrl' }.schema.example", - equalTo("https://tonys-server.com")); + vr.body(parametersPath + ".find{ it.name == 'callbackUrl' }.schema.examples", + contains("https://tonys-server.com")); final String responsePath = "paths.'/streams'.post.responses"; vr.body(responsePath, aMapWithSize(1)); @@ -1008,8 +1008,8 @@ public void testStaticFileDefinitions(String type) { equalTo("this unique identifier allows management of the subscription")); vr.body(response201Path + ".content.'application/json'.schema.properties.subscriptionId.type", equalTo("string")); - vr.body(response201Path + ".content.'application/json'.schema.properties.subscriptionId.example", - equalTo("2531329f-fb09-4ef7-887e-84e648214436")); + vr.body(response201Path + ".content.'application/json'.schema.properties.subscriptionId.examples", + contains("2531329f-fb09-4ef7-887e-84e648214436")); final String callbacksPath = "paths.'/streams'.post.callbacks.onData.'{$request.query.callbackUrl}/data'.post"; vr.body(callbacksPath + ".requestBody.description", equalTo("subscription payload")); diff --git a/tck/src/main/resources/openapi.yaml b/tck/src/main/resources/openapi.yaml index 94bc335b..94016fcf 100644 --- a/tck/src/main/resources/openapi.yaml +++ b/tck/src/main/resources/openapi.yaml @@ -30,7 +30,8 @@ paths: schema: type: string format: uri - example: https://tonys-server.com + examples: + - https://tonys-server.com responses: '201': description: subscription successfully created @@ -44,7 +45,8 @@ paths: subscriptionId: description: this unique identifier allows management of the subscription type: string - example: 2531329f-fb09-4ef7-887e-84e648214436 + examples: + - 2531329f-fb09-4ef7-887e-84e648214436 callbacks: # the name `onData` is a convenience locator onData: diff --git a/tck/src/main/resources/simpleapi.yaml b/tck/src/main/resources/simpleapi.yaml index a081863e..7e414995 100644 --- a/tck/src/main/resources/simpleapi.yaml +++ b/tck/src/main/resources/simpleapi.yaml @@ -133,14 +133,17 @@ components: id: type: string format: uuid - example: d290f1ee-6c54-4b01-90e6-d701748f0851 + examples: + - d290f1ee-6c54-4b01-90e6-d701748f0851 name: type: string - example: Widget Adapter + examples: + - Widget Adapter releaseDate: type: string format: int32 - example: '2016-08-29T09:12:33.001Z' + examples: + - '2016-08-29T09:12:33.001Z' manufacturer: $ref: '#/components/schemas/Manufacturer' Manufacturer: @@ -149,12 +152,15 @@ components: properties: name: type: string - example: ACME Corporation + examples: + - ACME Corporation homePage: type: string format: url - example: 'https://www.acme-corp.com' + examples: + - 'https://www.acme-corp.com' phone: type: string - example: 408-867-5309 + examples: + - 408-867-5309 type: object \ No newline at end of file From 7314481e1c154ab698f96858463d5dc4c20f58dd Mon Sep 17 00:00:00 2001 From: Andrew Rouse Date: Tue, 13 Feb 2024 13:04:13 +0000 Subject: [PATCH 11/25] TCK updates for Schema.type Schema.type can now be either a string or an array of strings --- .../openapi/tck/AirlinesAppTest.java | 39 ++++++------ .../microprofile/openapi/tck/FilterTest.java | 5 +- .../openapi/tck/ModelReaderAppTest.java | 7 ++- .../openapi/tck/OASConfigSchemaTest.java | 4 +- .../openapi/tck/PetStoreAppTest.java | 9 +-- .../beanvalidation/BeanValidationTest.java | 24 ++++---- .../openapi/tck/utils/TCKMatchers.java | 60 +++++++++++++++++++ 7 files changed, 108 insertions(+), 40 deletions(-) diff --git a/tck/src/main/java/org/eclipse/microprofile/openapi/tck/AirlinesAppTest.java b/tck/src/main/java/org/eclipse/microprofile/openapi/tck/AirlinesAppTest.java index 42207e17..39551bba 100644 --- a/tck/src/main/java/org/eclipse/microprofile/openapi/tck/AirlinesAppTest.java +++ b/tck/src/main/java/org/eclipse/microprofile/openapi/tck/AirlinesAppTest.java @@ -16,6 +16,7 @@ package org.eclipse.microprofile.openapi.tck; +import static org.eclipse.microprofile.openapi.tck.utils.TCKMatchers.itemOrSingleton; import static org.hamcrest.Matchers.allOf; import static org.hamcrest.Matchers.anEmptyMap; import static org.hamcrest.Matchers.both; @@ -360,7 +361,7 @@ private void testUserLoginMethods(ValidatableResponse vr) { vr.body(query + ".in", both(hasSize(1)).and(contains("query"))); vr.body(query + ".description", both(hasSize(1)).and(contains(list.get(i)[1]))); vr.body(query + ".required", both(hasSize(1)).and(contains(true))); - vr.body(query + ".schema.type", both(hasSize(1)).and(contains("string"))); + vr.body(query + ".schema.type", both(hasSize(1)).and(contains(itemOrSingleton("string")))); } } @@ -373,7 +374,7 @@ private void testReviewIdMethods(ValidatableResponse vr) { both(hasSize(1)).and(contains("ID of the booking"))); vr.body(reviewParameters + ".findAll { it.name == 'id' }.required", both(hasSize(1)).and(contains(true))); vr.body(reviewParameters + ".findAll { it.name == 'id' }.content.'*/*'.schema.type", - both(hasSize(1)).and(contains("integer"))); + both(hasSize(1)).and(contains(itemOrSingleton("integer")))); } private void testBookingIdMethods(ValidatableResponse vr) { @@ -386,7 +387,7 @@ private void testBookingIdMethods(ValidatableResponse vr) { vr.body(bookingParameters + ".findAll { it }.name", contains("id")); vr.body(bookingParameters + ".findAll { it.name == 'id' }.required", both(hasSize(1)).and(contains(true))); vr.body(bookingParameters + ".findAll { it.name == 'id' }.schema.type", - both(hasSize(1)).and(contains("integer"))); + both(hasSize(1)).and(contains(itemOrSingleton("integer")))); } bookingParameters = "paths.'/bookings/{id}'.get.parameters"; @@ -415,7 +416,7 @@ private void testAvailabilityGetParamater(ValidatableResponse vr) { vr.body(query + ".in", both(hasSize(1)).and(contains("query"))); vr.body(query + ".description", both(hasSize(1)).and(contains(list.get(i)[1]))); vr.body(query + ".required", both(hasSize(1)).and(contains(true))); - vr.body(query + ".schema.type", both(hasSize(1)).and(contains("string"))); + vr.body(query + ".schema.type", both(hasSize(1)).and(contains(itemOrSingleton("string")))); } vr.body(availabilityParameters + ".findAll { it.name == 'numberOfAdults' }.schema.minimum", @@ -467,13 +468,13 @@ public void testCallbackOperationAnnotations(String type) { vr.body(endpoint, hasKey("get")); vr.body(endpoint + ".get.summary", equalTo("Retrieve all bookings for current user")); vr.body(endpoint + ".get.responses.'200'.description", equalTo("Bookings retrieved")); - vr.body(endpoint + ".get.responses.'200'.content.'application/json'.schema.type", equalTo("array")); + vr.body(endpoint + ".get.responses.'200'.content.'application/json'.schema.type", itemOrSingleton("array")); endpoint = "paths.'/reviews'.post.callbacks.testCallback.'http://localhost:9080/oas3-airlines/reviews'"; vr.body(endpoint, hasKey("get")); vr.body(endpoint + ".get.summary", equalTo("Get all reviews")); vr.body(endpoint + ".get.responses.'200'.description", equalTo("successful operation")); - vr.body(endpoint + ".get.responses.'200'.content.'application/json'.schema.type", equalTo("array")); + vr.body(endpoint + ".get.responses.'200'.content.'application/json'.schema.type", itemOrSingleton("array")); vr.body(endpoint + ".get.responses.'200'.content.'application/json'.schema.items", notNullValue()); vr.body(endpoint + ".get.x-callback-operation", equalTo("test-callback-operation")); } @@ -700,7 +701,7 @@ public void testSchema(String type) { vr.body("components.schemas.AirlinesRef.$ref", equalTo("#/components/schemas/Airlines")); vr.body("components.schemas.Airlines.title", equalTo("Airlines")); vr.body("components.schemas.Airlines.x-schema", equalTo("test-schema")); - vr.body("paths.'/bookings'.post.responses.'201'.content.'application/json'.schema.type", equalTo("string")); + vr.body("paths.'/bookings'.post.responses.'201'.content.'application/json'.schema.type", itemOrSingleton("string")); vr.body("components.schemas.id.format", equalTo("int32")); vr.body("paths.'/bookings'.post.responses.'201'.content.'application/json'.schema.description", equalTo("id of the new booking")); @@ -852,7 +853,7 @@ public void testHeaderInAPIResponse(String type) { vr.body(responseHeader1 + ".deprecated", equalTo(true)); vr.body(responseHeader1 + ".allowEmptyValue", equalTo(true)); vr.body(responseHeader1 + ".style", equalTo("simple")); - vr.body(responseHeader1 + ".schema.type", equalTo("integer")); + vr.body(responseHeader1 + ".schema.type", itemOrSingleton("integer")); String responseHeader2 = "paths.'/reviews/{id}'.get.responses.'200'.headers.responseHeader2"; vr.body(responseHeader2, notNullValue()); @@ -861,7 +862,7 @@ public void testHeaderInAPIResponse(String type) { vr.body(responseHeader2 + ".deprecated", equalTo(true)); vr.body(responseHeader2 + ".allowEmptyValue", equalTo(true)); vr.body(responseHeader2 + ".style", equalTo("simple")); - vr.body(responseHeader2 + ".schema.type", equalTo("string")); + vr.body(responseHeader2 + ".schema.type", itemOrSingleton("string")); } @Test(dataProvider = "formatProvider") @@ -877,7 +878,7 @@ public void testHeaderInEncoding(String type) { vr.body(testHeader + ".deprecated", equalTo(true)); vr.body(testHeader + ".allowEmptyValue", equalTo(true)); vr.body(testHeader + ".style", equalTo("simple")); - vr.body(testHeader + ".schema.type", equalTo("integer")); + vr.body(testHeader + ".schema.type", itemOrSingleton("integer")); } @Test(dataProvider = "formatProvider") @@ -910,7 +911,7 @@ public void testHeaderInComponents(String type) { vr.body(maxRate + ".deprecated", equalTo(true)); vr.body(maxRate + ".allowEmptyValue", equalTo(true)); vr.body(maxRate + ".style", equalTo("simple")); - vr.body(maxRate + ".schema.type", equalTo("integer")); + vr.body(maxRate + ".schema.type", itemOrSingleton("integer")); vr.body(maxRate + ".x-header", equalTo("test-header")); } @@ -920,7 +921,7 @@ public void testContentInAPIResponse(String type) { String content1 = "paths.'/availability'.get.responses.'200'.content.'application/json'"; vr.body(content1, notNullValue()); - vr.body(content1 + ".schema.type", equalTo("array")); + vr.body(content1 + ".schema.type", itemOrSingleton("array")); vr.body(content1 + ".schema.items", notNullValue()); vr.body(content1 + ".x-content", equalTo("test-content")); @@ -953,7 +954,7 @@ public void testContentInParameter(String type) { String content = "paths.'/reviews/users/{user}'.get.parameters.find{ it.name == 'user' }.content"; vr.body(content, notNullValue()); vr.body(content + ".'*/*'", notNullValue()); - vr.body(content + ".'*/*'.schema.type", equalTo("string")); + vr.body(content + ".'*/*'.schema.type", itemOrSingleton("string")); } @Test(dataProvider = "formatProvider") @@ -990,7 +991,7 @@ public void testStaticFileDefinitions(String type) { vr.body(parametersPath + ".find{ it.name == 'callbackUrl' }.required", equalTo(true)); vr.body(parametersPath + ".find{ it.name == 'callbackUrl' }.description", containsString("the location where data will be sent.")); - vr.body(parametersPath + ".find{ it.name == 'callbackUrl' }.schema.type", equalTo("string")); + vr.body(parametersPath + ".find{ it.name == 'callbackUrl' }.schema.type", itemOrSingleton("string")); vr.body(parametersPath + ".find{ it.name == 'callbackUrl' }.schema.format", equalTo("uri")); vr.body(parametersPath + ".find{ it.name == 'callbackUrl' }.schema.examples", contains("https://tonys-server.com")); @@ -1007,18 +1008,18 @@ public void testStaticFileDefinitions(String type) { vr.body(response201Path + ".content.'application/json'.schema.properties.subscriptionId.description", equalTo("this unique identifier allows management of the subscription")); vr.body(response201Path + ".content.'application/json'.schema.properties.subscriptionId.type", - equalTo("string")); + itemOrSingleton("string")); vr.body(response201Path + ".content.'application/json'.schema.properties.subscriptionId.examples", contains("2531329f-fb09-4ef7-887e-84e648214436")); final String callbacksPath = "paths.'/streams'.post.callbacks.onData.'{$request.query.callbackUrl}/data'.post"; vr.body(callbacksPath + ".requestBody.description", equalTo("subscription payload")); vr.body(callbacksPath + ".requestBody.content.'application/json'.schema.properties.timestamp.type", - equalTo("string")); + itemOrSingleton("string")); vr.body(callbacksPath + ".requestBody.content.'application/json'.schema.properties.timestamp.format", equalTo("date-time")); vr.body(callbacksPath + ".requestBody.content.'application/json'.schema.properties.userData.type", - equalTo("string")); + itemOrSingleton("string")); vr.body(callbacksPath + ".responses", aMapWithSize(2)); vr.body(callbacksPath + ".responses.'202'.description", @@ -1055,7 +1056,7 @@ public void testExceptionMappers(String type) { String rejectedReviewSchema = dereference(vr, "paths.'/reviews'.post.responses.'400'.content.'application/json'.schema"); - vr.body(rejectedReviewSchema + ".type", equalTo("object")); + vr.body(rejectedReviewSchema + ".type", itemOrSingleton("object")); vr.body(rejectedReviewSchema + ".properties", hasKey("reason")); } @@ -1104,7 +1105,7 @@ public void testAdditionalPropertiesTypeString(String type) { vr.body(responseSchema, notNullValue()); String flightSchema = dereference(vr, responseSchema, "properties.returningFlight"); - vr.body(flightSchema + ".additionalProperties.type", equalTo("string")); + vr.body(flightSchema + ".additionalProperties.type", itemOrSingleton("string")); } @Test(dataProvider = "formatProvider") diff --git a/tck/src/main/java/org/eclipse/microprofile/openapi/tck/FilterTest.java b/tck/src/main/java/org/eclipse/microprofile/openapi/tck/FilterTest.java index dbc4abf0..70d11bd7 100644 --- a/tck/src/main/java/org/eclipse/microprofile/openapi/tck/FilterTest.java +++ b/tck/src/main/java/org/eclipse/microprofile/openapi/tck/FilterTest.java @@ -16,6 +16,7 @@ package org.eclipse.microprofile.openapi.tck; +import static org.eclipse.microprofile.openapi.tck.utils.TCKMatchers.itemOrSingleton; import static org.hamcrest.Matchers.both; import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.containsInAnyOrder; @@ -112,7 +113,7 @@ public void testFilterParameter(String type) { vr.body(username + ".in", both(hasSize(1)).and(contains("query"))); vr.body(username + ".description", both(hasSize(1)).and(contains("filterParameter - The user name for login"))); vr.body(username + ".required", both(hasSize(1)).and(contains(true))); - vr.body(username + ".schema.type", both(hasSize(1)).and(contains("string"))); + vr.body(username + ".schema.type", both(hasSize(1)).and(contains(itemOrSingleton("string")))); // Parameter named 'password' should have been removed by filter vr.body(reviewParameters, hasSize(1)); @@ -161,7 +162,7 @@ public void testFilterHeader(String type) { vr.body(maxRate + ".deprecated", equalTo(true)); vr.body(maxRate + ".allowEmptyValue", equalTo(true)); vr.body(maxRate + ".style", equalTo("simple")); - vr.body(maxRate + ".schema.type", equalTo("integer")); + vr.body(maxRate + ".schema.type", itemOrSingleton("integer")); } @Test(dataProvider = "formatProvider") diff --git a/tck/src/main/java/org/eclipse/microprofile/openapi/tck/ModelReaderAppTest.java b/tck/src/main/java/org/eclipse/microprofile/openapi/tck/ModelReaderAppTest.java index cfdf6438..6b240cb5 100644 --- a/tck/src/main/java/org/eclipse/microprofile/openapi/tck/ModelReaderAppTest.java +++ b/tck/src/main/java/org/eclipse/microprofile/openapi/tck/ModelReaderAppTest.java @@ -16,6 +16,7 @@ package org.eclipse.microprofile.openapi.tck; +import static org.eclipse.microprofile.openapi.tck.utils.TCKMatchers.itemOrSingleton; import static org.hamcrest.Matchers.both; import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.containsInAnyOrder; @@ -169,7 +170,7 @@ public void testAvailabilityGetParameter(String type) { vr.body(query + ".in", both(hasSize(1)).and(contains("query"))); vr.body(query + ".description", both(hasSize(1)).and(contains(list.get(i)[1]))); vr.body(query + ".required", both(hasSize(1)).and(contains(true))); - vr.body(query + ".schema.type", both(hasSize(1)).and(contains("string"))); + vr.body(query + ".schema.type", both(hasSize(1)).and(contains(itemOrSingleton("string")))); } vr.body(availabilityParameters + ".findAll { it.name == 'numberOfAdults' }.schema.minimum", @@ -211,7 +212,7 @@ public void testSchema(String type) { vr.body("components.schemas.AirlinesRef.$ref", equalTo("#/components/schemas/Airlines")); vr.body("components.schemas.Airlines.title", equalTo("Airlines")); vr.body("paths.'/modelReader/bookings'.post.responses.'201'.content.'text/plain'.schema.type", - equalTo("string")); + itemOrSingleton("string")); vr.body("components.schemas.id.format", equalTo("int32")); vr.body("paths.'/modelReader/bookings'.post.responses.'201'.content.'text/plain'.schema.description", equalTo("id of the new booking")); @@ -291,7 +292,7 @@ public void testContentInAPIResponse(String type) { String content1 = "paths.'/availability'.get.responses.'200'.content.'application/json'"; vr.body(content1, notNullValue()); - vr.body(content1 + ".schema.type", equalTo("array")); + vr.body(content1 + ".schema.type", itemOrSingleton("array")); vr.body(content1 + ".schema.items", notNullValue()); } } diff --git a/tck/src/main/java/org/eclipse/microprofile/openapi/tck/OASConfigSchemaTest.java b/tck/src/main/java/org/eclipse/microprofile/openapi/tck/OASConfigSchemaTest.java index e42285ba..e15751b0 100644 --- a/tck/src/main/java/org/eclipse/microprofile/openapi/tck/OASConfigSchemaTest.java +++ b/tck/src/main/java/org/eclipse/microprofile/openapi/tck/OASConfigSchemaTest.java @@ -16,9 +16,11 @@ package org.eclipse.microprofile.openapi.tck; +import static org.eclipse.microprofile.openapi.tck.utils.TCKMatchers.itemOrSingleton; import static org.hamcrest.Matchers.allOf; import static org.hamcrest.Matchers.anyOf; import static org.hamcrest.Matchers.hasEntry; +import static org.hamcrest.Matchers.is; import static org.hamcrest.collection.IsMapWithSize.aMapWithSize; import java.util.Map; @@ -53,7 +55,7 @@ public void testSchemaConfigApplied(String type) { private Matcher> epochSecondsSchema() { return allOf(aMapWithSize(4), hasEntry("title", "Epoch Seconds"), - hasEntry("type", "number"), + hasEntry(is("type"), itemOrSingleton("number")), hasEntry("format", "int64"), hasEntry("description", "Number of seconds from the epoch of 1970-01-01T00:00:00Z")); } diff --git a/tck/src/main/java/org/eclipse/microprofile/openapi/tck/PetStoreAppTest.java b/tck/src/main/java/org/eclipse/microprofile/openapi/tck/PetStoreAppTest.java index 23b3bd94..11fc7757 100644 --- a/tck/src/main/java/org/eclipse/microprofile/openapi/tck/PetStoreAppTest.java +++ b/tck/src/main/java/org/eclipse/microprofile/openapi/tck/PetStoreAppTest.java @@ -18,6 +18,7 @@ import static io.restassured.RestAssured.given; import static org.eclipse.microprofile.openapi.tck.utils.TCKMatchers.comparesEqualToNumber; +import static org.eclipse.microprofile.openapi.tck.utils.TCKMatchers.itemOrSingleton; import static org.hamcrest.Matchers.allOf; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.hasEntry; @@ -218,7 +219,7 @@ public void testRequestBodySchema(String type) { vr.body(schemaObject, allOf(aMapWithSize(3), hasEntry(equalTo("required"), notNullValue()), - hasEntry(equalTo("type"), equalTo("object")), + hasEntry(equalTo("type"), itemOrSingleton("object")), hasEntry(equalTo("properties"), notNullValue()))); } @@ -241,7 +242,7 @@ public void testAPIResponseSchema(String type) { vr.body(schemaObject, allOf(aMapWithSize(3), hasEntry(equalTo("required"), notNullValue()), - hasEntry(equalTo("type"), equalTo("object")), + hasEntry(equalTo("type"), itemOrSingleton("object")), hasEntry(equalTo("properties"), notNullValue()))); } @@ -265,7 +266,7 @@ public void testAPIResponseSchemaDefaultResponseCode(String type) { vr.body(arraySchemaObject, allOf(aMapWithSize(2), - hasEntry(equalTo("type"), equalTo("array")), + hasEntry(equalTo("type"), itemOrSingleton("array")), hasEntry(equalTo("items"), notNullValue()))); String schemaObject = dereference(vr, arraySchemaObject + ".items"); @@ -273,7 +274,7 @@ public void testAPIResponseSchemaDefaultResponseCode(String type) { vr.body(schemaObject, allOf(aMapWithSize(3), hasEntry(equalTo("required"), notNullValue()), - hasEntry(equalTo("type"), equalTo("object")), + hasEntry(equalTo("type"), itemOrSingleton("object")), hasEntry(equalTo("properties"), notNullValue()))); } diff --git a/tck/src/main/java/org/eclipse/microprofile/openapi/tck/beanvalidation/BeanValidationTest.java b/tck/src/main/java/org/eclipse/microprofile/openapi/tck/beanvalidation/BeanValidationTest.java index f94d45a6..e55a431a 100644 --- a/tck/src/main/java/org/eclipse/microprofile/openapi/tck/beanvalidation/BeanValidationTest.java +++ b/tck/src/main/java/org/eclipse/microprofile/openapi/tck/beanvalidation/BeanValidationTest.java @@ -16,8 +16,10 @@ package org.eclipse.microprofile.openapi.tck.beanvalidation; import static org.eclipse.microprofile.openapi.tck.Groups.BEAN_VALIDATION; +import static org.eclipse.microprofile.openapi.tck.utils.TCKMatchers.itemOrSingleton; import static org.hamcrest.Matchers.hasEntry; import static org.hamcrest.Matchers.hasKey; +import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.not; import org.eclipse.microprofile.openapi.apps.beanvalidation.BeanValidationApp; @@ -42,21 +44,21 @@ public static WebArchive buildApp() { public void notEmptyStringTest(String format) { ValidatableResponse vr = callEndpoint(format); assertProperty(vr, "notEmptyString", hasEntry("minLength", 1)); - assertProperty(vr, "notEmptyString", hasEntry("type", "string")); + assertProperty(vr, "notEmptyString", hasEntry(is("type"), itemOrSingleton("string"))); } @Test(dataProvider = "formatProvider", groups = BEAN_VALIDATION) public void notEmptyListTest(String format) { ValidatableResponse vr = callEndpoint(format); assertProperty(vr, "notEmptyList", hasEntry("minItems", 1)); - assertProperty(vr, "notEmptyList", hasEntry("type", "array")); + assertProperty(vr, "notEmptyList", hasEntry(is("type"), itemOrSingleton("array"))); } @Test(dataProvider = "formatProvider", groups = BEAN_VALIDATION) public void notEmptyMapTest(String format) { ValidatableResponse vr = callEndpoint(format); assertProperty(vr, "notEmptyMap", hasEntry("minProperties", 1)); - assertProperty(vr, "notEmptyMap", hasEntry("type", "object")); + assertProperty(vr, "notEmptyMap", hasEntry(is("type"), itemOrSingleton("object"))); } @Test(dataProvider = "formatProvider", groups = BEAN_VALIDATION) @@ -70,7 +72,7 @@ public void sizedStringTest(String format) { ValidatableResponse vr = callEndpoint(format); assertProperty(vr, "sizedString", hasEntry("minLength", 2)); assertProperty(vr, "sizedString", hasEntry("maxLength", 7)); - assertProperty(vr, "sizedString", hasEntry("type", "string")); + assertProperty(vr, "sizedString", hasEntry(is("type"), itemOrSingleton("string"))); } @Test(dataProvider = "formatProvider", groups = BEAN_VALIDATION) @@ -78,7 +80,7 @@ public void sizedListTest(String format) { ValidatableResponse vr = callEndpoint(format); assertProperty(vr, "sizedList", hasEntry("minItems", 1)); assertProperty(vr, "sizedList", hasEntry("maxItems", 10)); - assertProperty(vr, "sizedList", hasEntry("type", "array")); + assertProperty(vr, "sizedList", hasEntry(is("type"), itemOrSingleton("array"))); } @Test(dataProvider = "formatProvider", groups = BEAN_VALIDATION) @@ -86,14 +88,14 @@ public void sizedMapTest(String format) { ValidatableResponse vr = callEndpoint(format); assertProperty(vr, "sizedMap", hasEntry("minProperties", 3)); assertProperty(vr, "sizedMap", hasEntry("maxProperties", 5)); - assertProperty(vr, "sizedMap", hasEntry("type", "object")); + assertProperty(vr, "sizedMap", hasEntry(is("type"), itemOrSingleton("object"))); } @Test(dataProvider = "formatProvider", groups = BEAN_VALIDATION) public void maxDecimalInclusiveTest(String format) { ValidatableResponse vr = callEndpoint(format); assertProperty(vr, "maxDecimalInclusive", hasEntry("maximum", 1.5f)); - assertProperty(vr, "maxDecimalInclusive", hasEntry("type", "number")); + assertProperty(vr, "maxDecimalInclusive", hasEntry(is("type"), itemOrSingleton("number"))); } @Test(dataProvider = "formatProvider", groups = BEAN_VALIDATION) @@ -101,14 +103,14 @@ public void maxDecimalExclusiveTest(String format) { ValidatableResponse vr = callEndpoint(format); assertProperty(vr, "maxDecimalExclusive", hasEntry("maximum", 1.5f)); assertProperty(vr, "maxDecimalExclusive", hasEntry("exclusiveMaximum", true)); - assertProperty(vr, "maxDecimalExclusive", hasEntry("type", "number")); + assertProperty(vr, "maxDecimalExclusive", hasEntry(is("type"), itemOrSingleton("number"))); } @Test(dataProvider = "formatProvider", groups = BEAN_VALIDATION) public void minDecimalInclusiveTest(String format) { ValidatableResponse vr = callEndpoint(format); assertProperty(vr, "minDecimalInclusive", hasEntry("minimum", 3.25f)); - assertProperty(vr, "minDecimalInclusive", hasEntry("type", "number")); + assertProperty(vr, "minDecimalInclusive", hasEntry(is("type"), itemOrSingleton("number"))); } @Test(dataProvider = "formatProvider", groups = BEAN_VALIDATION) @@ -116,7 +118,7 @@ public void minDecimalExclusiveTest(String format) { ValidatableResponse vr = callEndpoint(format); assertProperty(vr, "minDecimalExclusive", hasEntry("minimum", 3.25f)); assertProperty(vr, "minDecimalExclusive", hasEntry("exclusiveMinimum", true)); - assertProperty(vr, "minDecimalExclusive", hasEntry("type", "number")); + assertProperty(vr, "minDecimalExclusive", hasEntry(is("type"), itemOrSingleton("number"))); } @Test(dataProvider = "formatProvider", groups = BEAN_VALIDATION) @@ -180,7 +182,7 @@ public void parameterTest(String format) { ValidatableResponse vr = callEndpoint(format); String schemaPath = dereference(vr, "paths.'/parameter/{test}'.post.parameters[0]", "schema"); vr.body(schemaPath, hasEntry("maxLength", 6)); - vr.body(schemaPath, hasEntry("type", "string")); + vr.body(schemaPath, hasEntry(is("type"), itemOrSingleton("string"))); } /** diff --git a/tck/src/main/java/org/eclipse/microprofile/openapi/tck/utils/TCKMatchers.java b/tck/src/main/java/org/eclipse/microprofile/openapi/tck/utils/TCKMatchers.java index b819359a..924f80be 100644 --- a/tck/src/main/java/org/eclipse/microprofile/openapi/tck/utils/TCKMatchers.java +++ b/tck/src/main/java/org/eclipse/microprofile/openapi/tck/utils/TCKMatchers.java @@ -15,12 +15,16 @@ */ package org.eclipse.microprofile.openapi.tck.utils; +import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.comparator.ComparatorMatcherBuilder.comparedBy; import java.math.BigDecimal; +import java.util.Collection; import java.util.Comparator; +import org.hamcrest.Description; import org.hamcrest.Matcher; +import org.hamcrest.TypeSafeDiagnosingMatcher; public final class TCKMatchers { @@ -55,4 +59,60 @@ private TCKMatchers() { public static Matcher comparesEqualToNumber(Number expected) { return comparedBy(NUMERIC_COMPARATOR).comparesEqualTo(expected); } + + /** + * Creates a matcher which matches an item or a {@link Collection} containing just that item + * + * @param itemMatcher + * the matcher for the item + * @return the matcher + */ + public static Matcher itemOrSingleton(Matcher itemMatcher) { + return new ItemOrSingletonMatcher(itemMatcher); + } + + /** + * Creates a matcher which matches an item or a {@link Collection} containing just that item + * + * @param item + * the item + * @return the matcher + */ + public static Matcher itemOrSingleton(Object item) { + return itemOrSingleton(equalTo(item)); + } + + + public static class ItemOrSingletonMatcher extends TypeSafeDiagnosingMatcher { + + private Matcher baseMatcher; + + public ItemOrSingletonMatcher(Matcher baseMatcher) { + super(Object.class); + this.baseMatcher = baseMatcher; + } + + @Override + public void describeTo(Description description) { + description.appendText("An item or singleton list containing ").appendDescriptionOf(baseMatcher); + } + + @Override + protected boolean matchesSafely(Object item, Description mismatchDescription) { + if (item instanceof Collection) { + Collection collection = (Collection) item; + if (collection.size() != 1) { + mismatchDescription.appendText("object is a collection of size ").appendValue(collection.size()); + return false; + } + item = collection.iterator().next(); + } + + boolean result = baseMatcher.matches(item); + if (!result) { + baseMatcher.describeMismatch(item, mismatchDescription); + } + return result; + } + } } From 1e1442ae9225b99c271dfbae20aeb8aac100c52b Mon Sep 17 00:00:00 2001 From: Andrew Rouse Date: Tue, 13 Feb 2024 13:07:23 +0000 Subject: [PATCH 12/25] Upate existing TCK for Schema.nullable --- .../org/eclipse/microprofile/openapi/tck/AirlinesAppTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tck/src/main/java/org/eclipse/microprofile/openapi/tck/AirlinesAppTest.java b/tck/src/main/java/org/eclipse/microprofile/openapi/tck/AirlinesAppTest.java index 39551bba..877e514b 100644 --- a/tck/src/main/java/org/eclipse/microprofile/openapi/tck/AirlinesAppTest.java +++ b/tck/src/main/java/org/eclipse/microprofile/openapi/tck/AirlinesAppTest.java @@ -42,6 +42,7 @@ import java.util.ArrayList; import java.util.List; +import org.hamcrest.Matchers; import org.hamcrest.collection.IsMapWithSize; import org.jboss.arquillian.container.test.api.Deployment; import org.jboss.shrinkwrap.api.ShrinkWrap; @@ -716,7 +717,7 @@ public void testSchema(String type) { // Array properties String createSchema = "paths.'/user/createWithArray'.post.requestBody.content.'application/json'.schema"; - vr.body(createSchema + ".nullable", equalTo(true)); + vr.body(createSchema + ".type", containsInAnyOrder("array", "null")); vr.body(createSchema + ".writeOnly", equalTo(true)); vr.body(createSchema + ".maxItems", equalTo(20)); vr.body(createSchema + ".minItems", equalTo(2)); From 00700d506b4acb3c80cf9f4379693e84c270b5f4 Mon Sep 17 00:00:00 2001 From: Andrew Rouse Date: Tue, 13 Feb 2024 14:32:17 +0000 Subject: [PATCH 13/25] Update TCKs for Schema.exclusiveMinimum|Maximum exclusiveMinimum and exclusiveMaximum are now standalone numeric properties, rather than boolean properties interpreted in conjunction with minimum and maximum. --- .../openapi/tck/PetStoreAppTest.java | 8 ++------ .../beanvalidation/BeanValidationTest.java | 20 +++++++++++-------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/tck/src/main/java/org/eclipse/microprofile/openapi/tck/PetStoreAppTest.java b/tck/src/main/java/org/eclipse/microprofile/openapi/tck/PetStoreAppTest.java index 11fc7757..024856f1 100644 --- a/tck/src/main/java/org/eclipse/microprofile/openapi/tck/PetStoreAppTest.java +++ b/tck/src/main/java/org/eclipse/microprofile/openapi/tck/PetStoreAppTest.java @@ -61,14 +61,10 @@ public void testSchema(String type) { vr.body("paths.'/store/order/{orderId}'.get.responses.'599'.schema", nullValue()); // Numerical properties - vr.body("paths.'/pet/{petId}'.get.parameters.find{ it.name == 'petId' }.schema.maximum", - comparesEqualToNumber(101.0)); vr.body("paths.'/pet/{petId}'.get.parameters.find{ it.name == 'petId' }.schema.exclusiveMaximum", - equalTo(true)); - vr.body("paths.'/pet/{petId}'.get.parameters.find{ it.name == 'petId' }.schema.minimum", - comparesEqualToNumber(9)); + comparesEqualToNumber(101.0)); vr.body("paths.'/pet/{petId}'.get.parameters.find{ it.name == 'petId' }.schema.exclusiveMinimum", - equalTo(true)); + comparesEqualToNumber(9)); vr.body("paths.'/pet/{petId}'.get.parameters.find{ it.name == 'petId' }.schema.multipleOf", comparesEqualToNumber(10)); diff --git a/tck/src/main/java/org/eclipse/microprofile/openapi/tck/beanvalidation/BeanValidationTest.java b/tck/src/main/java/org/eclipse/microprofile/openapi/tck/beanvalidation/BeanValidationTest.java index e55a431a..396f3943 100644 --- a/tck/src/main/java/org/eclipse/microprofile/openapi/tck/beanvalidation/BeanValidationTest.java +++ b/tck/src/main/java/org/eclipse/microprofile/openapi/tck/beanvalidation/BeanValidationTest.java @@ -95,14 +95,15 @@ public void sizedMapTest(String format) { public void maxDecimalInclusiveTest(String format) { ValidatableResponse vr = callEndpoint(format); assertProperty(vr, "maxDecimalInclusive", hasEntry("maximum", 1.5f)); + assertProperty(vr, "maxDecimalInclusive", not(hasKey("exclusiveMaximum"))); assertProperty(vr, "maxDecimalInclusive", hasEntry(is("type"), itemOrSingleton("number"))); } @Test(dataProvider = "formatProvider", groups = BEAN_VALIDATION) public void maxDecimalExclusiveTest(String format) { ValidatableResponse vr = callEndpoint(format); - assertProperty(vr, "maxDecimalExclusive", hasEntry("maximum", 1.5f)); - assertProperty(vr, "maxDecimalExclusive", hasEntry("exclusiveMaximum", true)); + assertProperty(vr, "maxDecimalExclusive", hasEntry("exclusiveMaximum", 1.5f)); + assertProperty(vr, "maxDecimalExclusive", not(hasKey("maximum"))); assertProperty(vr, "maxDecimalExclusive", hasEntry(is("type"), itemOrSingleton("number"))); } @@ -110,14 +111,15 @@ public void maxDecimalExclusiveTest(String format) { public void minDecimalInclusiveTest(String format) { ValidatableResponse vr = callEndpoint(format); assertProperty(vr, "minDecimalInclusive", hasEntry("minimum", 3.25f)); + assertProperty(vr, "minDecimalInclusive", not(hasKey("exclusiveMinimum"))); assertProperty(vr, "minDecimalInclusive", hasEntry(is("type"), itemOrSingleton("number"))); } @Test(dataProvider = "formatProvider", groups = BEAN_VALIDATION) public void minDecimalExclusiveTest(String format) { ValidatableResponse vr = callEndpoint(format); - assertProperty(vr, "minDecimalExclusive", hasEntry("minimum", 3.25f)); - assertProperty(vr, "minDecimalExclusive", hasEntry("exclusiveMinimum", true)); + assertProperty(vr, "minDecimalExclusive", hasEntry("exclusiveMinimum", 3.25f)); + assertProperty(vr, "minDecimalExclusive", not(hasKey("minimum"))); assertProperty(vr, "minDecimalExclusive", hasEntry(is("type"), itemOrSingleton("number"))); } @@ -136,27 +138,29 @@ public void minIntTest(String format) { @Test(dataProvider = "formatProvider", groups = BEAN_VALIDATION) public void negativeIntTest(String format) { ValidatableResponse vr = callEndpoint(format); - assertProperty(vr, "negativeInt", hasEntry("maximum", 0)); - assertProperty(vr, "negativeInt", hasEntry("exclusiveMaximum", true)); + assertProperty(vr, "negativeInt", hasEntry("exclusiveMaximum", 0)); + assertProperty(vr, "negativeInt", not(hasKey("maximum"))); } @Test(dataProvider = "formatProvider", groups = BEAN_VALIDATION) public void negativeOrZeroIntTest(String format) { ValidatableResponse vr = callEndpoint(format); assertProperty(vr, "negativeOrZeroInt", hasEntry("maximum", 0)); + assertProperty(vr, "negativeOrZeroInt", not(hasKey("exclusiveMaximum"))); } @Test(dataProvider = "formatProvider", groups = BEAN_VALIDATION) public void positiveIntTest(String format) { ValidatableResponse vr = callEndpoint(format); - assertProperty(vr, "positiveInt", hasEntry("minimum", 0)); - assertProperty(vr, "positiveInt", hasEntry("exclusiveMinimum", true)); + assertProperty(vr, "positiveInt", hasEntry("exclusiveMinimum", 0)); + assertProperty(vr, "positiveInt", not(hasKey("minimum"))); } @Test(dataProvider = "formatProvider", groups = BEAN_VALIDATION) public void positiveOrZeroIntTest(String format) { ValidatableResponse vr = callEndpoint(format); assertProperty(vr, "positiveOrZeroInt", hasEntry("minimum", 0)); + assertProperty(vr, "positiveOrZeroInt", not(hasKey("exclusiveMinimum"))); } @Test(dataProvider = "formatProvider", groups = BEAN_VALIDATION) From 738df493a18a31b26bc7d8c0dcd75ad468a83c18 Mon Sep 17 00:00:00 2001 From: Andrew Rouse Date: Mon, 18 Mar 2024 17:06:48 +0000 Subject: [PATCH 14/25] Update TCKs to allow type to be an array --- .../microprofile/openapi/tck/AirlinesAppTest.java | 4 ++-- .../microprofile/openapi/tck/OASConfigSchemaTest.java | 9 ++++++--- .../microprofile/openapi/tck/utils/TCKMatchers.java | 3 +-- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/tck/src/main/java/org/eclipse/microprofile/openapi/tck/AirlinesAppTest.java b/tck/src/main/java/org/eclipse/microprofile/openapi/tck/AirlinesAppTest.java index 877e514b..96b54ecb 100644 --- a/tck/src/main/java/org/eclipse/microprofile/openapi/tck/AirlinesAppTest.java +++ b/tck/src/main/java/org/eclipse/microprofile/openapi/tck/AirlinesAppTest.java @@ -42,7 +42,6 @@ import java.util.ArrayList; import java.util.List; -import org.hamcrest.Matchers; import org.hamcrest.collection.IsMapWithSize; import org.jboss.arquillian.container.test.api.Deployment; import org.jboss.shrinkwrap.api.ShrinkWrap; @@ -702,7 +701,8 @@ public void testSchema(String type) { vr.body("components.schemas.AirlinesRef.$ref", equalTo("#/components/schemas/Airlines")); vr.body("components.schemas.Airlines.title", equalTo("Airlines")); vr.body("components.schemas.Airlines.x-schema", equalTo("test-schema")); - vr.body("paths.'/bookings'.post.responses.'201'.content.'application/json'.schema.type", itemOrSingleton("string")); + vr.body("paths.'/bookings'.post.responses.'201'.content.'application/json'.schema.type", + itemOrSingleton("string")); vr.body("components.schemas.id.format", equalTo("int32")); vr.body("paths.'/bookings'.post.responses.'201'.content.'application/json'.schema.description", equalTo("id of the new booking")); diff --git a/tck/src/main/java/org/eclipse/microprofile/openapi/tck/OASConfigSchemaTest.java b/tck/src/main/java/org/eclipse/microprofile/openapi/tck/OASConfigSchemaTest.java index e15751b0..e5b51949 100644 --- a/tck/src/main/java/org/eclipse/microprofile/openapi/tck/OASConfigSchemaTest.java +++ b/tck/src/main/java/org/eclipse/microprofile/openapi/tck/OASConfigSchemaTest.java @@ -26,6 +26,7 @@ import java.util.Map; import org.hamcrest.Matcher; +import org.hamcrest.Matchers; import org.jboss.arquillian.container.test.api.Deployment; import org.jboss.shrinkwrap.api.ShrinkWrap; import org.jboss.shrinkwrap.api.spec.WebArchive; @@ -52,12 +53,14 @@ public void testSchemaConfigApplied(String type) { anyOf(epochSecondsSchema(), epochSecondsRef())); } - private Matcher> epochSecondsSchema() { - return allOf(aMapWithSize(4), + private Matcher> epochSecondsSchema() { + return Matchers.>allOf( + aMapWithSize(4), hasEntry("title", "Epoch Seconds"), hasEntry(is("type"), itemOrSingleton("number")), hasEntry("format", "int64"), - hasEntry("description", "Number of seconds from the epoch of 1970-01-01T00:00:00Z")); + hasEntry("description", + "Number of seconds from the epoch of 1970-01-01T00:00:00Z")); } private Matcher> epochSecondsRef() { diff --git a/tck/src/main/java/org/eclipse/microprofile/openapi/tck/utils/TCKMatchers.java b/tck/src/main/java/org/eclipse/microprofile/openapi/tck/utils/TCKMatchers.java index 924f80be..68047270 100644 --- a/tck/src/main/java/org/eclipse/microprofile/openapi/tck/utils/TCKMatchers.java +++ b/tck/src/main/java/org/eclipse/microprofile/openapi/tck/utils/TCKMatchers.java @@ -70,7 +70,7 @@ public static Matcher comparesEqualToNumber(Number expected) { public static Matcher itemOrSingleton(Matcher itemMatcher) { return new ItemOrSingletonMatcher(itemMatcher); } - + /** * Creates a matcher which matches an item or a {@link Collection} containing just that item * @@ -82,7 +82,6 @@ public static Matcher itemOrSingleton(Object item) { return itemOrSingleton(equalTo(item)); } - public static class ItemOrSingletonMatcher extends TypeSafeDiagnosingMatcher { private Matcher baseMatcher; From da4400f3f4fb92264f7bf36c62cf9556849e53d6 Mon Sep 17 00:00:00 2001 From: Andrew Rouse Date: Tue, 2 Apr 2024 17:30:21 +0100 Subject: [PATCH 15/25] Improve error reporting in ModelConstructionTest The exception type and stack-trace is important here. --- .../microprofile/openapi/tck/ModelConstructionTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tck/src/main/java/org/eclipse/microprofile/openapi/tck/ModelConstructionTest.java b/tck/src/main/java/org/eclipse/microprofile/openapi/tck/ModelConstructionTest.java index aadb17d4..af63cb2d 100644 --- a/tck/src/main/java/org/eclipse/microprofile/openapi/tck/ModelConstructionTest.java +++ b/tck/src/main/java/org/eclipse/microprofile/openapi/tck/ModelConstructionTest.java @@ -166,7 +166,7 @@ public Object invokeGetter(Object target) { try { return getter.invoke(target); } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { - fail("Invocation of getter method \"" + getter.getName() + "\" failed: " + e.getMessage()); + fail("Invocation of getter method \"" + getter.getName() + "\" failed: " + e.getMessage(), e); throw new RuntimeException(e); } } @@ -174,7 +174,7 @@ public void invokeSetter(Object target, Object value) { try { setter.invoke(target, value); } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { - fail("Invocation of setter method \"" + setter.getName() + "\" failed: " + e.getMessage()); + fail("Invocation of setter method \"" + setter.getName() + "\" failed: " + e.getMessage(), e); throw new RuntimeException(e); } } @@ -182,7 +182,7 @@ public Object invokeBuilder(Object target, Object value) { try { return builder.invoke(target, value); } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { - fail("Invocation of builder method \"" + builder.getName() + "\" failed: " + e.getMessage()); + fail("Invocation of builder method \"" + builder.getName() + "\" failed: " + e.getMessage(), e); throw new RuntimeException(e); } } From 0947f0c013e05d07fb382cc66503d1d8b78dccad Mon Sep 17 00:00:00 2001 From: Andrew Rouse Date: Tue, 2 Apr 2024 17:41:47 +0100 Subject: [PATCH 16/25] Update boolean schema tests Tests for Schema.getAdditionalPropertiesBoolean and getAdditionalPropertiesSchema. --- .../openapi/tck/ModelConstructionTest.java | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/tck/src/main/java/org/eclipse/microprofile/openapi/tck/ModelConstructionTest.java b/tck/src/main/java/org/eclipse/microprofile/openapi/tck/ModelConstructionTest.java index af63cb2d..ab076716 100644 --- a/tck/src/main/java/org/eclipse/microprofile/openapi/tck/ModelConstructionTest.java +++ b/tck/src/main/java/org/eclipse/microprofile/openapi/tck/ModelConstructionTest.java @@ -999,16 +999,23 @@ public void schemaTest() { checkSameObject(ap, s.getAdditionalPropertiesSchema()); assertEquals(s.getAdditionalPropertiesBoolean(), null, "AdditionalProperties (Boolean type) is expected to be null"); + checkSameObject(s, s.additionalPropertiesBoolean(Boolean.TRUE)); assertEquals(s.getAdditionalPropertiesBoolean(), Boolean.TRUE, "AdditionalProperties (Boolean type) is expected to be true"); - assertEquals(s.getAdditionalPropertiesSchema(), null, - "AdditionalProperties (Schema type) is expected to be null"); + Schema s2 = s.getAdditionalPropertiesSchema(); + assertNotNull(s2, "AdditionalProperties (Schema type) is expected to be non-null"); + assertEquals(s2.getBooleanSchema(), Boolean.TRUE, + "AdditionalProperties (Schema type) is expected to return a boolean-true schema"); + s.setAdditionalPropertiesBoolean(Boolean.FALSE); assertEquals(s.getAdditionalPropertiesBoolean(), Boolean.FALSE, "AdditionalProperties (Boolean type) is expected to be false"); - assertEquals(s.getAdditionalPropertiesSchema(), null, - "AdditionalProperties (Schema type) is expected to be null"); + s2 = s.getAdditionalPropertiesSchema(); + assertNotNull(s2, "AdditionalProperties (Schema type) is expected to be non-null"); + assertEquals(s2.getBooleanSchema(), Boolean.FALSE, + "AdditionalProperties (Schema type) is expected to return a boolean-false schema"); + s.setAdditionalPropertiesSchema(null); assertEquals(s.getAdditionalPropertiesBoolean(), null, "AdditionalProperties (Boolean type) is expected to be null"); From 56d5a85827b7aa12f6e7f94b441115badaa99cda Mon Sep 17 00:00:00 2001 From: Andrew Rouse Date: Tue, 2 Apr 2024 17:43:03 +0100 Subject: [PATCH 17/25] Set constructible properties back to null This avoids conflicts between mutually exclusive properties now present in Schema. If setBooleanSchema is called with a non-null value, other methods may fail. --- .../eclipse/microprofile/openapi/tck/ModelConstructionTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/tck/src/main/java/org/eclipse/microprofile/openapi/tck/ModelConstructionTest.java b/tck/src/main/java/org/eclipse/microprofile/openapi/tck/ModelConstructionTest.java index ab076716..433ac413 100644 --- a/tck/src/main/java/org/eclipse/microprofile/openapi/tck/ModelConstructionTest.java +++ b/tck/src/main/java/org/eclipse/microprofile/openapi/tck/ModelConstructionTest.java @@ -1531,6 +1531,7 @@ private void processConstructibleProperty(Constructible o, Property p, Class "\" is expected to be equal to the value that was set."); } } + p.invokeSetter(o, null); } // Returns instances for testing getter, setter and builder methods. From 0f363150ffa052d60bd9dbcdedb6fcb3bfcd68b4 Mon Sep 17 00:00:00 2001 From: Andrew Rouse Date: Tue, 2 Apr 2024 17:53:13 +0100 Subject: [PATCH 18/25] Remove use of wrapper-type constructors These constructors are deprecated and cause problems when the model tests call assertSameInstance. --- .../openapi/tck/ModelConstructionTest.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tck/src/main/java/org/eclipse/microprofile/openapi/tck/ModelConstructionTest.java b/tck/src/main/java/org/eclipse/microprofile/openapi/tck/ModelConstructionTest.java index 433ac413..9d1c88bd 100644 --- a/tck/src/main/java/org/eclipse/microprofile/openapi/tck/ModelConstructionTest.java +++ b/tck/src/main/java/org/eclipse/microprofile/openapi/tck/ModelConstructionTest.java @@ -1554,21 +1554,21 @@ private Object getInstanceOf(Class clazz, boolean alternateEnumValue) { } else if (clazz == String.class) { return new String("value"); } else if (clazz == Boolean.class || clazz == Boolean.TYPE) { - return new Boolean(true); + return Boolean.valueOf(true); } else if (clazz == Byte.class || clazz == Byte.TYPE) { - return new Byte((byte) 1); + return Byte.valueOf((byte) 1); } else if (clazz == Short.class || clazz == Short.TYPE) { - return new Short((short) 1); + return Short.valueOf((short) 1); } else if (clazz == Integer.class || clazz == Integer.TYPE) { - return new Integer(1); + return Integer.valueOf(1); } else if (clazz == Long.class || clazz == Long.TYPE) { - return new Long(1L); + return Long.valueOf(1L); } else if (clazz == Float.class || clazz == Float.TYPE) { - return new Float(1); + return Float.valueOf(1); } else if (clazz == Double.class || clazz == Double.TYPE) { - return new Double(1); + return Double.valueOf(1); } else if (clazz == Character.class || clazz == Character.TYPE) { - return new Character('a'); + return Character.valueOf('a'); } else if (clazz == BigInteger.class) { return new BigInteger("1"); } else if (clazz == BigDecimal.class) { From 6b6e181e3c217c5179273a34c0fc4a5c7891f09b Mon Sep 17 00:00:00 2001 From: Andrew Rouse Date: Wed, 3 Apr 2024 15:17:11 +0100 Subject: [PATCH 19/25] TCKs for new Schema List and Map properties --- .../openapi/tck/ModelConstructionTest.java | 86 ++++++++++++++++++- 1 file changed, 85 insertions(+), 1 deletion(-) diff --git a/tck/src/main/java/org/eclipse/microprofile/openapi/tck/ModelConstructionTest.java b/tck/src/main/java/org/eclipse/microprofile/openapi/tck/ModelConstructionTest.java index 9d1c88bd..1dba83f5 100644 --- a/tck/src/main/java/org/eclipse/microprofile/openapi/tck/ModelConstructionTest.java +++ b/tck/src/main/java/org/eclipse/microprofile/openapi/tck/ModelConstructionTest.java @@ -1131,7 +1131,91 @@ public void schemaTest() { checkListEntry(s.getRequired(), required); final String otherRequiredValue = new String("otherRequired"); - checkListImmutable(s, Schema::getEnumeration, otherRequiredValue); + checkListImmutable(s, Schema::getRequired, otherRequiredValue); + + final String dependentSchemaKey = "myDependentSchemaKey"; + final Schema dependentSchemaValue = createConstructibleInstance(Schema.class); + checkSameObject(s, s.addDependentSchema(dependentSchemaKey, dependentSchemaValue)); + checkMapEntry(s.getDependentSchemas(), dependentSchemaKey, dependentSchemaValue); + assertEquals(s.getDependentSchemas().size(), 1, "The map is expected to contain one entry."); + s.removeDependentSchema(dependentSchemaKey); + assertEquals(s.getDependentSchemas().size(), 0, "The map is expected to be empty."); + + final String dependentSchemaKey2 = "myDependentSchemaKey2"; + final Schema dependentSchemaValue2 = createConstructibleInstance(Schema.class); + s.setDependentSchemas(Collections.singletonMap(dependentSchemaKey2, dependentSchemaValue2)); + checkMapEntry(s.getDependentSchemas(), dependentSchemaKey2, dependentSchemaValue2); + assertEquals(s.getDependentSchemas().size(), 1, "The map is expected to contain one entry."); + checkSameObject(s, s.addDependentSchema(dependentSchemaKey, dependentSchemaValue)); + checkMapEntry(s.getDependentSchemas(), dependentSchemaKey, dependentSchemaValue); + assertEquals(s.getDependentSchemas().size(), 2, "The map is expected to contain two entries."); + + final Schema otherDependentSchemaValue = createConstructibleInstance(Schema.class); + checkMapImmutable(s, Schema::getDependentSchemas, "otherDependentSchemaKey", otherDependentSchemaValue); + checkNullValueInAdd(s::getDependentSchemas, s::addDependentSchema, "otherDependentSchemaKey", + dependentSchemaValue); + + final Schema prefixItem = createConstructibleInstance(Schema.class); + checkSameObject(s, s.addPrefixItem(prefixItem)); + checkListEntry(s.getPrefixItems(), prefixItem); + assertEquals(s.getPrefixItems().size(), 1, "The list is expected to contain one entry."); + s.removePrefixItem(prefixItem); + assertEquals(s.getPrefixItems().size(), 0, "The list is expected to be empty."); + + final Schema prefixItem2 = createConstructibleInstance(Schema.class); + s.setPrefixItems(Collections.singletonList(prefixItem2)); + assertEquals(s.getPrefixItems().size(), 1, "The list is expected to contain one entry."); + checkListEntry(s.getPrefixItems(), prefixItem2); + checkSameObject(s, s.addPrefixItem(prefixItem)); + assertEquals(s.getPrefixItems().size(), 2, "The list is expected to contain two entries."); + checkListEntry(s.getPrefixItems(), prefixItem); + + final Schema otherPrefixItemValue = createConstructibleInstance(Schema.class); + checkListImmutable(s, Schema::getPrefixItems, otherPrefixItemValue); + + final String patternPropertyKey = "myPatternPropertyKey"; + final Schema patternPropertyValue = createConstructibleInstance(Schema.class); + checkSameObject(s, s.addPatternProperty(patternPropertyKey, patternPropertyValue)); + checkMapEntry(s.getPatternProperties(), patternPropertyKey, patternPropertyValue); + assertEquals(s.getPatternProperties().size(), 1, "The map is expected to contain one entry."); + s.removePatternProperty(patternPropertyKey); + assertEquals(s.getPatternProperties().size(), 0, "The map is expected to be empty."); + + final String patternPropertyKey2 = "myPatternPropertyKey2"; + final Schema patternPropertyValue2 = createConstructibleInstance(Schema.class); + s.setPatternProperties(Collections.singletonMap(patternPropertyKey2, patternPropertyValue2)); + checkMapEntry(s.getPatternProperties(), patternPropertyKey2, patternPropertyValue2); + assertEquals(s.getPatternProperties().size(), 1, "The map is expected to contain one entry."); + checkSameObject(s, s.addPatternProperty(patternPropertyKey, patternPropertyValue)); + checkMapEntry(s.getPatternProperties(), patternPropertyKey, patternPropertyValue); + assertEquals(s.getPatternProperties().size(), 2, "The map is expected to contain two entries."); + + final Schema otherPatternPropertyValue = createConstructibleInstance(Schema.class); + checkMapImmutable(s, Schema::getPatternProperties, "otherPatternPropertyKey", otherPatternPropertyValue); + checkNullValueInAdd(s::getPatternProperties, s::addPatternProperty, "otherPatternPropertyKey", + patternPropertyValue); + + final String dependentRequiredKey = "myDependentRequiredKey"; + final List dependentRequiredValue = Collections.singletonList("myDependentRequired"); + checkSameObject(s, s.addDependentRequired(dependentRequiredKey, dependentRequiredValue)); + checkMapEntry(s.getDependentRequired(), dependentRequiredKey, dependentRequiredValue); + assertEquals(s.getDependentRequired().size(), 1, "The map is expected to contain one entry."); + s.removeDependentRequired(dependentRequiredKey); + assertEquals(s.getDependentRequired().size(), 0, "The map is expected to be empty."); + + final String dependentRequiredKey2 = "myDependentRequiredKey2"; + final List dependentRequiredValue2 = Collections.singletonList("myDependentRequired2"); + s.setDependentRequired(Collections.singletonMap(dependentRequiredKey2, dependentRequiredValue2)); + checkMapEntry(s.getDependentRequired(), dependentRequiredKey2, dependentRequiredValue2); + assertEquals(s.getDependentRequired().size(), 1, "The map is expected to contain one entry."); + checkSameObject(s, s.addDependentRequired(dependentRequiredKey, dependentRequiredValue)); + checkMapEntry(s.getDependentRequired(), dependentRequiredKey, dependentRequiredValue); + assertEquals(s.getDependentRequired().size(), 2, "The map is expected to contain two entries."); + + final List otherDependentRequiredValue = Collections.singletonList("myOtherDependentRequired"); + checkMapImmutable(s, Schema::getDependentRequired, "otherDependentRequiredKey", otherDependentRequiredValue); + checkNullValueInAdd(s::getDependentRequired, s::addDependentRequired, "otherDependentRequiredKey", + dependentRequiredValue); } @Test From 98a9e754f795ff7496e7e15ce4a5ce2ca8f069a6 Mon Sep 17 00:00:00 2001 From: Andrew Rouse Date: Wed, 3 Apr 2024 17:35:52 +0100 Subject: [PATCH 20/25] Schema model: tests for examples and example Test that example and examples do not affect each other. --- .../openapi/tck/ModelConstructionTest.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tck/src/main/java/org/eclipse/microprofile/openapi/tck/ModelConstructionTest.java b/tck/src/main/java/org/eclipse/microprofile/openapi/tck/ModelConstructionTest.java index 1dba83f5..4e8fe145 100644 --- a/tck/src/main/java/org/eclipse/microprofile/openapi/tck/ModelConstructionTest.java +++ b/tck/src/main/java/org/eclipse/microprofile/openapi/tck/ModelConstructionTest.java @@ -20,6 +20,7 @@ // import static org.testng.Assert.assertNotSame; // import static org.testng.Assert.assertSame; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.sameInstance; import static org.testng.Assert.assertEquals; @@ -1022,6 +1023,17 @@ public void schemaTest() { assertEquals(s.getAdditionalPropertiesSchema(), null, "AdditionalProperties (Schema type) is expected to be null"); + s.setExamples(null); + s.setExample("example1"); + assertEquals(s.getExample(), "example1", "Example is expected to be set"); + assertNull(s.getExamples(), "Examples should be null"); + s.setExamples(Arrays.asList("example2", "example3")); + assertEquals(s.getExample(), "example1", "Example should not be affected by settings examples"); + assertThat("Examples should be set", s.getExamples(), contains("example2", "example3")); + s.setExample("example4"); + assertEquals(s.getExample(), "example4", "Example should be set"); + assertThat("Examples should not be affected by example", s.getExamples(), contains("example2", "example3")); + final Schema allOf = createConstructibleInstance(Schema.class); checkSameObject(s, s.addAllOf(allOf)); checkListEntry(s.getAllOf(), allOf); From 26be717c7b013c0289d55b23631ca4bba56d5d7c Mon Sep 17 00:00:00 2001 From: Andrew Rouse Date: Wed, 3 Apr 2024 17:37:37 +0100 Subject: [PATCH 21/25] Schema model: TCKs for property access by name --- .../openapi/tck/ModelConstructionTest.java | 198 ++++++++++++++++++ 1 file changed, 198 insertions(+) diff --git a/tck/src/main/java/org/eclipse/microprofile/openapi/tck/ModelConstructionTest.java b/tck/src/main/java/org/eclipse/microprofile/openapi/tck/ModelConstructionTest.java index 4e8fe145..dd736060 100644 --- a/tck/src/main/java/org/eclipse/microprofile/openapi/tck/ModelConstructionTest.java +++ b/tck/src/main/java/org/eclipse/microprofile/openapi/tck/ModelConstructionTest.java @@ -20,7 +20,9 @@ // import static org.testng.Assert.assertNotSame; // import static org.testng.Assert.assertSame; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.anEmptyMap; import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.empty; import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.sameInstance; import static org.testng.Assert.assertEquals; @@ -41,6 +43,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.function.BiConsumer; import java.util.function.BiFunction; import java.util.function.Function; import java.util.function.Supplier; @@ -991,6 +994,7 @@ public void mediaTypeTest() { checkNullValueInAdd(mt::getExamples, mt::addExample, "otherExample", exampleValue); } + @SuppressWarnings("deprecation") // Testing deprecated Schema methods @Test public void schemaTest() { final Schema s = processConstructible(Schema.class); @@ -1230,6 +1234,200 @@ public void schemaTest() { dependentRequiredValue); } + @SuppressWarnings("deprecation") // Testing deprecated Schema methods + @Test + public void testSchemaArbitraryProperties() { + Schema s = createConstructibleInstance(Schema.class); + + testSchemaProperty(s, "discriminator", Schema::getDiscriminator, Schema::setDiscriminator, + createConstructibleInstance(Discriminator.class)); + testSchemaProperty(s, "title", Schema::getTitle, Schema::setTitle, "test title"); + testSchemaProperty(s, "default", Schema::getDefaultValue, Schema::setDefaultValue, "test"); + testSchemaListProperty(s, "enum", Schema::getEnumeration, Schema::setEnumeration, "a"); + testSchemaProperty(s, "multipleOf", Schema::getMultipleOf, Schema::setMultipleOf, new BigDecimal("3")); + testSchemaProperty(s, "maximum", Schema::getMaximum, Schema::setMaximum, new BigDecimal("3")); + testSchemaProperty(s, "exclusiveMaximum", Schema::getExclusiveMaximum, Schema::setExclusiveMaximum, + new BigDecimal("3")); + testSchemaProperty(s, "minimum", Schema::getMinimum, Schema::setMinimum, new BigDecimal("3")); + testSchemaProperty(s, "exclusiveMinimum", Schema::getExclusiveMinimum, Schema::setExclusiveMinimum, + new BigDecimal("3")); + testSchemaProperty(s, "maxLength", Schema::getMaxLength, Schema::setMaxLength, 17); + testSchemaProperty(s, "minLength", Schema::getMinLength, Schema::setMinLength, 5); + testSchemaProperty(s, "pattern", Schema::getPattern, Schema::setPattern, "[a-z]+"); + testSchemaProperty(s, "maxItems", Schema::getMaxItems, Schema::setMaxItems, 5); + testSchemaProperty(s, "minItems", Schema::getMinItems, Schema::setMinItems, 3); + testSchemaProperty(s, "uniqueItems", Schema::getUniqueItems, Schema::setUniqueItems, true); + testSchemaProperty(s, "maxProperties", Schema::getMaxProperties, Schema::setMaxProperties, 10); + testSchemaProperty(s, "minProperties", Schema::getMinProperties, Schema::setMinProperties, 8); + testSchemaListProperty(s, "required", Schema::getRequired, Schema::setRequired, "propName"); + testSchemaListProperty(s, "type", Schema::getType, Schema::setType, Schema.SchemaType.OBJECT); + testSchemaProperty(s, "not", Schema::getNot, Schema::setNot, createConstructibleInstance(Schema.class)); + testSchemaMapProperty(s, "properties", Schema::getProperties, Schema::setProperties, + createConstructibleInstance(Schema.class)); + testSchemaProperty(s, "additionalProperties", Schema::getAdditionalPropertiesSchema, + Schema::setAdditionalPropertiesSchema, + createConstructibleInstance(Schema.class)); + testSchemaProperty(s, "description", Schema::getDescription, Schema::setDescription, "test schema"); + testSchemaProperty(s, "format", Schema::getFormat, Schema::setFormat, "date-time"); + testSchemaProperty(s, "readOnly", Schema::getReadOnly, Schema::setReadOnly, true); + testSchemaProperty(s, "writeOnly", Schema::getWriteOnly, Schema::setWriteOnly, true); + testSchemaProperty(s, "example", Schema::getExample, Schema::setExample, "test"); + testSchemaProperty(s, "externalDocs", Schema::getExternalDocs, Schema::setExternalDocs, + createConstructibleInstance(ExternalDocumentation.class)); + testSchemaProperty(s, "deprecated", Schema::getDeprecated, Schema::setDeprecated, true); + testSchemaProperty(s, "xml", Schema::getXml, Schema::setXml, createConstructibleInstance(XML.class)); + testSchemaProperty(s, "items", Schema::getItems, Schema::setItems, createConstructibleInstance(Schema.class)); + testSchemaListProperty(s, "allOf", Schema::getAllOf, Schema::setAllOf, + createConstructibleInstance(Schema.class)); + testSchemaListProperty(s, "anyOf", Schema::getAnyOf, Schema::setAnyOf, + createConstructibleInstance(Schema.class)); + testSchemaListProperty(s, "oneOf", Schema::getOneOf, Schema::setOneOf, + createConstructibleInstance(Schema.class)); + testSchemaProperty(s, "$schema", Schema::getSchemaDialect, Schema::setSchemaDialect, "http://test.dialect"); + testSchemaProperty(s, "$comment", Schema::getComment, Schema::setComment, "about this schema"); + testSchemaProperty(s, "if", Schema::getIfSchema, Schema::setIfSchema, + createConstructibleInstance(Schema.class)); + testSchemaProperty(s, "then", Schema::getThenSchema, Schema::setThenSchema, + createConstructibleInstance(Schema.class)); + testSchemaProperty(s, "else", Schema::getElseSchema, Schema::setElseSchema, + createConstructibleInstance(Schema.class)); + testSchemaMapProperty(s, "dependentSchemas", Schema::getDependentSchemas, Schema::setDependentSchemas, + createConstructibleInstance(Schema.class)); + testSchemaListProperty(s, "prefixItems", Schema::getPrefixItems, Schema::setPrefixItems, + createConstructibleInstance(Schema.class)); + testSchemaProperty(s, "contains", Schema::getContains, Schema::setContains, + createConstructibleInstance(Schema.class)); + testSchemaMapProperty(s, "patternProperties", Schema::getPatternProperties, Schema::setPatternProperties, + createConstructibleInstance(Schema.class)); + testSchemaProperty(s, "propertyNames", Schema::getPropertyNames, Schema::setPropertyNames, + createConstructibleInstance(Schema.class)); + testSchemaProperty(s, "unevaluatedItems", Schema::getUnevaluatedItems, Schema::setUnevaluatedItems, + createConstructibleInstance(Schema.class)); + testSchemaProperty(s, "unevaluatedProperties", Schema::getUnevaluatedProperties, + Schema::setUnevaluatedProperties, createConstructibleInstance(Schema.class)); + testSchemaProperty(s, "const", Schema::getConstValue, Schema::setConstValue, "value"); + testSchemaProperty(s, "maxContains", Schema::getMaxContains, Schema::setMaxContains, 5); + testSchemaProperty(s, "minContains", Schema::getMinContains, Schema::setMinContains, 3); + testSchemaMapProperty(s, "dependentRequired", Schema::getDependentRequired, Schema::setDependentRequired, + Arrays.asList("a", "b")); + testSchemaProperty(s, "contentEncoding", Schema::getContentEncoding, Schema::setContentEncoding, "base64"); + testSchemaProperty(s, "contentMediaType", Schema::getContentMediaType, Schema::setContentMediaType, + "test/plain"); + testSchemaProperty(s, "contentSchema", Schema::getContentSchema, Schema::setContentSchema, + createConstructibleInstance(Schema.class)); + testSchemaListProperty(s, "examples", Schema::getExamples, Schema::setExamples, "foo"); + } + + public void testSchemaProperty(Schema testSchema, String name, Function getter, + BiConsumer setter, V testValue) { + // Set with the setter + setter.accept(testSchema, testValue); + assertSame(getter.apply(testSchema), testValue, + "Getter should return the same instance as was set for property " + name); + assertSame(testSchema.get(name), testValue, + "Generic getter should return same instance as was set for property " + name); + + // Clear with the setter + setter.accept(testSchema, null); + assertNull(getter.apply(testSchema), "Getter should return null for property " + name); + assertNull(testSchema.get(name), "Generic access should return null for property " + name); + + // Set with generic access + testSchema.set(name, testValue); + assertSame(getter.apply(testSchema), testValue, + "Getter should return the same instance as was set for property " + name); + assertSame(testSchema.get(name), testValue, + "Generic getter should return same instance as was set for property " + name); + + // Clear with generic access + testSchema.set(name, null); + assertNull(getter.apply(testSchema), "Getter should return null for property " + name); + assertNull(testSchema.get(name), "Generic access should return null for property " + name); + } + + public void testSchemaMapProperty(Schema testSchema, String name, + Function> getter, BiConsumer> setter, + V testValue) { + // Set with the setter + Map testMap = new HashMap<>(); + testMap.put("test1", testValue); + + setter.accept(testSchema, testMap); + testMapFromGetter(() -> getter.apply(testSchema), testMap, name); + testMapFromGetter(() -> testSchema.get(name), testMap, name); + + // Clear with the setter + setter.accept(testSchema, null); + assertNull(getter.apply(testSchema), "Getter should return null for property " + name); + assertNull(testSchema.get(name), "Generic access should return null for property " + name); + + // Set with generic access + testSchema.set(name, testMap); + testMapFromGetter(() -> getter.apply(testSchema), testMap, name); + testMapFromGetter(() -> testSchema.get(name), testMap, name); + + // Clear with generic access + testSchema.set(name, null); + assertNull(getter.apply(testSchema), "Getter should return null for property " + name); + assertNull(testSchema.get(name), "Generic access should return null for property " + name); + } + + private void testMapFromGetter(Supplier getter, Map expected, + String name) { + assertThat("Test error: expected may not be empty", expected, not(anEmptyMap())); + + Object actualObj = getter.get(); + assertEquals(actualObj, expected, "Getter should return value that was set for property " + name); + + // Check that all values are the same instance + Map actualMap = (Map) actualObj; + expected.forEach((k, v) -> { + assertSame(v, actualMap.get(k), + "Getter should return value with same instance for key " + v + " property " + name); + }); + } + + public void testSchemaListProperty(Schema testSchema, String name, + Function> getter, BiConsumer> setter, + V testValue) { + // Set with the setter + List testList = new ArrayList<>(); + testList.add(testValue); + + setter.accept(testSchema, testList); + testListFromGetter(() -> getter.apply(testSchema), testList, name); + testListFromGetter(() -> testSchema.get(name), testList, name); + + // Clear with the setter + setter.accept(testSchema, null); + assertNull(getter.apply(testSchema), "Getter should return null for property " + name); + assertNull(testSchema.get(name), "Generic access should return null for property " + name); + + // Set with generic access + testSchema.set(name, testList); + testListFromGetter(() -> getter.apply(testSchema), testList, name); + testListFromGetter(() -> testSchema.get(name), testList, name); + + // Clear with generic access + testSchema.set(name, null); + assertNull(getter.apply(testSchema), "Getter should return null for property " + name); + assertNull(testSchema.get(name), "Generic access should return null for property " + name); + } + + private void testListFromGetter(Supplier getter, List expected, String name) { + assertThat("Test error: expected may not be empty", expected, not(empty())); + + Object actualObj = getter.get(); + assertEquals(actualObj, expected, "Getter should return value that was set for property " + name); + + // Check that all values are the same instance + List actualList = (List) actualObj; + expected.forEach((expectedV) -> { + assertTrue(actualList.stream().anyMatch((actualV) -> expectedV == actualV), + "Getter should return value containing " + expectedV + " for property " + name); + }); + } + @Test public void xmlTest() { processConstructible(XML.class); From 08957ed49a4373024bb7391b7a35f9bc2913e08b Mon Sep 17 00:00:00 2001 From: Andrew Rouse Date: Fri, 5 Apr 2024 14:58:40 +0100 Subject: [PATCH 22/25] Model TCK: Remove use of deprecated Schema.type --- .../openapi/reader/MyOASModelReaderImpl.java | 31 ++++++++++--------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/tck/src/main/java/org/eclipse/microprofile/openapi/reader/MyOASModelReaderImpl.java b/tck/src/main/java/org/eclipse/microprofile/openapi/reader/MyOASModelReaderImpl.java index 4769b233..e8d89f11 100644 --- a/tck/src/main/java/org/eclipse/microprofile/openapi/reader/MyOASModelReaderImpl.java +++ b/tck/src/main/java/org/eclipse/microprofile/openapi/reader/MyOASModelReaderImpl.java @@ -90,16 +90,16 @@ public OpenAPI buildModel() { .components(OASFactory.createObject(Components.class) .schemas(new HashMap()) .addSchema("Bookings", OASFactory.createObject(Schema.class) - .type(Schema.SchemaType.INTEGER) + .addType(Schema.SchemaType.INTEGER) .title("Bookings") .ref("#/components.schemas.Booking")) .addSchema("Airlines", OASFactory.createObject(Schema.class) - .type(Schema.SchemaType.INTEGER) + .addType(Schema.SchemaType.INTEGER) .title("Airlines")) .addSchema("AirlinesRef", OASFactory.createObject(Schema.class) .ref("#/components/schemas/Airlines")) .addSchema("id", OASFactory.createObject(Schema.class) - .type(Schema.SchemaType.INTEGER) + .addType(Schema.SchemaType.INTEGER) .format("int32")) .responses(new HashMap()) .addResponse("FoundAirlines", OASFactory.createObject(APIResponse.class) @@ -107,13 +107,13 @@ public OpenAPI buildModel() { .content(OASFactory.createObject(Content.class) .addMediaType("application/json", OASFactory.createObject(MediaType.class) .schema(OASFactory.createObject(Schema.class) - .type(Schema.SchemaType.ARRAY))))) + .addType(Schema.SchemaType.ARRAY))))) .addResponse("FoundBookings", OASFactory.createObject(APIResponse.class) .description("Bookings retrieved") .content(OASFactory.createObject(Content.class) .addMediaType("application/json", OASFactory.createObject(MediaType.class) .schema(OASFactory.createObject(Schema.class) - .type(Schema.SchemaType.ARRAY) + .addType(Schema.SchemaType.ARRAY) .ref("#/components.schemas.Booking"))))) .parameters(new HashMap()) .addParameter("departureDate", OASFactory.createObject(Parameter.class) @@ -144,14 +144,14 @@ public OpenAPI buildModel() { .addHeader("Max-Rate", OASFactory.createObject(Header.class) .description("Maximum rate") .schema(OASFactory.createObject(Schema.class) - .type(Schema.SchemaType.INTEGER)) + .addType(Schema.SchemaType.INTEGER)) .required(true) .allowEmptyValue(true) .deprecated(true)) .addHeader("Request-Limit", OASFactory.createObject(Header.class) .description("The number of allowed requests in the current period") .schema(OASFactory.createObject(Schema.class) - .type(Schema.SchemaType.INTEGER))) + .addType(Schema.SchemaType.INTEGER))) .securitySchemes(new HashMap()) .addSecurityScheme("httpTestScheme", OASFactory.createObject(SecurityScheme.class) .description("user security scheme") @@ -218,7 +218,7 @@ public OpenAPI buildModel() { .addMediaType("application/json", OASFactory .createObject(MediaType.class) .schema(OASFactory.createObject(Schema.class) - .type(Schema.SchemaType.ARRAY) + .addType(Schema.SchemaType.ARRAY) .ref("#/components.schemas.Flight"))))) .addAPIResponse("404", OASFactory.createObject(APIResponse.class) .description("No available flights found") @@ -235,7 +235,7 @@ public OpenAPI buildModel() { .allowEmptyValue(true) .description("Airport the customer departs from") .schema(OASFactory.createObject(Schema.class) - .type(Schema.SchemaType.STRING))) + .addType(Schema.SchemaType.STRING))) .addParameter(OASFactory.createObject(Parameter.class) .name("returningDate") .required(true) @@ -243,14 +243,14 @@ public OpenAPI buildModel() { .allowReserved(true) .description("Customer return date") .schema(OASFactory.createObject(Schema.class) - .type(Schema.SchemaType.STRING))) + .addType(Schema.SchemaType.STRING))) .addParameter(OASFactory.createObject(Parameter.class) .name("airportTo") .required(true) .in(Parameter.In.QUERY) .description("Airport the customer returns to") .schema(OASFactory.createObject(Schema.class) - .type(Schema.SchemaType.STRING))) + .addType(Schema.SchemaType.STRING))) .addParameter(OASFactory.createObject(Parameter.class) .name("numberOfAdults") .required(true) @@ -258,7 +258,7 @@ public OpenAPI buildModel() { .description("Number of adults on the flight") .schema(OASFactory.createObject(Schema.class) .minimum(new BigDecimal(0)) - .type(Schema.SchemaType.STRING))) + .addType(Schema.SchemaType.STRING))) .addParameter(OASFactory.createObject(Parameter.class) .name("numberOfChildren") .required(true) @@ -267,7 +267,7 @@ public OpenAPI buildModel() { .description("Number of children on the flight") .schema(OASFactory.createObject(Schema.class) .minimum(new BigDecimal(0)) - .type(Schema.SchemaType.STRING))))) + .addType(Schema.SchemaType.STRING))))) .addPathItem("/modelReader/bookings", OASFactory.createObject(PathItem.class) .GET(OASFactory.createObject(Operation.class) .tags(new ArrayList()) @@ -281,7 +281,7 @@ public OpenAPI buildModel() { .addMediaType("applictaion/json", OASFactory .createObject(MediaType.class) .schema(OASFactory.createObject(Schema.class) - .type(Schema.SchemaType.ARRAY) + .addType(Schema.SchemaType.ARRAY) .ref("#/components.schemas.Booking"))))) .addAPIResponse("404", OASFactory.createObject(APIResponse.class) .description("No bookings found for the user")))) @@ -304,6 +304,7 @@ public OpenAPI buildModel() { .schema(OASFactory.createObject(Schema.class) .title("id") .description("id of the new booking") - .type(Schema.SchemaType.STRING))))))))); + .addType( + Schema.SchemaType.STRING))))))))); } } From 3a835a46e5c24a59f61f7c8c49c108fbe2a86fd4 Mon Sep 17 00:00:00 2001 From: Andrew Rouse Date: Fri, 5 Apr 2024 15:29:29 +0100 Subject: [PATCH 23/25] Schema model: remove type and nullable methods --- .../openapi/models/media/Schema.java | 60 ------------------- 1 file changed, 60 deletions(-) diff --git a/api/src/main/java/org/eclipse/microprofile/openapi/models/media/Schema.java b/api/src/main/java/org/eclipse/microprofile/openapi/models/media/Schema.java index b7b686dd..6a7e45bb 100644 --- a/api/src/main/java/org/eclipse/microprofile/openapi/models/media/Schema.java +++ b/api/src/main/java/org/eclipse/microprofile/openapi/models/media/Schema.java @@ -644,31 +644,6 @@ default Schema type(List types) { */ void removeType(SchemaType type); - /** - * Sets the type property of this Schema instance to a single type. - * - * @param type - * the required type - * @since "4.0" - * @deprecated use {@link #setType(List)} - */ - @Deprecated(since = "4.0") - void setType(SchemaType type); - - /** - * Sets the type property of this Schema instance to a single type. - * - * @param type - * the required type - * @return the current Schema instance - * @deprecated use {@link #setType(List)} - */ - @Deprecated(since = "4.0") - default Schema type(SchemaType type) { - setType(type); - return this; - } - /** * Returns a Schema which describes properties not allowed in objects defined by the current schema. * @@ -893,41 +868,6 @@ default Schema format(String format) { return this; } - /** - * Returns whether the type property allows the object to be {@code null} - * - * @return whether null is allowed - * @deprecated use {@link #getType()} and check if the result contains {@link SchemaType#NULL} - */ - @Deprecated(since = "4.0") - Boolean getNullable(); - - /** - * Updates the type property to either permit or disallow {@code null} - * - * @param nullable - * a boolean value indicating whether this Schema allows a null value. - * @deprecated use {@link #setType(List)}, {@link #addType(SchemaType)}, or {@link #removeType(SchemaType)} to add - * or remove {@link SchemaType#NULL} - */ - @Deprecated(since = "4.0") - void setNullable(Boolean nullable); - - /** - * Sets the nullable property of this Schema instance. Specify true if this Schema will allow null values. - * - * @param nullable - * a boolean value indicating this Schema allows a null value. - * @return the current Schema instance - * @deprecated use {@link #setType(List)}, {@link #addType(SchemaType)}, or {@link #removeType(SchemaType)} to add - * or remove {@link SchemaType#NULL} - */ - @Deprecated(since = "4.0") - default Schema nullable(Boolean nullable) { - setNullable(nullable); - return this; - } - /** * Returns the readOnly property from this Schema instance. * From c0eccb814c9fa6fc333e8a68ce9386645e065502 Mon Sep 17 00:00:00 2001 From: Andrew Rouse Date: Mon, 22 Apr 2024 11:30:07 +0100 Subject: [PATCH 24/25] TCK for a custom schema dialect Test building a schema with a custom dialect in a model reader and ensure it is serialized correctly. --- .../openapi/reader/MyOASModelReaderImpl.java | 61 +++++++++++++++++++ .../openapi/tck/ModelReaderAppTest.java | 49 +++++++++++++++ .../openapi/tck/utils/TCKMatchers.java | 55 +++++++++++++++++ 3 files changed, 165 insertions(+) diff --git a/tck/src/main/java/org/eclipse/microprofile/openapi/reader/MyOASModelReaderImpl.java b/tck/src/main/java/org/eclipse/microprofile/openapi/reader/MyOASModelReaderImpl.java index e8d89f11..45ce98a3 100644 --- a/tck/src/main/java/org/eclipse/microprofile/openapi/reader/MyOASModelReaderImpl.java +++ b/tck/src/main/java/org/eclipse/microprofile/openapi/reader/MyOASModelReaderImpl.java @@ -15,9 +15,14 @@ */ package org.eclipse.microprofile.openapi.reader; +import static java.util.Collections.emptyMap; + import java.math.BigDecimal; +import java.math.BigInteger; +import java.time.DayOfWeek; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import org.eclipse.microprofile.openapi.OASFactory; @@ -38,11 +43,13 @@ import org.eclipse.microprofile.openapi.models.media.MediaType; import org.eclipse.microprofile.openapi.models.media.Schema; import org.eclipse.microprofile.openapi.models.parameters.Parameter; +import org.eclipse.microprofile.openapi.models.parameters.Parameter.In; import org.eclipse.microprofile.openapi.models.parameters.RequestBody; import org.eclipse.microprofile.openapi.models.responses.APIResponse; import org.eclipse.microprofile.openapi.models.responses.APIResponses; import org.eclipse.microprofile.openapi.models.security.SecurityRequirement; import org.eclipse.microprofile.openapi.models.security.SecurityScheme; +import org.eclipse.microprofile.openapi.models.security.SecurityScheme.Type; import org.eclipse.microprofile.openapi.models.servers.Server; import org.eclipse.microprofile.openapi.models.servers.ServerVariable; import org.eclipse.microprofile.openapi.models.tags.Tag; @@ -101,6 +108,60 @@ public OpenAPI buildModel() { .addSchema("id", OASFactory.createObject(Schema.class) .addType(Schema.SchemaType.INTEGER) .format("int32")) + .addSchema("custom", OASFactory.createSchema() + .schemaDialect("http://example.com/myCustomSchema") + .set("shortKey", (short) 1) + .set("intKey", 2) + .set("longKey", 3L) + .set("booleanKey", true) + .set("charKey", 'a') + .set("stringKey", "string") + .set("floatKey", 3.5f) + .set("doubleKey", 3.5d) + .set("bigDecimalKey", new BigDecimal("3.5")) + .set("bigIntegerKey", new BigInteger("7")) + .set("extDocKey", OASFactory.createExternalDocumentation().description("test")) + .set("operationKey", OASFactory.createOperation().description("test")) + .set("pathItemKey", OASFactory.createPathItem().description("test")) + .set("pathsKey", OASFactory.createPaths() + .addPathItem("test", OASFactory.createPathItem().description("test"))) + .set("callbackKey", OASFactory.createCallback() + .addPathItem("test", OASFactory.createPathItem().description("test"))) + .set("exampleKey", OASFactory.createExample().value("test")) + .set("headerKey", OASFactory.createHeader().description("test")) + .set("contactKey", OASFactory.createContact().name("test")) + .set("infoKey", OASFactory.createInfo().title("test").version("1.0")) + .set("licenseKey", OASFactory.createLicense().name("test")) + .set("linkKey", OASFactory.createLink().operationId("getTestFlights")) + .set("contentKey", OASFactory.createContent() + .addMediaType("test", OASFactory.createMediaType().example("test"))) + .set("discriminatorKey", OASFactory.createDiscriminator().propertyName("test")) + .set("schemaKey", OASFactory.createSchema().title("test")) + .set("xmlKey", OASFactory.createXML().name("test")) + .set("parameterKey", OASFactory.createParameter().name("test").in(In.PATH)) + .set("requestBodyKey", OASFactory.createRequestBody() + .content(OASFactory.createContent() + .addMediaType("test", OASFactory.createMediaType().example("test")))) + .set("apiResponseKey", OASFactory.createAPIResponse().description("test")) + .set("apiResponsesKey", OASFactory.createAPIResponses() + .addAPIResponse("200", OASFactory.createAPIResponse().description("test"))) + .set("oAuthFlowKey", + OASFactory.createOAuthFlow().authorizationUrl("http://example.com")) + .set("oAuthFlowsKey", OASFactory.createOAuthFlows().implicit( + OASFactory.createOAuthFlow().authorizationUrl("http://example.com") + .scopes(emptyMap()))) + .set("securityReqKey", OASFactory.createSecurityRequirement().addScheme("test")) + .set("securitySchemeKey", OASFactory.createSecurityScheme() + .type(Type.HTTP) + .scheme("Basic")) + .set("serverKey", OASFactory.createServer().url("http://example.com")) + .set("serverVarKey", OASFactory.createServerVariable().defaultValue("test")) + .set("tagKey", OASFactory.createTag().name("test")) + .set("enumKey", DayOfWeek.MONDAY) + .set("listKey", Arrays.asList( + "test", + OASFactory.createXML().name("test"))) + .set("mapKey", Collections.singletonMap("test", DayOfWeek.THURSDAY))) .responses(new HashMap()) .addResponse("FoundAirlines", OASFactory.createObject(APIResponse.class) .description("successfully found airlines") diff --git a/tck/src/main/java/org/eclipse/microprofile/openapi/tck/ModelReaderAppTest.java b/tck/src/main/java/org/eclipse/microprofile/openapi/tck/ModelReaderAppTest.java index 6b240cb5..7c638c72 100644 --- a/tck/src/main/java/org/eclipse/microprofile/openapi/tck/ModelReaderAppTest.java +++ b/tck/src/main/java/org/eclipse/microprofile/openapi/tck/ModelReaderAppTest.java @@ -17,11 +17,14 @@ package org.eclipse.microprofile.openapi.tck; import static org.eclipse.microprofile.openapi.tck.utils.TCKMatchers.itemOrSingleton; +import static org.eclipse.microprofile.openapi.tck.utils.TCKMatchers.number; import static org.hamcrest.Matchers.both; import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.equalToIgnoringCase; +import static org.hamcrest.Matchers.hasItem; import static org.hamcrest.Matchers.hasItems; import static org.hamcrest.Matchers.hasKey; import static org.hamcrest.Matchers.hasSize; @@ -218,6 +221,52 @@ public void testSchema(String type) { equalTo("id of the new booking")); } + @Test(dataProvider = "formatProvider") + public void testSchemaCustomProperties(String type) { + ValidatableResponse vr = callEndpoint(type); + vr.body("components.schemas.custom.$schema", equalTo("http://example.com/myCustomSchema")); + vr.body("components.schemas.custom.shortKey", number(1)); + vr.body("components.schemas.custom.intKey", number(2)); + vr.body("components.schemas.custom.longKey", number(3)); + vr.body("components.schemas.custom.booleanKey", equalTo(true)); + vr.body("components.schemas.custom.charKey", equalTo("a")); + vr.body("components.schemas.custom.stringKey", equalTo("string")); + vr.body("components.schemas.custom.floatKey", number(3.5)); + vr.body("components.schemas.custom.doubleKey", number(3.5)); + vr.body("components.schemas.custom.bigDecimalKey", number(3.5)); + vr.body("components.schemas.custom.bigIntegerKey", number(7)); + vr.body("components.schemas.custom.extDocKey.description", equalTo("test")); + vr.body("components.schemas.custom.operationKey.description", equalTo("test")); + vr.body("components.schemas.custom.pathItemKey.description", equalTo("test")); + vr.body("components.schemas.custom.pathsKey.test.description", equalTo("test")); + vr.body("components.schemas.custom.callbacKey.description", equalTo("test")); + vr.body("components.schemas.custom.exampleKey.value", equalTo("test")); + vr.body("components.schemas.custom.headerKey.description", equalTo("test")); + vr.body("components.schemas.custom.contactKey.name", equalTo("test")); + vr.body("components.schemas.custom.infoKey.title", equalTo("test")); + vr.body("components.schemas.custom.licenseKey.name", equalTo("test")); + vr.body("components.schemas.custom.linkKey.operationId", equalTo("test")); + vr.body("components.schemas.custom.contentKey.test.example", equalTo("test")); + vr.body("components.schemas.custom.discriminatorKey.propertyName", equalTo("test")); + vr.body("components.schemas.custom.schemaKey.title", equalTo("test")); + vr.body("components.schemas.custom.xmlKey.name", equalTo("test")); + vr.body("components.schemas.custom.parameterKey.name", equalTo("test")); + vr.body("components.schemas.custom.requestBodyKey.content.test.example", equalTo("test")); + vr.body("components.schemas.custom.apiResponseKey.description", equalTo("test")); + vr.body("components.schemas.custom.apiResponsesKey.200.description", equalTo("test")); + vr.body("components.schemas.custom.oAuthFlowKey.authorizationUrl", equalTo("http://example.com")); + vr.body("components.schemas.custom.oAuthFlowsKey.implicit.authorizationUrl", equalTo("http://example.com")); + vr.body("components.schemas.custom.securityReqKey.scheme", contains("test")); + vr.body("components.schemas.custom.securitySchemeKey.type", equalTo("http")); + vr.body("components.schemas.custom.serverKey.url", equalTo("http://example.com")); + vr.body("components.schemas.custom.serverVarKey.default", equalTo("test")); + vr.body("components.schemas.custom.tagKey.name", equalTo("test")); + vr.body("components.schemas.custom.enumKey", equalToIgnoringCase("MONDAY")); + vr.body("components.schemas.custom.listKey", hasItem("test")); + vr.body("components.schemas.custom.listKey.name", hasItem("test")); + vr.body("components.schemas.custom.mapKey.test", equalToIgnoringCase("MONDAY")); + } + @Test(dataProvider = "formatProvider") public void testExampleObject(String type) { ValidatableResponse vr = callEndpoint(type); diff --git a/tck/src/main/java/org/eclipse/microprofile/openapi/tck/utils/TCKMatchers.java b/tck/src/main/java/org/eclipse/microprofile/openapi/tck/utils/TCKMatchers.java index 68047270..61e12070 100644 --- a/tck/src/main/java/org/eclipse/microprofile/openapi/tck/utils/TCKMatchers.java +++ b/tck/src/main/java/org/eclipse/microprofile/openapi/tck/utils/TCKMatchers.java @@ -19,6 +19,7 @@ import static org.hamcrest.comparator.ComparatorMatcherBuilder.comparedBy; import java.math.BigDecimal; +import java.math.BigInteger; import java.util.Collection; import java.util.Comparator; @@ -82,6 +83,20 @@ public static Matcher itemOrSingleton(Object item) { return itemOrSingleton(equalTo(item)); } + /** + * Creates a matcher which matches numbers based on their numeric value without considering their type. + *

+ * Both the expected and actual value are converted to {@link BigDecimal} and compared using + * {@link BigDecimal#compareTo(BigDecimal) compareTo}. + * + * @param number + * the expected number + * @return the matcher + */ + public static Matcher number(Number number) { + return new NumericEqualityMatcher(number); + } + public static class ItemOrSingletonMatcher extends TypeSafeDiagnosingMatcher { private Matcher baseMatcher; @@ -114,4 +129,44 @@ protected boolean matchesSafely(Object item, Description mismatchDescription) { return result; } } + + public static class NumericEqualityMatcher extends TypeSafeDiagnosingMatcher { + + private BigDecimal expected; + + public NumericEqualityMatcher(Number expected) { + this.expected = toBigDecimal(expected); + } + + @Override + public void describeTo(Description desc) { + desc.appendText("A number equal to ").appendValue(expected); + } + + @Override + protected boolean matchesSafely(Number item, Description mismatchDescription) { + BigDecimal actual = toBigDecimal(item); + mismatchDescription.appendText("was: ").appendValue(item); + return expected.compareTo(actual) == 0; + } + + private static BigDecimal toBigDecimal(Number number) { + if (number instanceof Integer) { + return new BigDecimal((Integer) number); + } else if (number instanceof Short) { + return new BigDecimal((Short) number); + } else if (number instanceof Long) { + return new BigDecimal((Long) number); + } else if (number instanceof Float) { + return new BigDecimal((Float) number); + } else if (number instanceof Double) { + return new BigDecimal((Double) number); + } else if (number instanceof BigInteger) { + return new BigDecimal((BigInteger) number); + } else { + return new BigDecimal(number.doubleValue()); + } + } + + } } From e959eb49b66c42adfd1e7b902c560d8330b143ca Mon Sep 17 00:00:00 2001 From: Andrew Rouse Date: Mon, 22 Apr 2024 16:39:35 +0100 Subject: [PATCH 25/25] Test custom schema dialect in a static document --- .../tck/StaticDocumentCustomDialectTest.java | 51 +++++++++++++++++++ tck/src/main/resources/customDialect.yaml | 31 +++++++++++ 2 files changed, 82 insertions(+) create mode 100644 tck/src/main/java/org/eclipse/microprofile/openapi/tck/StaticDocumentCustomDialectTest.java create mode 100644 tck/src/main/resources/customDialect.yaml diff --git a/tck/src/main/java/org/eclipse/microprofile/openapi/tck/StaticDocumentCustomDialectTest.java b/tck/src/main/java/org/eclipse/microprofile/openapi/tck/StaticDocumentCustomDialectTest.java new file mode 100644 index 00000000..e4ec2f46 --- /dev/null +++ b/tck/src/main/java/org/eclipse/microprofile/openapi/tck/StaticDocumentCustomDialectTest.java @@ -0,0 +1,51 @@ +/** + * Copyright (c) 2024 Contributors to the Eclipse Foundation + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License 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 org.eclipse.microprofile.openapi.tck; + +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.startsWith; + +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.spec.WebArchive; +import org.testng.annotations.Test; + +import io.restassured.response.ValidatableResponse; + +/** + * Test that a static document can contain a schema with a custom dialect + */ +public class StaticDocumentCustomDialectTest extends AppTestBase { + + @Deployment(name = "customdialect", testable = false) + public static WebArchive createDeployment() { + return ShrinkWrap.create(WebArchive.class, "customdialect.war") + .addAsManifestResource("customDialect.yaml", "openapi.yaml"); + } + + @Test(dataProvider = "formatProvider") + public void testStaticDocumentCustomDialect(String type) { + ValidatableResponse vr = callEndpoint(type); + + vr.body("openapi", startsWith("3.1.")); + + final String schemaPath = "paths.'/test'.get.responses.'200'.content.'application/json'.schema"; + vr.body(schemaPath + ".$schema", equalTo("http://example.com/custom")); + vr.body(schemaPath + ".foo", equalTo("bar")); + vr.body(schemaPath + ".baz", equalTo("qux")); + } + +} diff --git a/tck/src/main/resources/customDialect.yaml b/tck/src/main/resources/customDialect.yaml new file mode 100644 index 00000000..e6d80a43 --- /dev/null +++ b/tck/src/main/resources/customDialect.yaml @@ -0,0 +1,31 @@ +# Copyright (c) 2024 Contributors to the Eclipse Foundation +#

+# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +#

+# http://www.apache.org/licenses/LICENSE-2.0 +#

+# Unless required by applicable law or agreed to in writing, software +# distributed under the License 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. + +openapi: 3.1.0 +info: + title: Custom dialect schema example + version: 1.0.0 +paths: + /test: + get: + description: Returns data in a custom schema dialect + responses: + '200': + content: + application/json: + schema: + $schema: http://example.com/custom + description: This is an example of a completely custom schema which should be passed through untouched + foo: bar + baz: qux \ No newline at end of file