Repository: eclipse/microprofile-open-api (java)

Issue:
TCK tests logging "Static configuration methods can cause unexpected behavior."
At the start of the TCK run, we see multiple occurrences of the following warning [1]. We should consider making the `@BeforeClass` method non-static (for a micro release) or looking into another approach like suggested in testng-team/testng#2554 (for the next minor release).

```
[2024-10-15 15:15:24] [WARN   ] org.testng.log4testng.Logger warn Detected a static method [org.eclipse.microprofile.openapi.tck.AppTestBase.configureRestAssured()]. Static configuration methods can cause unexpected behavior.
```

[1] https://github.com/smallrye/smallrye-open-api/actions/runs/11349084528/job/31564363806?pr=2017#step:7:53

Pull request:
Make TCK `@BeforeClass` method non-static (RestAssured setup process)
Avoid use of static setup method and move work fields to method scope where used.

Fixes #664 

Patch:
diff --git a/api/src/main/java/org/eclipse/microprofile/openapi/annotations/media/DependentRequired.java b/api/src/main/java/org/eclipse/microprofile/openapi/annotations/media/DependentRequired.java
index dc410ff..4db9194 100644
--- a/api/src/main/java/org/eclipse/microprofile/openapi/annotations/media/DependentRequired.java
+++ b/api/src/main/java/org/eclipse/microprofile/openapi/annotations/media/DependentRequired.java
@@ -15,6 +15,8 @@
  */
 package org.eclipse.microprofile.openapi.annotations.media;
 
+import java.lang.annotation.Target;
+
 /**
  * A property name and an associated list of other property names.
  * <p>
@@ -24,6 +26,7 @@ package org.eclipse.microprofile.openapi.annotations.media;
  * @see Schema#dependentRequired()
  * @since 4.0
  */
+@Target({})
 public @interface DependentRequired {
 
     /**
diff --git a/api/src/main/java/org/eclipse/microprofile/openapi/annotations/media/DependentSchema.java b/api/src/main/java/org/eclipse/microprofile/openapi/annotations/media/DependentSchema.java
index 6ea7af4..6a30645 100644
--- a/api/src/main/java/org/eclipse/microprofile/openapi/annotations/media/DependentSchema.java
+++ b/api/src/main/java/org/eclipse/microprofile/openapi/annotations/media/DependentSchema.java
@@ -15,6 +15,8 @@
  */
 package org.eclipse.microprofile.openapi.annotations.media;
 
+import java.lang.annotation.Target;
+
 /**
  * A property name and an associated schema.
  * <p>
@@ -24,6 +26,7 @@ package org.eclipse.microprofile.openapi.annotations.media;
  * @see Schema#dependentSchemas()
  * @since 4.0
  */
+@Target({})
 public @interface DependentSchema {
 
     /**
diff --git a/api/src/main/java/org/eclipse/microprofile/openapi/annotations/media/SchemaProperty.java b/api/src/main/java/org/eclipse/microprofile/openapi/annotations/media/SchemaProperty.java
index 66f24c7..c4cd589 100644
--- a/api/src/main/java/org/eclipse/microprofile/openapi/annotations/media/SchemaProperty.java
+++ b/api/src/main/java/org/eclipse/microprofile/openapi/annotations/media/SchemaProperty.java
@@ -19,6 +19,7 @@ package org.eclipse.microprofile.openapi.annotations.media;
 import java.lang.annotation.Inherited;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
 
 import org.eclipse.microprofile.openapi.annotations.ExternalDocumentation;
 import org.eclipse.microprofile.openapi.annotations.enums.SchemaType;
@@ -37,6 +38,7 @@ import org.eclipse.microprofile.openapi.annotations.media.Schema.True;
  *
  * @since 2.0
  **/
+@Target({})
 @Retention(RetentionPolicy.RUNTIME)
 @Inherited
 public @interface SchemaProperty {
diff --git a/api/src/main/java/org/eclipse/microprofile/openapi/annotations/media/package-info.java b/api/src/main/java/org/eclipse/microprofile/openapi/annotations/media/package-info.java
index 1c8176a..5834cec 100644
--- a/api/src/main/java/org/eclipse/microprofile/openapi/annotations/media/package-info.java
+++ b/api/src/main/java/org/eclipse/microprofile/openapi/annotations/media/package-info.java
@@ -25,6 +25,6 @@
  * </pre>
  */
 
-@org.osgi.annotation.versioning.Version("1.3")
+@org.osgi.annotation.versioning.Version("1.3.1")
 @org.osgi.annotation.versioning.ProviderType
 package org.eclipse.microprofile.openapi.annotations.media;
\ No newline at end of file
diff --git a/api/src/main/java/org/eclipse/microprofile/openapi/models/Extensible.java b/api/src/main/java/org/eclipse/microprofile/openapi/models/Extensible.java
index 407204f..2b7c473 100644
--- a/api/src/main/java/org/eclipse/microprofile/openapi/models/Extensible.java
+++ b/api/src/main/java/org/eclipse/microprofile/openapi/models/Extensible.java
@@ -76,4 +76,34 @@ public interface Extensible<T extends Extensible<T>> {
      */
     void setExtensions(Map<String, Object> extensions);
 
+    /**
+     * Checks whether an extension with the given name is present in this Extensible's map of extensions.
+     *
+     * @param name
+     *            the key used to access the extension object. Always prefixed by "x-".
+     * @return {@code true} if an extension with the given name is present, otherwise {@code false}
+     */
+    default boolean hasExtension(String name) {
+        Map<String, Object> map = getExtensions();
+        if (map == null) {
+            return false;
+        }
+        return map.containsKey(name);
+    }
+
+    /**
+     * Returns the extension object with the given name from this Extensible's map of extensions.
+     *
+     * @param name
+     *            the key used to access the extension object. Always prefixed by "x-".
+     * @return the corresponding extension object, or {@code null} if no extension with the given name is present
+     */
+    default Object getExtension(String name) {
+        Map<String, Object> map = getExtensions();
+        if (map == null) {
+            return null;
+        }
+        return map.get(name);
+    }
+
 }
diff --git a/api/src/main/java/org/eclipse/microprofile/openapi/models/OpenAPI.java b/api/src/main/java/org/eclipse/microprofile/openapi/models/OpenAPI.java
index eed5b42..be8929f 100644
--- a/api/src/main/java/org/eclipse/microprofile/openapi/models/OpenAPI.java
+++ b/api/src/main/java/org/eclipse/microprofile/openapi/models/OpenAPI.java
@@ -327,6 +327,36 @@ public interface OpenAPI extends Constructible, Extensible<OpenAPI> {
      */
     void removeWebhook(String name);
 
+    /**
+     * Returns the default JSON Schema dialect for schemas in this document.
+     *
+     * @return the identifier of the default schema dialect for schemas in this document
+     * @since 4.1
+     */
+    String getJsonSchemaDialect();
+
+    /**
+     * Sets the default JSON Schema dialect for schemas in this document.
+     *
+     * @param jsonSchemaDialect
+     *            the identifier of the default schema dialect for schemas in this document
+     * @since 4.1
+     */
+    void setJsonSchemaDialect(String jsonSchemaDialect);
+
+    /**
+     * Sets the default JSON Schema dialect for schemas in this document.
+     *
+     * @param jsonSchemaDialect
+     *            the identifier of the default schema dialect for schemas in this document
+     * @return the current OpenAPI object
+     * @since 4.1
+     */
+    default OpenAPI jsonSchemaDialect(String jsonSchemaDialect) {
+        setJsonSchemaDialect(jsonSchemaDialect);
+        return this;
+    }
+
     /**
      * Returns the components property from an OpenAPI instance.
      *
diff --git a/api/src/main/java/org/eclipse/microprofile/openapi/models/callbacks/package-info.java b/api/src/main/java/org/eclipse/microprofile/openapi/models/callbacks/package-info.java
index cc8a571..fe05271 100644
--- a/api/src/main/java/org/eclipse/microprofile/openapi/models/callbacks/package-info.java
+++ b/api/src/main/java/org/eclipse/microprofile/openapi/models/callbacks/package-info.java
@@ -17,6 +17,6 @@
  * The behaviour of methods inherited from java.lang.Object are undefined by the MicroProfile OpenAPI specification.
  */
 
-@org.osgi.annotation.versioning.Version("2.0")
+@org.osgi.annotation.versioning.Version("2.1")
 @org.osgi.annotation.versioning.ProviderType
 package org.eclipse.microprofile.openapi.models.callbacks;
\ No newline at end of file
diff --git a/api/src/main/java/org/eclipse/microprofile/openapi/models/examples/package-info.java b/api/src/main/java/org/eclipse/microprofile/openapi/models/examples/package-info.java
index 2956c67..d1d6898 100644
--- a/api/src/main/java/org/eclipse/microprofile/openapi/models/examples/package-info.java
+++ b/api/src/main/java/org/eclipse/microprofile/openapi/models/examples/package-info.java
@@ -31,6 +31,6 @@
  * </pre>
  */
 
-@org.osgi.annotation.versioning.Version("1.0")
+@org.osgi.annotation.versioning.Version("1.1")
 @org.osgi.annotation.versioning.ProviderType
 package org.eclipse.microprofile.openapi.models.examples;
\ No newline at end of file
diff --git a/api/src/main/java/org/eclipse/microprofile/openapi/models/headers/package-info.java b/api/src/main/java/org/eclipse/microprofile/openapi/models/headers/package-info.java
index 3d3da47..4eb3a27 100644
--- a/api/src/main/java/org/eclipse/microprofile/openapi/models/headers/package-info.java
+++ b/api/src/main/java/org/eclipse/microprofile/openapi/models/headers/package-info.java
@@ -35,6 +35,6 @@
  * </pre>
  */
 
-@org.osgi.annotation.versioning.Version("1.0")
+@org.osgi.annotation.versioning.Version("1.1")
 @org.osgi.annotation.versioning.ProviderType
 package org.eclipse.microprofile.openapi.models.headers;
\ No newline at end of file
diff --git a/api/src/main/java/org/eclipse/microprofile/openapi/models/info/package-info.java b/api/src/main/java/org/eclipse/microprofile/openapi/models/info/package-info.java
index 6ec0a09..1671c9d 100644
--- a/api/src/main/java/org/eclipse/microprofile/openapi/models/info/package-info.java
+++ b/api/src/main/java/org/eclipse/microprofile/openapi/models/info/package-info.java
@@ -40,6 +40,6 @@
  * </pre>
  */
 
-@org.osgi.annotation.versioning.Version("1.1")
+@org.osgi.annotation.versioning.Version("1.2")
 @org.osgi.annotation.versioning.ProviderType
 package org.eclipse.microprofile.openapi.models.info;
\ No newline at end of file
diff --git a/api/src/main/java/org/eclipse/microprofile/openapi/models/links/package-info.java b/api/src/main/java/org/eclipse/microprofile/openapi/models/links/package-info.java
index 0b6e822..e28730a 100644
--- a/api/src/main/java/org/eclipse/microprofile/openapi/models/links/package-info.java
+++ b/api/src/main/java/org/eclipse/microprofile/openapi/models/links/package-info.java
@@ -29,6 +29,6 @@
  * </pre>
  */
 
-@org.osgi.annotation.versioning.Version("1.0")
+@org.osgi.annotation.versioning.Version("1.1")
 @org.osgi.annotation.versioning.ProviderType
 package org.eclipse.microprofile.openapi.models.links;
\ No newline at end of file
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 3e143df..a1fb925 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 @@
  * </pre>
  */
 
-@org.osgi.annotation.versioning.Version("3.0")
+@org.osgi.annotation.versioning.Version("3.1")
 @org.osgi.annotation.versioning.ProviderType
 package org.eclipse.microprofile.openapi.models.media;
\ No newline at end of file
diff --git a/api/src/main/java/org/eclipse/microprofile/openapi/models/package-info.java b/api/src/main/java/org/eclipse/microprofile/openapi/models/package-info.java
index f29b807..929acdc 100644
--- a/api/src/main/java/org/eclipse/microprofile/openapi/models/package-info.java
+++ b/api/src/main/java/org/eclipse/microprofile/openapi/models/package-info.java
@@ -40,6 +40,6 @@
  * </pre>
  */
 
-@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;
\ No newline at end of file
diff --git a/api/src/main/java/org/eclipse/microprofile/openapi/models/parameters/package-info.java b/api/src/main/java/org/eclipse/microprofile/openapi/models/parameters/package-info.java
index bf390ff..fefc738 100644
--- a/api/src/main/java/org/eclipse/microprofile/openapi/models/parameters/package-info.java
+++ b/api/src/main/java/org/eclipse/microprofile/openapi/models/parameters/package-info.java
@@ -32,6 +32,6 @@
  * </pre>
  */
 
-@org.osgi.annotation.versioning.Version("1.0")
+@org.osgi.annotation.versioning.Version("1.1")
 @org.osgi.annotation.versioning.ProviderType
 package org.eclipse.microprofile.openapi.models.parameters;
\ No newline at end of file
diff --git a/api/src/main/java/org/eclipse/microprofile/openapi/models/responses/package-info.java b/api/src/main/java/org/eclipse/microprofile/openapi/models/responses/package-info.java
index 41b9c37..8955422 100644
--- a/api/src/main/java/org/eclipse/microprofile/openapi/models/responses/package-info.java
+++ b/api/src/main/java/org/eclipse/microprofile/openapi/models/responses/package-info.java
@@ -34,6 +34,6 @@
  * </pre>
  */
 
-@org.osgi.annotation.versioning.Version("2.0")
+@org.osgi.annotation.versioning.Version("2.1")
 @org.osgi.annotation.versioning.ProviderType
 package org.eclipse.microprofile.openapi.models.responses;
\ No newline at end of file
diff --git a/api/src/main/java/org/eclipse/microprofile/openapi/models/security/package-info.java b/api/src/main/java/org/eclipse/microprofile/openapi/models/security/package-info.java
index b9380d4..0eb28a4 100644
--- a/api/src/main/java/org/eclipse/microprofile/openapi/models/security/package-info.java
+++ b/api/src/main/java/org/eclipse/microprofile/openapi/models/security/package-info.java
@@ -28,6 +28,6 @@
  * </pre>
  */
 
-@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.security;
\ No newline at end of file
diff --git a/api/src/main/java/org/eclipse/microprofile/openapi/models/servers/package-info.java b/api/src/main/java/org/eclipse/microprofile/openapi/models/servers/package-info.java
index 8a0f931..167a61a 100644
--- a/api/src/main/java/org/eclipse/microprofile/openapi/models/servers/package-info.java
+++ b/api/src/main/java/org/eclipse/microprofile/openapi/models/servers/package-info.java
@@ -35,6 +35,6 @@
  * </pre>
  */
 
-@org.osgi.annotation.versioning.Version("2.0")
+@org.osgi.annotation.versioning.Version("2.1")
 @org.osgi.annotation.versioning.ProviderType
 package org.eclipse.microprofile.openapi.models.servers;
\ No newline at end of file
diff --git a/api/src/main/java/org/eclipse/microprofile/openapi/models/tags/package-info.java b/api/src/main/java/org/eclipse/microprofile/openapi/models/tags/package-info.java
index 195d309..12a8a57 100644
--- a/api/src/main/java/org/eclipse/microprofile/openapi/models/tags/package-info.java
+++ b/api/src/main/java/org/eclipse/microprofile/openapi/models/tags/package-info.java
@@ -29,6 +29,6 @@
  * </pre>
  */
 
-@org.osgi.annotation.versioning.Version("1.0")
+@org.osgi.annotation.versioning.Version("1.1")
 @org.osgi.annotation.versioning.ProviderType
 package org.eclipse.microprofile.openapi.models.tags;
\ No newline at end of file
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 e94c0a7..e26833e 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
@@ -308,6 +308,7 @@ public class MyOASModelReaderImpl implements OASModelReader {
                 .externalDocs(OASFactory.createObject(ExternalDocumentation.class)
                         .description("instructions for how to deploy this app")
                         .url("https://github.com/microservices-api/oas3-airlines/blob/master/README.md"))
+                .jsonSchemaDialect("https://json-schema.org/draft/2020-12/schema")
                 .addWebhook("bookingEvent", OASFactory.createPathItem()
                         .PUT(OASFactory.createOperation()
                                 .summary("Notifies that a booking has been created")


Test patch:
diff --git a/tck/src/main/java/org/eclipse/microprofile/openapi/tck/AppTestBase.java b/tck/src/main/java/org/eclipse/microprofile/openapi/tck/AppTestBase.java
index 7eb1017..30ed9b1 100644
--- a/tck/src/main/java/org/eclipse/microprofile/openapi/tck/AppTestBase.java
+++ b/tck/src/main/java/org/eclipse/microprofile/openapi/tck/AppTestBase.java
@@ -41,16 +41,12 @@ public abstract class AppTestBase extends Arquillian {
     private static final String DEFAULT_HOST = "localhost";
     private static final int DEFAULT_PORT = 9080;
 
-    private static String serverUrl;
-    private static String username;
-    private static String password;
-
     protected static final Filter YAML_FILTER = new YamlToJsonFilter();
 
     @BeforeClass
-    public static void configureRestAssured() throws MalformedURLException {
+    public void configureRestAssured() throws MalformedURLException {
         // set base URI and port number to use for all requests
-        serverUrl = System.getProperty("test.url");
+        String serverUrl = System.getProperty("test.url");
         String protocol = DEFAULT_PROTOCOL;
         String host = DEFAULT_HOST;
         int port = DEFAULT_PORT;
@@ -65,8 +61,8 @@ public abstract class AppTestBase extends Arquillian {
         RestAssured.baseURI = protocol + "://" + host;
         RestAssured.port = port;
 
-        username = System.getProperty("test.user");
-        password = System.getProperty("test.pwd");
+        String username = System.getProperty("test.user");
+        String password = System.getProperty("test.pwd");
 
         if (username != null && password != null) {
             RestAssured.authentication = RestAssured.basic(username, password);
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 9482aab..9481a99 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
@@ -1781,16 +1781,28 @@ public class ModelConstructionTest extends Arquillian {
         assertEquals(map.size(), 2, "The extensions map is expected to contain two entries.");
         assertTrue(map.containsKey(extensionName1),
                 "The extensions map is expected to contain the key: " + extensionName1);
+        assertTrue(e.hasExtension(extensionName1),
+                "hasExtension is expected to return true for the key: " + extensionName1);
         assertTrue(map.containsKey(extensionName2),
                 "The extensions map is expected to contain the key: " + extensionName2);
+        assertTrue(e.hasExtension(extensionName2),
+                "hasExtension is expected to return true for the key: " + extensionName2);
         assertSame(map.get(extensionName1), obj1,
                 "The value associated with the key: " + extensionName1
                         + " is expected to be the same one that was added.");
+        assertSame(e.getExtension(extensionName1), obj1,
+                "getExtension should return the same instance added for the key: " + extensionName1);
         assertSame(map.get(extensionName2), obj2,
                 "The value associated with the key: " + extensionName2
                         + " is expected to be the same one that was added.");
+        assertSame(e.getExtension(extensionName2), obj2,
+                "getExtension should return the same instance added for the key: " + extensionName2);
         e.removeExtension(extensionName1);
         assertEquals(e.getExtensions().size(), 1, "The extensions map is expected to contain one entry.");
+        assertFalse(e.hasExtension(extensionName1),
+                "hasExtension is expected to return false for removed key: " + extensionName1);
+        assertNull(e.getExtension(extensionName1),
+                "getExtension is expected to return null for removed key: " + extensionName1);
         // Check that the extension map can be replaced with the setter and that it is returned by the getter.
         final Map<String, Object> newMap = new HashMap<>();
         e.setExtensions(newMap);
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 5d421f6..a890c60 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
@@ -427,4 +427,10 @@ public class ModelReaderAppTest extends AppTestBase {
 
         vr.body("paths.'/zepplins'.delete.requestBody.content", notNullValue());
     }
+
+    @Test(dataProvider = "formatProvider")
+    public void testSchemaDialect(String type) {
+        ValidatableResponse vr = callEndpoint(type);
+        vr.body("jsonSchemaDialect", equalTo("https://json-schema.org/draft/2020-12/schema"));
+    }
 }