Repository: vert-x3/vertx-web
Issue: Hosted OpenAPI document relative `$ref` values replaced with absolute file paths

### Version

4.1.0

### Context

When hosting an OpenAPI document using `io.vertx.ext.web.openapi.RouterBuilder` with `io.vertx.ext.web.openapi.RouterBuilderOptions#setContractEndpoint`, the hosted document has absolute paths in `$ref` attribute values. It appears the relative references (i.e. to `#/components/...`) were replaced for the purposes of validation. However, the relative paths should still be present in the hosted document returned from HTTP GET at `/openapi` (or whatever the contract endpoint is configured to be).

### Do you have a reproducer?

Not yet, but I can put something together if necessary. 

### Extra

N/A


Changed files:
vertx-web-openapi/src/main/java/io/vertx/ext/web/openapi/impl/OpenAPIHolderImpl.java
vertx-web-openapi/src/test/java/io/vertx/ext/web/openapi/impl/OpenAPIHolderTest.java

diff --git a/vertx-web-openapi/src/main/java/io/vertx/ext/web/openapi/impl/OpenAPIHolderImpl.java b/vertx-web-openapi/src/main/java/io/vertx/ext/web/openapi/impl/OpenAPIHolderImpl.java
index f227a422c..c092f22bb 100755
--- a/vertx-web-openapi/src/main/java/io/vertx/ext/web/openapi/impl/OpenAPIHolderImpl.java
+++ b/vertx-web-openapi/src/main/java/io/vertx/ext/web/openapi/impl/OpenAPIHolderImpl.java
@@ -76,7 +76,7 @@ public class OpenAPIHolderImpl implements OpenAPIHolder {
       })
       .compose(openapi -> {
         absolutePaths.put(initialScope, openapi); // Circular refs hell!
-        openapiRoot = openapi;
+        openapiRoot = openapi.copy();
         return walkAndSolve(openapi, initialScope).map(openapi);
       })
       .compose(openapi -> {
diff --git a/vertx-web-openapi/src/test/java/io/vertx/ext/web/openapi/impl/OpenAPIHolderTest.java b/vertx-web-openapi/src/test/java/io/vertx/ext/web/openapi/impl/OpenAPIHolderTest.java
index b799caacb..2b92e6e9f 100755
--- a/vertx-web-openapi/src/test/java/io/vertx/ext/web/openapi/impl/OpenAPIHolderTest.java
+++ b/vertx-web-openapi/src/test/java/io/vertx/ext/web/openapi/impl/OpenAPIHolderTest.java
@@ -224,6 +224,20 @@ public class OpenAPIHolderTest {
                 "src/test/resources/yaml/valid/local_refs.yaml#/components/schemas/Simple"
               ).toString());
 
+            // Verify the OpenAPI object stored by the OpenAPIHolder retains local refs.
+            assertThat(loader.getOpenAPI())
+              .extracting(JsonPointer.create()
+                .append("paths")
+                .append("/simple")
+                .append("post")
+                .append("requestBody")
+                .append("content")
+                .append("multipart/form-data")
+                .append("schema")
+                .append("$ref")
+              )
+              .isEqualTo("#/components/schemas/Simple");
+
             assertThat(loader)
               .hasCached(resolveAbsoluteURIFromFS("src/test/resources/yaml/valid/refs/Simple.yaml"));
 
@@ -645,7 +659,7 @@ public class OpenAPIHolderTest {
         )).append(Arrays.asList(
           "paths", "/test8", "post", "requestBody", "content", "application/json", "schema"
         ));
-        JsonObject resolved = (JsonObject) schemaPointer.query(loader.getOpenAPI(),
+        JsonObject resolved = (JsonObject) schemaPointer.query(l.result(),
           new JsonPointerIteratorWithLoader(loader));
 
         Map<JsonPointer, JsonObject> additionalSchemasToRegister = new HashMap<>();