Eliminate ObjectNode(s) from Operation class 07/107707/11
authorOleksandr Zharov <oleksandr.zharov@pantheon.tech>
Tue, 5 Sep 2023 11:12:50 +0000 (13:12 +0200)
committerIvan Hrasko <ivan.hrasko@pantheon.tech>
Fri, 22 Sep 2023 12:37:59 +0000 (12:37 +0000)
Removed usage of ObjectNode and ArrayNode in Operation class
and replaced them with proper objects.

JIRA: NETCONF-938
Change-Id: I15d8f64d004141f40f5beebaa21690d32a25b14f
Signed-off-by: Oleksandr Zharov <oleksandr.zharov@pantheon.tech>
Signed-off-by: Ivan Hrasko <ivan.hrasko@pantheon.tech>
12 files changed:
restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/model/Link.java [new file with mode: 0644]
restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/model/MediaTypeObject.java [new file with mode: 0644]
restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/model/Operation.java
restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/model/RequestBody.java [new file with mode: 0644]
restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/model/ResponseObject.java [new file with mode: 0644]
restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/model/builder/OperationBuilder.java
restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/mountpoints/MountPointOpenApi.java
restconf/restconf-openapi/src/test/java/org/opendaylight/restconf/openapi/JsonModelNameTest.java
restconf/restconf-openapi/src/test/java/org/opendaylight/restconf/openapi/OperationalDataTest.java
restconf/restconf-openapi/src/test/java/org/opendaylight/restconf/openapi/SchemaObjectsTest.java
restconf/restconf-openapi/src/test/java/org/opendaylight/restconf/openapi/impl/OpenApiGeneratorRFC8040Test.java
restconf/restconf-openapi/src/test/java/org/opendaylight/restconf/openapi/impl/PostPayloadTest.java

diff --git a/restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/model/Link.java b/restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/model/Link.java
new file mode 100644 (file)
index 0000000..705f4b1
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2023 PANTHEON.tech, s.r.o. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.restconf.openapi.model;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import java.util.Map;
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public record Link(
+        String operationRef,
+        String operationId,
+        Map<String, Object> parameters,
+        RequestBody requestBody,
+        String description,
+        Server server) {
+}
diff --git a/restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/model/MediaTypeObject.java b/restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/model/MediaTypeObject.java
new file mode 100644 (file)
index 0000000..fcb5e69
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2023 PANTHEON.tech, s.r.o. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.restconf.openapi.model;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import org.eclipse.jdt.annotation.Nullable;
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public record MediaTypeObject(
+        @Nullable Schema schema) {
+
+    private MediaTypeObject(final Builder builder) {
+        this(builder.schema);
+    }
+
+    @SuppressWarnings("checkstyle:hiddenField")
+    public static class Builder {
+        Schema schema;
+
+        public Builder schema(Schema schema) {
+            this.schema = schema;
+            return this;
+        }
+
+        public MediaTypeObject build() {
+            return new MediaTypeObject(this);
+        }
+    }
+}
index 8db94a653d2059b78b1773b864213890d2fb5761..318a1873087dea8e9443a9857c16774f4c984de7 100644 (file)
@@ -8,8 +8,6 @@
 package org.opendaylight.restconf.openapi.model;
 
 import com.fasterxml.jackson.annotation.JsonInclude;
-import com.fasterxml.jackson.databind.node.ArrayNode;
-import com.fasterxml.jackson.databind.node.ObjectNode;
 import java.util.List;
 import java.util.Map;
 
@@ -19,15 +17,24 @@ public record Operation(
         List<String> tags,
         List<Parameter> parameters,
         List<Map<String, List<String>>> security,
-        ArrayNode servers,
-        ObjectNode callbacks,
-        ObjectNode externalDocs,
-        ObjectNode requestBody,
-        ObjectNode responses,
+        List<Server> servers,
+        Map<String, Path> callbacks,
+        ExternalDocumentation externalDocs,
+        RequestBody requestBody,
+        Map<String, ResponseObject> responses,
         String description,
         String operationId,
         String summary) {
 
+    public Operation {
+        tags = tags == null ? null : List.copyOf(tags);
+        parameters = parameters == null ? null : List.copyOf(parameters);
+        security = security == null ? null : List.copyOf(security);
+        servers = servers == null ? null : List.copyOf(servers);
+        callbacks = callbacks == null ? null : Map.copyOf(callbacks);
+        responses = responses == null ? null : Map.copyOf(responses);
+    }
+
     private Operation(final Builder builder) {
         this(builder.deprecated, builder.tags, builder.parameters, builder.security, builder.servers, builder.callbacks,
             builder.externalDocs, builder.requestBody, builder.responses, builder.description, builder.operationId,
@@ -40,11 +47,11 @@ public record Operation(
         private List<String> tags;
         private List<Parameter> parameters;
         private List<Map<String, List<String>>> security;
-        private ArrayNode servers;
-        private ObjectNode callbacks;
-        private ObjectNode externalDocs;
-        private ObjectNode requestBody;
-        private ObjectNode responses;
+        private List<Server> servers;
+        private Map<String, Path> callbacks;
+        private ExternalDocumentation externalDocs;
+        private RequestBody requestBody;
+        private Map<String, ResponseObject> responses;
         private String description;
         private String operationId;
         private String summary;
@@ -69,27 +76,27 @@ public record Operation(
             return this;
         }
 
-        public Builder servers(final ArrayNode servers) {
+        public Builder servers(final List<Server> servers) {
             this.servers = servers;
             return this;
         }
 
-        public Builder callbacks(final ObjectNode callbacks) {
+        public Builder callbacks(final Map<String, Path> callbacks) {
             this.callbacks = callbacks;
             return this;
         }
 
-        public Builder externalDocs(final ObjectNode externalDocs) {
+        public Builder externalDocs(final ExternalDocumentation externalDocs) {
             this.externalDocs = externalDocs;
             return this;
         }
 
-        public Builder requestBody(final ObjectNode requestBody) {
+        public Builder requestBody(final RequestBody requestBody) {
             this.requestBody = requestBody;
             return this;
         }
 
-        public Builder responses(final ObjectNode responses) {
+        public Builder responses(final Map<String, ResponseObject> responses) {
             this.responses = responses;
             return this;
         }
diff --git a/restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/model/RequestBody.java b/restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/model/RequestBody.java
new file mode 100644 (file)
index 0000000..6682ddf
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2023 PANTHEON.tech s.r.o and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.restconf.openapi.model;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import java.util.Map;
+import java.util.Objects;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public record RequestBody(
+        @Nullable String description,
+        @NonNull Map<String, MediaTypeObject> content,
+        boolean required) {
+
+    public RequestBody {
+        content = Map.copyOf(Objects.requireNonNull(content));
+    }
+
+    private RequestBody(final Builder builder) {
+        this(builder.description, builder.content, builder.required);
+    }
+
+    @SuppressWarnings("checkstyle:hiddenField")
+    public static class Builder {
+        private String description;
+        private Map<String, MediaTypeObject> content;
+        private boolean required;
+
+        public Builder description(final String description) {
+            this.description = description;
+            return this;
+        }
+
+        public Builder content(final Map<String, MediaTypeObject> content) {
+            this.content = content;
+            return this;
+        }
+
+        public Builder required(final boolean required) {
+            this.required = required;
+            return this;
+        }
+
+        public RequestBody build() {
+            return new RequestBody(this);
+        }
+    }
+}
diff --git a/restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/model/ResponseObject.java b/restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/model/ResponseObject.java
new file mode 100644 (file)
index 0000000..32484e8
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2023 PANTHEON.tech, s.r.o. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.restconf.openapi.model;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import java.util.Map;
+import java.util.Objects;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public record ResponseObject(
+        @NonNull String description,
+        @Nullable Map<String, String> headers,
+        @Nullable Map<String, MediaTypeObject> content,
+        @Nullable Map<String, Link> links) {
+
+    public ResponseObject {
+        description = Objects.requireNonNull(description);
+        headers = headers == null ? null : Map.copyOf(headers);
+        content = content == null ? null : Map.copyOf(content);
+        links = links == null ? null : Map.copyOf(links);
+    }
+
+    private ResponseObject(final Builder builder) {
+        this(builder.description, builder.headers, builder.content, builder.links);
+    }
+
+    @SuppressWarnings("checkstyle:hiddenField")
+    public static class Builder {
+        private String description;
+        private Map<String, String> headers;
+        private Map<String, MediaTypeObject> content;
+        private Map<String, Link> links;
+
+        public Builder description(final String description) {
+            this.description = description;
+            return this;
+        }
+
+        public Builder headers(final Map<String, String> headers) {
+            this.headers = headers;
+            return this;
+        }
+
+        public Builder content(final Map<String, MediaTypeObject> content) {
+            this.content = content;
+            return this;
+        }
+
+        public Builder links(final Map<String, Link> links) {
+            this.links = links;
+            return this;
+        }
+
+        public ResponseObject build() {
+            return new ResponseObject(this);
+        }
+    }
+}
index 8a5203bbfb47a5d314e53ac1374a904a6dfd0d12..39e1ef160865ea725b0255e4f3b6ab1563bd8cbf 100644 (file)
@@ -7,22 +7,29 @@
  */
 package org.opendaylight.restconf.openapi.model.builder;
 
-import static org.opendaylight.restconf.openapi.impl.DefinitionGenerator.INPUT;
+import static javax.ws.rs.core.Response.Status.NO_CONTENT;
+import static javax.ws.rs.core.Response.Status.OK;
 import static org.opendaylight.restconf.openapi.impl.DefinitionGenerator.INPUT_SUFFIX;
 import static org.opendaylight.restconf.openapi.impl.DefinitionGenerator.OUTPUT_SUFFIX;
 
-import com.fasterxml.jackson.databind.node.JsonNodeFactory;
-import com.fasterxml.jackson.databind.node.ObjectNode;
+import java.util.AbstractMap.SimpleEntry;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import javax.ws.rs.HttpMethod;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.restconf.openapi.impl.DefinitionNames;
+import org.opendaylight.restconf.openapi.model.MediaTypeObject;
 import org.opendaylight.restconf.openapi.model.Operation;
 import org.opendaylight.restconf.openapi.model.Parameter;
+import org.opendaylight.restconf.openapi.model.Property;
+import org.opendaylight.restconf.openapi.model.RequestBody;
+import org.opendaylight.restconf.openapi.model.ResponseObject;
 import org.opendaylight.restconf.openapi.model.Schema;
+import org.opendaylight.restconf.openapi.model.Xml;
 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
@@ -32,19 +39,11 @@ import org.opendaylight.yangtools.yang.model.api.OperationDefinition;
 import org.opendaylight.yangtools.yang.model.api.OutputSchemaNode;
 
 public final class OperationBuilder {
-    public static final String CONTENT_KEY = "content";
     public static final String COMPONENTS_PREFIX = "#/components/schemas/";
-    public static final String DESCRIPTION_KEY = "description";
     public static final String INPUT_KEY = "input";
-    public static final String NAME_KEY = "name";
-    public static final String PROPERTIES_KEY = "properties";
-    public static final String REF_KEY = "$ref";
-    public static final String SCHEMA_KEY = "schema";
     public static final String SUMMARY_TEMPLATE = "%s - %s - %s - %s";
-    public static final String XML_KEY = "xml";
     private static final List<String> MIME_TYPES = List.of(MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON);
     private static final String OBJECT = "object";
-    private static final String TYPE_KEY = "type";
     private static final String POST_DESCRIPTION = """
         \n
         Note:
@@ -62,7 +61,7 @@ public final class OperationBuilder {
         final var summary = SUMMARY_TEMPLATE.formatted(HttpMethod.POST, deviceName, moduleName, nodeName);
         final List<String> tags = List.of(deviceName + " " + moduleName);
         final List<Parameter> parameters = new ArrayList<>(pathParams);
-        final ObjectNode requestBody;
+        final RequestBody requestBody;
         final DataSchemaNode childNode = node == null ? null : getListOrContainerChildNode(node);
         final List<String> nameElements = new ArrayList<>();
         if (parentName != null) {
@@ -80,9 +79,8 @@ public final class OperationBuilder {
             final String defName = String.join("_", nameElements);
             requestBody = createPostDataRequestBodyParameter(defName, nodeName);
         }
-        final ObjectNode responses = JsonNodeFactory.instance.objectNode();
-        responses.set(String.valueOf(Response.Status.CREATED.getStatusCode()),
-                buildResponse(Response.Status.CREATED.getReasonPhrase()));
+        final Map<String, ResponseObject> responses = Map.of(String.valueOf(Response.Status.CREATED.getStatusCode()),
+            buildResponse(Response.Status.CREATED.getReasonPhrase()));
 
         return new Operation.Builder()
             .tags(tags)
@@ -104,12 +102,11 @@ public final class OperationBuilder {
         final List<String> tags = List.of(deviceName + " " + moduleName);
         final List<Parameter> parameters = new ArrayList<>(pathParams);
         parameters.add(buildQueryParameters(isConfig));
-        final ObjectNode responses = JsonNodeFactory.instance.objectNode();
-
         final boolean isList = node instanceof ListSchemaNode;
-        final ObjectNode response = createRequestBodyParameter(defName, nodeName, isList, summary,
-                String.valueOf(Response.Status.OK.getStatusCode()));
-        responses.set(String.valueOf(Response.Status.OK.getStatusCode()), response);
+        final ResponseObject response = createResponse(defName, nodeName, isList,
+            String.valueOf(OK.getStatusCode()), summary);
+        final Map<String, ResponseObject> responses = Map.of(String.valueOf(OK.getStatusCode()),
+            response);
 
         return new Operation.Builder()
             .tags(tags)
@@ -139,18 +136,18 @@ public final class OperationBuilder {
         final List<Parameter> parameters = new ArrayList<>(pathParams);
         final String defName = parentName + "_" + nodeName;
         final boolean isList = node instanceof ListSchemaNode;
-        final ObjectNode requestBody = createRequestBodyParameter(defName, fullName, isList, summary, nodeName);
+        final RequestBody requestBody = createRequestBodyParameter(defName, fullName, isList, summary, nodeName);
 
-        final ObjectNode responses = JsonNodeFactory.instance.objectNode();
-        responses.set(String.valueOf(Response.Status.CREATED.getStatusCode()),
+        final var created = new SimpleEntry<>(String.valueOf(Response.Status.CREATED.getStatusCode()),
             buildResponse(Response.Status.CREATED.getReasonPhrase()));
-        responses.set(String.valueOf(Response.Status.NO_CONTENT.getStatusCode()), buildResponse("Updated"));
+        final var updated = new SimpleEntry<>(String.valueOf(NO_CONTENT.getStatusCode()),
+            buildResponse("Updated"));
 
         return new Operation.Builder()
             .tags(tags)
             .parameters(parameters)
             .requestBody(requestBody)
-            .responses(responses)
+            .responses(Map.of(created.getKey(), created.getValue(), updated.getKey(), updated.getValue()))
             .description(node.getDescription().orElse(""))
             .summary(summary)
             .build();
@@ -164,18 +161,18 @@ public final class OperationBuilder {
         final List<Parameter> parameters = new ArrayList<>(pathParams);
         final String defName = parentName + "_" + nodeName;
         final boolean isList = node instanceof ListSchemaNode;
-        final ObjectNode requestBody = createRequestBodyParameter(defName, fullName, isList, summary, nodeName);
+        final RequestBody requestBody = createRequestBodyParameter(defName, fullName, isList, summary, nodeName);
 
-        final ObjectNode responses = JsonNodeFactory.instance.objectNode();
-        responses.set(String.valueOf(Response.Status.OK.getStatusCode()),
-                buildResponse(Response.Status.OK.getReasonPhrase()));
-        responses.set(String.valueOf(Response.Status.NO_CONTENT.getStatusCode()), buildResponse("Updated"));
+        final SimpleEntry<String, ResponseObject> created = new SimpleEntry<>(String.valueOf(OK.getStatusCode()),
+            buildResponse(OK.getReasonPhrase()));
+        final SimpleEntry<String, ResponseObject> updated = new SimpleEntry<>(String.valueOf(NO_CONTENT
+            .getStatusCode()), buildResponse("Updated"));
 
         return new Operation.Builder()
             .tags(tags)
             .parameters(parameters)
             .requestBody(requestBody)
-            .responses(responses)
+            .responses(Map.of(created.getKey(), created.getValue(), updated.getKey(), updated.getValue()))
             .description(node.getDescription().orElse(""))
             .summary(summary)
             .build();
@@ -188,9 +185,8 @@ public final class OperationBuilder {
         final List<String> tags = List.of(deviceName + " " + moduleName);
         final String description = node.getDescription().orElse("");
         final List<Parameter> parameters = new ArrayList<>(pathParams);
-
-        final ObjectNode responses = JsonNodeFactory.instance.objectNode();
-        responses.set(String.valueOf(Response.Status.NO_CONTENT.getStatusCode()), buildResponse("Deleted"));
+        final Map<String, ResponseObject> responses = Map.of(String.valueOf(NO_CONTENT.getStatusCode()),
+            buildResponse("Deleted"));
 
         return new Operation.Builder()
             .tags(tags)
@@ -211,50 +207,52 @@ public final class OperationBuilder {
 
         final InputSchemaNode input = operDef.getInput();
         final OutputSchemaNode output = operDef.getOutput();
-        ObjectNode requestBody;
+        final RequestBody requestBody;
         if (!input.getChildNodes().isEmpty()) {
             final String discriminator = definitionNames.getDiscriminator(input);
             final String clearDefName = parentName + "_" + operationName + INPUT_SUFFIX;
             final String defName = clearDefName + discriminator;
             requestBody = createRequestBodyParameter(defName, INPUT_KEY, false, summary, inputName);
         } else {
-            final ObjectNode payload = JsonNodeFactory.instance.objectNode();
-            final ObjectNode jsonSchema = JsonNodeFactory.instance.objectNode();
-            final ObjectNode properties = JsonNodeFactory.instance.objectNode();
-            final ObjectNode inputSchema = JsonNodeFactory.instance.objectNode();
-            inputSchema.put(TYPE_KEY, OBJECT);
-            properties.set(INPUT_KEY, inputSchema);
-            jsonSchema.put(TYPE_KEY, OBJECT);
-            jsonSchema.set(PROPERTIES_KEY, properties);
-            final ObjectNode content = JsonNodeFactory.instance.objectNode();
-            final ObjectNode jsonTypeValue = JsonNodeFactory.instance.objectNode();
-            jsonTypeValue.set(SCHEMA_KEY, jsonSchema);
-            content.set(MediaType.APPLICATION_JSON, jsonTypeValue);
-
-            final ObjectNode xmlSchema = JsonNodeFactory.instance.objectNode();
-            xmlSchema.put(TYPE_KEY, OBJECT);
-            final ObjectNode xml = JsonNodeFactory.instance.objectNode();
-            xml.put(NAME_KEY, INPUT);
-            xmlSchema.set(XML_KEY, xml);
-            final ObjectNode xmlTypeValue = JsonNodeFactory.instance.objectNode();
-            xmlTypeValue.set(SCHEMA_KEY, xmlSchema);
-            content.set(MediaType.APPLICATION_XML, xmlTypeValue);
-
-            payload.set(CONTENT_KEY, content);
-            payload.put(DESCRIPTION_KEY, inputName);
-            requestBody = payload;
+            final Map<String, Property> properties = Map.of(INPUT_KEY, new Property.Builder().type(OBJECT).build());
+            final Schema jsonSchema = new Schema.Builder()
+                .type(OBJECT)
+                .properties(properties)
+                .build();
+            final MediaTypeObject jsonTypeValue = new MediaTypeObject.Builder()
+                .schema(jsonSchema)
+                .build();
+            final SimpleEntry<String, MediaTypeObject> jsonEntry = new SimpleEntry<>(MediaType.APPLICATION_JSON,
+                jsonTypeValue);
+
+            final Xml xml = new Xml(INPUT_KEY, null, null);
+            final Schema xmlSchema = new Schema.Builder()
+                .type(OBJECT)
+                .xml(xml)
+                .build();
+            final MediaTypeObject xmlTypeValue = new MediaTypeObject.Builder()
+                .schema(xmlSchema)
+                .build();
+            final SimpleEntry<String, MediaTypeObject> xmlEntry = new SimpleEntry<>(MediaType.APPLICATION_XML,
+                xmlTypeValue);
+
+            requestBody = new RequestBody.Builder()
+                .content(Map.of(jsonEntry.getKey(), jsonEntry.getValue(), xmlEntry.getKey(), xmlEntry.getValue()))
+                .description(inputName)
+                .build();
         }
-        final ObjectNode responses = JsonNodeFactory.instance.objectNode();
         final String description = String.format("RPC %s success", operationName);
 
+        final Map<String, ResponseObject> responses;
         if (!output.getChildNodes().isEmpty()) {
-            final ObjectNode schema = JsonNodeFactory.instance.objectNode();
             final String defName = parentName + "_" + operationName + OUTPUT_SUFFIX
-                    + definitionNames.getDiscriminator(output);
-            schema.put(REF_KEY, COMPONENTS_PREFIX + defName);
-            responses.set(String.valueOf(Response.Status.OK.getStatusCode()), buildResponse(description, schema));
+                + definitionNames.getDiscriminator(output);
+            final Schema schema = new Schema.Builder()
+                .ref(COMPONENTS_PREFIX + defName)
+                .build();
+            responses = Map.of(String.valueOf(OK.getStatusCode()), buildResponse(description, schema));
         } else {
-            responses.set(String.valueOf(Response.Status.NO_CONTENT.getStatusCode()), buildResponse(description));
+            responses = Map.of(String.valueOf(NO_CONTENT.getStatusCode()), buildResponse(description));
         }
         final String desc = operDef.getDescription().orElse("");
         final List<String> tags = List.of(deviceName + " " + moduleName);
@@ -268,77 +266,97 @@ public final class OperationBuilder {
             .build();
     }
 
-    private static ObjectNode createPostDataRequestBodyParameter(final String defName, final String name) {
-        final ObjectNode payload = JsonNodeFactory.instance.objectNode();
-        final ObjectNode content = JsonNodeFactory.instance.objectNode();
-        final ObjectNode value = buildMimeTypeValue(defName);
-        content.set(MediaType.APPLICATION_JSON, value);
-        content.set(MediaType.APPLICATION_XML, value);
-        payload.set(CONTENT_KEY, content);
-        payload.put(DESCRIPTION_KEY, name);
-        return payload;
+    private static RequestBody createPostDataRequestBodyParameter(final String defName, final String name) {
+        final MediaTypeObject value = buildMediaTypeObject(defName);
+        final Map<String, MediaTypeObject> content = Map.of(MediaType.APPLICATION_JSON, value,
+            MediaType.APPLICATION_XML, value);
+        return new RequestBody.Builder()
+            .content(content)
+            .description(name)
+            .build();
     }
 
-    private static ObjectNode createRequestBodyParameter(final String defName, final String name,
+    private static RequestBody createRequestBodyParameter(final String defName, final String name,
             final boolean isList, final String summary, final String description) {
-        final ObjectNode payload = JsonNodeFactory.instance.objectNode();
-        final ObjectNode content = JsonNodeFactory.instance.objectNode();
-        final ObjectNode properties = JsonNodeFactory.instance.objectNode();
+        final Map<String, MediaTypeObject> content = getStringMediaTypeObjectMap(defName, name, isList, summary);
+        return new RequestBody.Builder()
+            .content(content)
+            .description(description)
+            .build();
+    }
+
+    private static ResponseObject createResponse(final String defName, final String name,
+        final boolean isList, final String description, final String summary) {
+        final Map<String, MediaTypeObject> content = getStringMediaTypeObjectMap(defName, name, isList, summary);
+        return new ResponseObject.Builder()
+            .content(content)
+            .description(description)
+            .build();
+    }
+
+    private static Map<String, MediaTypeObject> getStringMediaTypeObjectMap(final String defName, final String name,
+            final boolean isList, final String summary) {
+        final Map<String, Property> properties;
         if (isList) {
-            final ObjectNode list = JsonNodeFactory.instance.objectNode();
-            final ObjectNode listValue = JsonNodeFactory.instance.objectNode();
-            listValue.put(TYPE_KEY, "array");
-            listValue.set("items", buildRefSchema(defName));
-            list.set(name, listValue);
-            properties.set(PROPERTIES_KEY, list);
+            properties = Map.of(name, new Property.Builder()
+                .type("array")
+                .items(new Property.Builder()
+                    .type(OBJECT)
+                    .ref(COMPONENTS_PREFIX + defName)
+                    .build())
+                .build());
         } else {
-            final ObjectNode container = JsonNodeFactory.instance.objectNode();
-            container.set(name, buildRefSchema(defName));
-            properties.set(PROPERTIES_KEY, container);
+            properties = Map.of(name, new Property.Builder()
+                .type(OBJECT)
+                .ref(COMPONENTS_PREFIX + defName)
+                .build());
         }
-        final ObjectNode jsonSchema = JsonNodeFactory.instance.objectNode();
-        jsonSchema.set(SCHEMA_KEY, properties);
+        final MediaTypeObject jsonSchema = new MediaTypeObject.Builder()
+            .schema(new Schema.Builder()
+                .properties(properties)
+                .build())
+            .build();
+        final Map<String, MediaTypeObject> content;
         if (summary != null && summary.contains(HttpMethod.PATCH)) {
-            content.set("application/yang-data+json", jsonSchema);
-            content.set("application/yang-data+xml", buildMimeTypeValue(defName));
+            content = Map.of("application/yang-data+json", jsonSchema,
+                "application/yang-data+xml", buildMediaTypeObject(defName));
         } else {
-            content.set(MediaType.APPLICATION_JSON, jsonSchema);
-            content.set(MediaType.APPLICATION_XML, buildMimeTypeValue(defName));
+            content = Map.of(MediaType.APPLICATION_JSON, jsonSchema,
+                MediaType.APPLICATION_XML, buildMediaTypeObject(defName));
         }
-        payload.set(CONTENT_KEY, content);
-        payload.put(DESCRIPTION_KEY, description);
-        return payload;
+        return content;
     }
 
-    private static ObjectNode buildRefSchema(final String defName) {
-        final ObjectNode schema = JsonNodeFactory.instance.objectNode();
-        schema.put(REF_KEY, COMPONENTS_PREFIX + defName);
-        return schema;
+    private static Schema buildRefSchema(final String defName) {
+        return new Schema.Builder()
+            .ref(COMPONENTS_PREFIX + defName)
+            .build();
     }
 
-    private static ObjectNode buildMimeTypeValue(final String defName) {
-        final ObjectNode mimeTypeValue = JsonNodeFactory.instance.objectNode();
-        mimeTypeValue.set(SCHEMA_KEY, buildRefSchema(defName));
-        return mimeTypeValue;
+    private static MediaTypeObject buildMediaTypeObject(final String defName) {
+        return new MediaTypeObject.Builder()
+            .schema(buildRefSchema(defName))
+            .build();
     }
 
-    private static ObjectNode buildResponse(final String description) {
-        final ObjectNode response = JsonNodeFactory.instance.objectNode();
-        response.put(DESCRIPTION_KEY, description);
-        return response;
+    private static ResponseObject buildResponse(final String description) {
+        return new ResponseObject.Builder()
+            .description(description)
+            .build();
     }
 
-    private static ObjectNode buildResponse(final String description, final ObjectNode schema) {
-        final ObjectNode response = JsonNodeFactory.instance.objectNode();
-        final ObjectNode content = JsonNodeFactory.instance.objectNode();
-        final ObjectNode body = JsonNodeFactory.instance.objectNode();
+    private static ResponseObject buildResponse(final String description, final Schema schema) {
+        final MediaTypeObject body = new MediaTypeObject.Builder()
+            .schema(schema)
+            .build();
+        final Map<String, MediaTypeObject> content = new HashMap<>();
         for (final String mimeType : MIME_TYPES) {
-            content.set(mimeType, body);
+            content.put(mimeType, body);
         }
-        body.set(SCHEMA_KEY, schema);
-        response.set(CONTENT_KEY, content);
-        response.put(DESCRIPTION_KEY, description);
-        return response;
+        return new ResponseObject.Builder()
+            .content(content)
+            .description(description)
+            .build();
     }
 
     private static DataSchemaNode getListOrContainerChildNode(final DataSchemaNode node) {
index a377408204cf5dd75138ecd9252887cbf7b200d8..61b680c517a8d3e3300ee0a82db4b647e8aa33b9 100644 (file)
@@ -19,11 +19,8 @@ import static org.opendaylight.restconf.openapi.impl.BaseYangOpenApiGenerator.SE
 import static org.opendaylight.restconf.openapi.impl.BaseYangOpenApiGenerator.filterByRange;
 import static org.opendaylight.restconf.openapi.impl.BaseYangOpenApiGenerator.getSortedModules;
 import static org.opendaylight.restconf.openapi.impl.OpenApiServiceImpl.DEFAULT_PAGESIZE;
-import static org.opendaylight.restconf.openapi.model.builder.OperationBuilder.DESCRIPTION_KEY;
 import static org.opendaylight.restconf.openapi.model.builder.OperationBuilder.SUMMARY_TEMPLATE;
 
-import com.fasterxml.jackson.databind.node.JsonNodeFactory;
-import com.fasterxml.jackson.databind.node.ObjectNode;
 import com.google.common.collect.Range;
 import java.util.HashMap;
 import java.util.List;
@@ -46,6 +43,7 @@ import org.opendaylight.restconf.openapi.model.Info;
 import org.opendaylight.restconf.openapi.model.OpenApiObject;
 import org.opendaylight.restconf.openapi.model.Operation;
 import org.opendaylight.restconf.openapi.model.Path;
+import org.opendaylight.restconf.openapi.model.ResponseObject;
 import org.opendaylight.restconf.openapi.model.Schema;
 import org.opendaylight.restconf.openapi.model.Server;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
@@ -259,13 +257,12 @@ public class MountPointOpenApi implements DOMMountPointListener, AutoCloseable {
             final String deviceName) {
         final String summary = SUMMARY_TEMPLATE.formatted(HttpMethod.GET, deviceName, "datastore", resourceType);
         final List<String> tags = List.of(deviceName + " GET root");
-        final ObjectNode okResponse = JsonNodeFactory.instance.objectNode();
-        okResponse.put(DESCRIPTION_KEY, Response.Status.OK.getReasonPhrase());
-        final ObjectNode responses = JsonNodeFactory.instance.objectNode();
-        responses.set(String.valueOf(Response.Status.OK.getStatusCode()), okResponse);
+        final ResponseObject okResponse = new ResponseObject.Builder()
+            .description(Response.Status.OK.getReasonPhrase())
+            .build();
         return new Operation.Builder()
             .tags(tags)
-            .responses(responses)
+            .responses(Map.of(String.valueOf(Response.Status.OK.getStatusCode()), okResponse))
             .description(description)
             .summary(summary)
             .build();
index 06d776182771bb9f308d6e7e1280e183dd064db7..d04eb4d959c20b8e9db6596583f28558799b4c68 100644 (file)
@@ -69,8 +69,8 @@ public class JsonModelNameTest {
     }
 
     private static String getSchemaPutOperationModuleName(final Operation put) {
-        final var parentName  = put.requestBody().path("content").path("application/json").path("schema")
-            .path("properties").properties().iterator().next().getKey();
+        final var parentName  = put.requestBody().content().get("application/json").schema().properties()
+            .keySet().iterator().next();
 
         final var doubleDotsIndex = parentName.indexOf(':');
         if (doubleDotsIndex >= 0 && doubleDotsIndex < parentName.length() - 1) {
index 2b168b30509a791882b2317958167fb5a6d4b9bb..8637083a09a34dd40e340d20d53c92d42bafc3b9 100644 (file)
@@ -13,7 +13,6 @@ import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
-import com.fasterxml.jackson.databind.JsonNode;
 import java.util.Map;
 import java.util.Optional;
 import java.util.Set;
@@ -98,31 +97,31 @@ public class OperationalDataTest {
         for (final var path : paths.values()) {
             if (path.get() != null) {
                 final var responses = path.get().responses();
-                final var response = responses.elements().next();
-                final var content = response.get("content");
+                final var response = responses.values().iterator().next();
+                final var content = response.content();
                 // In case of 200 no content
                 if (content != null) {
-                    verifyOperationHaveCorrectXmlReference(content.get("application/xml").get("schema"));
-                    verifyOperationHaveCorrectJsonReference(content.get("application/json").get("schema"));
+                    verifyOperationHaveCorrectXmlReference(content.get("application/xml").schema());
+                    verifyOperationHaveCorrectJsonReference(content.get("application/json").schema());
                 }
             }
             if (path.put() != null) {
                 final var responses = path.put().requestBody();
-                final var content = responses.get("content");
-                verifyOperationHaveCorrectXmlReference(content.get("application/xml").get("schema"));
-                verifyOperationHaveCorrectJsonReference(content.get("application/json").get("schema"));
+                final var content = responses.content();
+                verifyOperationHaveCorrectXmlReference(content.get("application/xml").schema());
+                verifyOperationHaveCorrectJsonReference(content.get("application/json").schema());
             }
             if (path.post() != null) {
                 final var responses = path.post().requestBody();
-                final var content = responses.get("content");
-                verifyOperationHaveCorrectXmlReference(content.get("application/xml").get("schema"));
-                verifyOperationHaveCorrectJsonReference(content.get("application/json").get("schema"));
+                final var content = responses.content();
+                verifyOperationHaveCorrectXmlReference(content.get("application/xml").schema());
+                verifyOperationHaveCorrectJsonReference(content.get("application/json").schema());
             }
             if (path.patch() != null) {
                 final var responses = path.patch().requestBody();
-                final var content = responses.get("content");
-                verifyOperationHaveCorrectXmlReference(content.get("application/yang-data+xml").get("schema"));
-                verifyOperationHaveCorrectJsonReference(content.get("application/yang-data+json").get("schema"));
+                final var content = responses.content();
+                verifyOperationHaveCorrectXmlReference(content.get("application/yang-data+xml").schema());
+                verifyOperationHaveCorrectJsonReference(content.get("application/yang-data+json").schema());
             }
         }
     }
@@ -230,37 +229,36 @@ public class OperationalDataTest {
         assertEquals(Set.of("ca-output"), actualProperties);
     }
 
-    private static void verifyOperationHaveCorrectXmlReference(final JsonNode schema) {
-        final var ref = schema.get("$ref");
+    private static void verifyOperationHaveCorrectXmlReference(final Schema schema) {
+        final var refValue = schema.ref();
         // In case of a POST RPC with a direct input body and no reference value
-        if (ref != null) {
-            final var refValue = ref.textValue();
+        if (refValue != null) {
             final var schemaElement = refValue.substring(refValue.lastIndexOf("/") + 1);
             assertTrue("Reference [" + refValue + "] not found in EXPECTED Schemas",
                 EXPECTED_SCHEMAS.contains(schemaElement));
         } else {
-            final var type = schema.get("type");
+            final var type = schema.type();
             assertNotNull(type);
-            assertEquals("object", type.asText());
+            assertEquals("object", type);
         }
     }
 
-    private static void verifyOperationHaveCorrectJsonReference(final JsonNode schema) {
-        final var properties = schema.findPath("properties");
+    private static void verifyOperationHaveCorrectJsonReference(final Schema schema) {
+        final var properties = schema.properties();
         final String refValue;
-        if (!properties.isMissingNode()) {
-            final var node = properties.elements().next();
-            final var type = node.path("type");
-            if (type.isMissingNode()) {
-                refValue = node.path("$ref").asText();
-            } else if (type.asText().equals("array")) {
-                refValue = node.path("items").path("$ref").asText();
+        if (properties != null) {
+            final var node = properties.values().iterator().next();
+            final var type = node.type();
+            if (type == null) {
+                refValue = node.ref();
+            } else if (type.equals("array")) {
+                refValue = node.items().ref();
             } else {
-                assertEquals("object", type.asText());
+                assertEquals("object", type);
                 return;
             }
         } else {
-            refValue = schema.path("$ref").asText();
+            refValue = schema.ref();
         }
         final var schemaElement = refValue.substring(refValue.lastIndexOf("/") + 1);
         assertTrue("Reference [" + refValue + "] not found in EXPECTED Schemas",
index e542df9271df17a2eb88fc97755861f69f2d7e96..74782cf6705c875e9471f3405da9d34b855d2055 100644 (file)
@@ -12,7 +12,6 @@ import static org.junit.Assert.assertNotNull;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
-import java.util.Collection;
 import java.util.List;
 import java.util.Optional;
 import javax.ws.rs.core.UriInfo;
@@ -22,8 +21,10 @@ import org.opendaylight.mdsal.dom.api.DOMMountPoint;
 import org.opendaylight.mdsal.dom.api.DOMMountPointService;
 import org.opendaylight.mdsal.dom.api.DOMSchemaService;
 import org.opendaylight.restconf.openapi.impl.MountPointOpenApiGeneratorRFC8040;
+import org.opendaylight.restconf.openapi.model.MediaTypeObject;
 import org.opendaylight.restconf.openapi.model.OpenApiObject;
 import org.opendaylight.restconf.openapi.model.Operation;
+import org.opendaylight.restconf.openapi.model.Schema;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
@@ -80,12 +81,34 @@ public class SchemaObjectsTest {
      * @return name of the schema used for operation
      */
     private static String extractSchemaName(final Operation operation) {
-        final var schemas = operation.requestBody().path("content").findValues("schema");
         // Find distinct schema refs
-        final var references = schemas.stream().map(s -> s.findValues("$ref"))
-                .flatMap(Collection::stream).distinct().toList();
+        final var references = operation.requestBody().content().values().stream()
+            .map(MediaTypeObject::schema)
+            .map(SchemaObjectsTest::getRef)
+            .distinct()
+            .toList();
         // Assert all schema refs are same
         assertEquals("Inconsistent schemas for operation: " + operation.summary(), 1, references.size());
-        return references.get(0).textValue().replaceAll("#/components/schemas/", "");
+        return references.get(0).replaceAll("#/components/schemas/", "");
+    }
+
+    private static String getRef(final Schema schema) {
+        final String ref;
+        if (schema.ref() != null) {
+            ref = schema.ref();
+        } else {
+            final var properties = schema.properties();
+            if (properties != null && !properties.isEmpty()) {
+                final var property = schema.properties().values().iterator().next();
+                if (property.type().equals("array")) {
+                    ref = property.items().ref();
+                } else {
+                    ref = property.ref();
+                }
+            } else {
+                ref = null;
+            }
+        }
+        return ref;
     }
 }
index b4222956af345c6cbb25032024fa5d5273c459ee..60348abd9f92d684d5d19f06e0006a99c17c6a16 100644 (file)
@@ -19,7 +19,6 @@ import static org.opendaylight.restconf.openapi.OpenApiTestUtils.getPathPostPara
 import static org.opendaylight.restconf.openapi.impl.BaseYangOpenApiGenerator.BASIC_AUTH_NAME;
 import static org.opendaylight.restconf.openapi.model.builder.OperationBuilder.COMPONENTS_PREFIX;
 
-import com.fasterxml.jackson.databind.JsonNode;
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
@@ -30,6 +29,7 @@ import org.junit.BeforeClass;
 import org.junit.Test;
 import org.opendaylight.mdsal.dom.api.DOMSchemaService;
 import org.opendaylight.restconf.openapi.DocGenTestHelper;
+import org.opendaylight.restconf.openapi.model.MediaTypeObject;
 import org.opendaylight.restconf.openapi.model.OpenApiObject;
 import org.opendaylight.restconf.openapi.model.Operation;
 import org.opendaylight.restconf.openapi.model.Path;
@@ -365,13 +365,11 @@ public final class OpenApiGeneratorRFC8040Test {
         final var jsonNodeCancelToast = doc.paths().get("/rests/operations/toaster2:cancel-toast");
         assertNull(jsonNodeCancelToast.get());
         // Test RPC with empty input
-        final var postContent = jsonNodeCancelToast.post().requestBody().get("content");
-        final var jsonSchema = postContent.get("application/json").get("schema");
-        assertNull(jsonSchema.get("$ref"));
-        assertEquals(2, jsonSchema.size());
-        final var xmlSchema = postContent.get("application/xml").get("schema");
-        assertNull(xmlSchema.get("$ref"));
-        assertEquals(2, xmlSchema.size());
+        final var postContent = jsonNodeCancelToast.post().requestBody().content();
+        final var jsonSchema = postContent.get("application/json").schema();
+        assertNull(jsonSchema.ref());
+        final var xmlSchema = postContent.get("application/xml").schema();
+        assertNull(xmlSchema.ref());
 
         // Test `components/schemas` objects
         final var definitions = doc.components().schemas();
@@ -408,42 +406,41 @@ public final class OpenApiGeneratorRFC8040Test {
      */
     private static void verifyPostDataRequestRef(final Operation operation, final String expectedJsonRef,
             final String expectedXmlRef) {
-        final JsonNode postContent;
+        final Map<String, MediaTypeObject> postContent;
         if (operation.requestBody() != null) {
-            postContent = operation.requestBody().get("content");
+            postContent = operation.requestBody().content();
         } else {
-            postContent = operation.responses().get("200").get("content");
+            postContent = operation.responses().get("200").content();
         }
         assertNotNull(postContent);
-        final var postJsonRef = postContent.get("application/json").get("schema").get("$ref");
+        final var postJsonRef = postContent.get("application/json").schema().ref();
         assertNotNull(postJsonRef);
-        assertEquals(expectedJsonRef, postJsonRef.textValue());
-        final var postXmlRef = postContent.get("application/xml").get("schema").get("$ref");
+        assertEquals(expectedJsonRef, postJsonRef);
+        final var postXmlRef = postContent.get("application/xml").schema().ref();
         assertNotNull(postXmlRef);
-        assertEquals(expectedXmlRef, postXmlRef.textValue());
+        assertEquals(expectedXmlRef, postXmlRef);
     }
 
     private static void verifyRequestRef(final Operation operation, final String expectedRef, final String nodeType) {
-        final JsonNode postContent;
+        final Map<String, MediaTypeObject> postContent;
         if (operation.requestBody() != null) {
-            postContent = operation.requestBody().path("content");
+            postContent = operation.requestBody().content();
         } else {
-            postContent = operation.responses().path("200").path("content");
+            postContent = operation.responses().get("200").content();
         }
         assertNotNull(postContent);
         final String postJsonRef;
         if (nodeType.equals(CONTAINER)) {
-            postJsonRef = postContent.path("application/json").path("schema").path("properties").elements().next()
-                .path("$ref").textValue();
+            postJsonRef = postContent.get("application/json").schema().properties().values().iterator().next().ref();
         } else {
-            postJsonRef = postContent.path("application/json").path("schema").path("properties").elements().next()
-                .path("items").path("$ref").textValue();
+            postJsonRef = postContent.get("application/json").schema().properties().values().iterator().next().items()
+                .ref();
         }
         assertNotNull(postJsonRef);
         assertEquals(expectedRef, postJsonRef);
-        final var postXmlRef = postContent.path("application/xml").path("schema").path("$ref");
+        final var postXmlRef = postContent.get("application/xml").schema().ref();
         assertNotNull(postXmlRef);
-        assertEquals(expectedRef, postXmlRef.textValue());
+        assertEquals(expectedRef, postXmlRef);
     }
 
     private static void verifyThatOthersNodeDoesNotHaveRequiredField(final List<String> expected,
@@ -471,19 +468,19 @@ public final class OpenApiGeneratorRFC8040Test {
         final var references = new HashSet<String>();
         final var get = path.get();
         if (get != null) {
-            references.addAll(schemaRefFromContent(get.responses().path("200").path("content")));
+            references.addAll(schemaRefFromContent(get.responses().get("200").content()));
         }
         final var post = path.post();
         if (post != null) {
-            references.addAll(schemaRefFromContent(post.requestBody().path("content")));
+            references.addAll(schemaRefFromContent(post.requestBody().content()));
         }
         final var put = path.put();
         if (put != null) {
-            references.addAll(schemaRefFromContent(put.requestBody().path("content")));
+            references.addAll(schemaRefFromContent(put.requestBody().content()));
         }
         final var patch = path.patch();
         if (patch != null) {
-            references.addAll(schemaRefFromContent(patch.requestBody().path("content")));
+            references.addAll(schemaRefFromContent(patch.requestBody().content()));
         }
         return references;
     }
@@ -499,27 +496,26 @@ public final class OpenApiGeneratorRFC8040Test {
      * @param content the element identified with key "content"
      * @return the set of referenced schemas
      */
-    private static Set<String> schemaRefFromContent(final JsonNode content) {
+    private static Set<String> schemaRefFromContent(final Map<String, MediaTypeObject> content) {
         final HashSet<String> refs = new HashSet<>();
-        content.fieldNames().forEachRemaining(mediaType -> {
-            final JsonNode schema = content.path(mediaType).path("schema");
-            final JsonNode props = schema.path("properties");
-            final JsonNode nameNode = props.isMissingNode() ? props : props.elements().next().path("items");
-            final JsonNode ref;
-            if (props.isMissingNode()) {
+        content.values().forEach(mediaType -> {
+            final var schema = mediaType.schema();
+            final var props = mediaType.schema().properties();
+            final String ref;
+            if (props == null) {
                 // either there is no node with the key "properties", try to find immediate child of schema
-                ref = schema.path("$ref");
-            } else if (nameNode.path("items").isMissingNode()) {
+                ref = schema.ref();
+            } else if (props.values().iterator().next().items() == null) {
                 // or the "properties" is defined and under that we didn't find the "items" node
-                // try to get "$ref" as immediate child under nameNode
-                ref = nameNode.path("$ref");
+                // try to get "$ref" as immediate child under properties
+                ref = props.values().iterator().next().ref();
             } else {
                 // or the "items" node is defined, in which case we try to get the "$ref" from this node
-                ref = nameNode.path("items").path("$ref");
+                ref = props.values().iterator().next().items().ref();
             }
 
-            if (ref != null && !ref.isMissingNode()) {
-                refs.add(ref.asText().replaceFirst(COMPONENTS_PREFIX, ""));
+            if (ref != null) {
+                refs.add(ref.replaceFirst(COMPONENTS_PREFIX, ""));
             }
         });
         return refs;
index feced2b90a52bf058fb735b591849e551d04b61d..e2d5fd3f56af747d417df37a7ca03b85499374b0 100644 (file)
@@ -103,8 +103,6 @@ public class PostPayloadTest {
                 }
               }
             }""";
-    private static final String CONTENT_KEY = "content";
-    private static final String SCHEMA_KEY = "schema";
 
     private static OpenApiObject containerDoc;
     private static OpenApiObject listDoc;
@@ -127,24 +125,21 @@ public class PostPayloadTest {
         final var path1 = "/rests/data/container-test:cont";
         assertTrue(containerDoc.paths().containsKey(path1));
         final var jsonRef1 = getJsonRef(containerDoc, path1);
-        assertEquals("{\"cont1\":{\"$ref\":\"#/components/schemas/container-test_cont_cont1\"}}",
-            jsonRef1);
+        assertEquals("#/components/schemas/container-test_cont_cont1", jsonRef1);
         final var xmlRef1 = getXmlRef(containerDoc, path1);
         assertEquals("#/components/schemas/container-test_cont_cont1", xmlRef1);
 
         final var path2 = "/rests/data/container-test:cont/cont1";
         assertTrue(containerDoc.paths().containsKey(path2));
         final var jsonRef2 = getJsonRef(containerDoc, path2);
-        assertEquals("{\"list4\":{\"type\":\"array\",\"items\":{\"$ref\":\""
-                + "#/components/schemas/container-test_cont_cont1_list4\"}}}", jsonRef2);
+        assertEquals("#/components/schemas/container-test_cont_cont1_list4", jsonRef2);
         final var xmlRef2 = getXmlRef(containerDoc, path2);
         assertEquals("#/components/schemas/container-test_cont_cont1_list4", xmlRef2);
 
         final var path4 = "/rests/data/container-test:cont/cont1/list4={key4}/cont2";
         assertTrue(containerDoc.paths().containsKey(path4));
         final var jsonRef4 = getJsonRef(containerDoc, path4);
-        assertEquals("{\"list5\":{\"type\":\"array\",\"items\":{\"$ref\":\""
-                + "#/components/schemas/container-test_cont_cont1_list4_cont2_list5\"}}}", jsonRef4);
+        assertEquals("#/components/schemas/container-test_cont_cont1_list4_cont2_list5", jsonRef4);
         final var xmlRef4 = getXmlRef(containerDoc, path4);
         assertEquals("#/components/schemas/container-test_cont_cont1_list4_cont2_list5", xmlRef4);
     }
@@ -154,19 +149,23 @@ public class PostPayloadTest {
         final var path1 = "/rests/data/list-test:cont";
         assertTrue(listDoc.paths().containsKey(path1));
         final var jsonRef1 = getJsonRef(listDoc, path1);
-        assertEquals("{\"list1\":{\"type\":\"array\",\"items\":{\"$ref\":\""
-            + "#/components/schemas/list-test_cont_list1\"}}}", jsonRef1);
+        assertEquals("#/components/schemas/list-test_cont_list1", jsonRef1);
         final var xmlRef1 = getXmlRef(listDoc, path1);
         assertEquals("#/components/schemas/list-test_cont_list1", xmlRef1);
     }
 
     private static String getJsonRef(final OpenApiObject openApiObject, final String path) {
-        return openApiObject.paths().get(path).post().requestBody().get(CONTENT_KEY).get("application/json")
-            .get(SCHEMA_KEY).get("properties").toString();
+        final var property = openApiObject.paths().get(path).post().requestBody().content().get("application/json")
+            .schema().properties().values().iterator().next();
+        if (property.type().equals("object")) {
+            return property.ref();
+        } else {
+            return property.items().ref();
+        }
     }
 
     private static String getXmlRef(final OpenApiObject openApiObject, final String path) {
-        return openApiObject.paths().get(path).post().requestBody().get(CONTENT_KEY).get(
-            "application/xml").get(SCHEMA_KEY).get("$ref").asText();
+        return openApiObject.paths().get(path).post().requestBody().content().get(
+            "application/xml").schema().ref();
     }
 }