Use Java Schema object instead of JsonNode 89/105989/12
authorOleksandrZharov <Oleksandr.Zharov@pantheon.tech>
Tue, 16 May 2023 10:30:38 +0000 (12:30 +0200)
committerIvan Hrasko <ivan.hrasko@pantheon.tech>
Thu, 18 May 2023 13:31:29 +0000 (15:31 +0200)
Created Schema.java object and replaced ObjectNode schemas inside
Components class with Map<String, Schema>. This allowed us remove
JsonUtil#addFields method which is addressed by another issue.

JIRA: NETCONF-1024
Change-Id: I13477fae13298b782df4af6e100fe9f807b331bd
Signed-off-by: OleksandrZharov <Oleksandr.Zharov@pantheon.tech>
Signed-off-by: Ivan Hrasko <ivan.hrasko@pantheon.tech>
restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/impl/BaseYangOpenApiGenerator.java
restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/impl/DefinitionGenerator.java
restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/model/Components.java
restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/model/Schema.java [new file with mode: 0644]
restconf/restconf-openapi/src/test/java/org/opendaylight/restconf/openapi/DocGenTestHelper.java
restconf/restconf-openapi/src/test/java/org/opendaylight/restconf/openapi/impl/DefinitionGeneratorTest.java
restconf/restconf-openapi/src/test/java/org/opendaylight/restconf/openapi/impl/OpenApiGeneratorRFC8040Test.java

index 8c908a21bc5602e314e2f5691a28483553c724fa..b723a73258b83b35c958cca63f92409aec58a6d0 100644 (file)
@@ -15,7 +15,6 @@ import static org.opendaylight.restconf.openapi.model.builder.OperationBuilder.b
 import static org.opendaylight.restconf.openapi.model.builder.OperationBuilder.buildPostOperation;
 import static org.opendaylight.restconf.openapi.model.builder.OperationBuilder.buildPut;
 import static org.opendaylight.restconf.openapi.model.builder.OperationBuilder.getTypeParentNode;
-import static org.opendaylight.restconf.openapi.util.JsonUtil.addFields;
 import static org.opendaylight.restconf.openapi.util.RestDocgenUtil.resolvePathArgumentsName;
 
 import com.fasterxml.jackson.databind.JsonNode;
@@ -45,6 +44,7 @@ import org.opendaylight.restconf.openapi.model.Components;
 import org.opendaylight.restconf.openapi.model.Info;
 import org.opendaylight.restconf.openapi.model.OpenApiObject;
 import org.opendaylight.restconf.openapi.model.Path;
+import org.opendaylight.restconf.openapi.model.Schema;
 import org.opendaylight.restconf.openapi.model.SecuritySchemes;
 import org.opendaylight.restconf.openapi.model.Server;
 import org.opendaylight.restconf.openapi.util.JsonUtil;
@@ -218,13 +218,9 @@ public abstract class BaseYangOpenApiGenerator {
             final EffectiveModelContext schemaContext, final DefinitionNames definitionNames, final OpenApiObject doc,
             final boolean isForSingleModule) {
         try {
-            final ObjectNode schema;
-            if (isForSingleModule) {
-                schema = jsonConverter.convertToJsonSchema(module, schemaContext, definitionNames, true);
-            } else {
-                schema = jsonConverter.convertToJsonSchema(module, schemaContext, definitionNames, false);
-            }
-            addFields(doc.getComponents().getSchemas(), schema.fields());
+            final Map<String, Schema> schemas = jsonConverter.convertToJsonSchema(module, schemaContext,
+                definitionNames, isForSingleModule);
+            doc.getComponents().getSchemas().putAll(schemas);
             if (LOG.isDebugEnabled()) {
                 LOG.debug("Document: {}", MAPPER.writeValueAsString(doc));
             }
@@ -310,8 +306,7 @@ public abstract class BaseYangOpenApiGenerator {
         info.setVersion(API_VERSION);
         doc.setInfo(info);
         doc.setServers(List.of(new Server(schema + "://" + host + basePath)));
-        doc.setComponents(new Components(JsonNodeFactory.instance.objectNode(),
-                new SecuritySchemes(OPEN_API_BASIC_AUTH)));
+        doc.setComponents(new Components(new HashMap<>(), new SecuritySchemes(OPEN_API_BASIC_AUTH)));
         doc.setSecurity(SECURITY);
         return doc;
     }
index 70cfa30a9a1f80ab85eee494fcc38a3077153cf5..cc3ca039df5eea3f87b47f07e25710a8735eb489 100644 (file)
@@ -27,6 +27,7 @@ import com.mifmif.common.regex.Generex;
 import java.io.IOException;
 import java.math.BigDecimal;
 import java.util.Collection;
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
@@ -34,6 +35,7 @@ import java.util.Optional;
 import java.util.Set;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
+import org.opendaylight.restconf.openapi.model.Schema;
 import org.opendaylight.yangtools.yang.common.Decimal64;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.model.api.ActionDefinition;
@@ -99,11 +101,9 @@ public class DefinitionGenerator {
     private static final String MIN_ITEMS = "minItems";
     private static final String MAX_LENGTH_KEY = "maxLength";
     private static final String MIN_LENGTH_KEY = "minLength";
-    private static final String REQUIRED_KEY = "required";
     private static final String REF_KEY = "$ref";
     private static final String ITEMS_KEY = "items";
     private static final String TYPE_KEY = "type";
-    private static final String PROPERTIES_KEY = "properties";
     private static final String DESCRIPTION_KEY = "description";
     private static final String ARRAY_TYPE = "array";
     private static final String ENUM_KEY = "enum";
@@ -142,9 +142,9 @@ public class DefinitionGenerator {
      */
 
 
-    public ObjectNode convertToJsonSchema(final Module module, final EffectiveModelContext schemaContext,
-            final ObjectNode definitions, final DefinitionNames definitionNames, final boolean isForSingleModule)
-            throws IOException {
+    public Map<String, Schema> convertToJsonSchema(final Module module, final EffectiveModelContext schemaContext,
+            final Map<String, Schema> definitions, final DefinitionNames definitionNames,
+            final boolean isForSingleModule) throws IOException {
         topLevelModule = module;
 
         processIdentities(module, definitions, definitionNames, schemaContext);
@@ -158,19 +158,19 @@ public class DefinitionGenerator {
         return definitions;
     }
 
-    public ObjectNode convertToJsonSchema(final Module module, final EffectiveModelContext schemaContext,
+    public Map<String, Schema> convertToJsonSchema(final Module module, final EffectiveModelContext schemaContext,
             final DefinitionNames definitionNames, final boolean isForSingleModule)
             throws IOException {
-        final ObjectNode definitions = JsonNodeFactory.instance.objectNode();
+        final Map<String, Schema> definitions = new HashMap<>();
         if (isForSingleModule) {
             definitionNames.addUnlinkedName(module.getName() + MODULE_NAME_SUFFIX);
         }
         return convertToJsonSchema(module, schemaContext, definitions, definitionNames, isForSingleModule);
     }
 
-    private void processModule(final Module module, final ObjectNode definitions, final DefinitionNames definitionNames,
-            final EffectiveModelContext schemaContext) {
-        final ObjectNode definition = JsonNodeFactory.instance.objectNode();
+    private void processModule(final Module module, final Map<String, Schema> definitions,
+            final DefinitionNames definitionNames, final EffectiveModelContext schemaContext) {
+        final Schema definition = new Schema();
         final ObjectNode properties = JsonNodeFactory.instance.objectNode();
         final ArrayNode required = JsonNodeFactory.instance.arrayNode();
         final String moduleName = module.getName();
@@ -217,16 +217,16 @@ public class DefinitionGenerator {
             }
             stack.exit();
         }
-        definition.put(TITLE_KEY, definitionName);
-        definition.put(TYPE_KEY, OBJECT_TYPE);
-        definition.set(PROPERTIES_KEY, properties);
-        definition.put(DESCRIPTION_KEY, module.getDescription().orElse(""));
+        definition.setTitle(definitionName);
+        definition.setType(OBJECT_TYPE);
+        definition.setProperties(properties);
+        definition.setDescription(module.getDescription().orElse(""));
         setRequiredIfNotEmpty(definition, required);
 
-        definitions.set(definitionName, definition);
+        definitions.put(definitionName, definition);
     }
 
-    private void processContainersAndLists(final Module module, final ObjectNode definitions,
+    private void processContainersAndLists(final Module module, final Map<String, Schema> definitions,
             final DefinitionNames definitionNames, final EffectiveModelContext schemaContext)  throws IOException {
         final String moduleName = module.getName();
         final SchemaInferenceStack stack = SchemaInferenceStack.of(schemaContext);
@@ -247,8 +247,8 @@ public class DefinitionGenerator {
     }
 
     private void processActionNodeContainer(final DataSchemaNode childNode, final String moduleName,
-            final ObjectNode definitions, final DefinitionNames definitionNames, final SchemaInferenceStack stack)
-            throws IOException {
+            final Map<String, Schema> definitions, final DefinitionNames definitionNames,
+            final SchemaInferenceStack stack) throws IOException {
         for (final ActionDefinition actionDef : ((ActionNodeContainer) childNode).getActions()) {
             stack.enterSchemaTree(actionDef.getQName());
             processOperations(actionDef, moduleName, definitions, definitionNames, stack);
@@ -256,8 +256,8 @@ public class DefinitionGenerator {
         }
     }
 
-    private void processRPCs(final Module module, final ObjectNode definitions, final DefinitionNames definitionNames,
-            final EffectiveModelContext schemaContext) throws IOException {
+    private void processRPCs(final Module module, final Map<String, Schema> definitions,
+            final DefinitionNames definitionNames, final EffectiveModelContext schemaContext) throws IOException {
         final String moduleName = module.getName();
         final SchemaInferenceStack stack = SchemaInferenceStack.of(schemaContext);
         for (final RpcDefinition rpcDefinition : module.getRpcs()) {
@@ -268,8 +268,8 @@ public class DefinitionGenerator {
     }
 
     private void processOperations(final OperationDefinition operationDef, final String parentName,
-            final ObjectNode definitions, final DefinitionNames definitionNames, final SchemaInferenceStack stack)
-            throws IOException {
+            final Map<String, Schema> definitions, final DefinitionNames definitionNames,
+            final SchemaInferenceStack stack) throws IOException {
         final String operationName = operationDef.getQName().getLocalName();
         processOperationInputOutput(operationDef.getInput(), operationName, parentName, true, definitions,
                 definitionNames, stack);
@@ -278,24 +278,24 @@ public class DefinitionGenerator {
     }
 
     private void processOperationInputOutput(final ContainerLike container, final String operationName,
-            final String parentName, final boolean isInput, final ObjectNode definitions,
+            final String parentName, final boolean isInput, final Map<String, Schema> definitions,
             final DefinitionNames definitionNames, final SchemaInferenceStack stack)
             throws IOException {
         stack.enterSchemaTree(container.getQName());
         if (!container.getChildNodes().isEmpty()) {
             final String filename = parentName + "_" + operationName + (isInput ? INPUT_SUFFIX : OUTPUT_SUFFIX);
-            final ObjectNode childSchema = JsonNodeFactory.instance.objectNode();
+            final Schema childSchema = new Schema();
             processChildren(childSchema, container.getChildNodes(), parentName, definitions, definitionNames,
                     false, stack);
 
-            childSchema.put(TYPE_KEY, OBJECT_TYPE);
+            childSchema.setType(OBJECT_TYPE);
             final ObjectNode xml = JsonNodeFactory.instance.objectNode();
             xml.put(NAME_KEY, isInput ? INPUT : OUTPUT);
-            childSchema.set(XML_KEY, xml);
-            childSchema.put(TITLE_KEY, filename);
+            childSchema.setXml(xml);
+            childSchema.setTitle(filename);
             final String discriminator =
                     definitionNames.pickDiscriminator(container, List.of(filename, filename + TOP));
-            definitions.set(filename + discriminator, childSchema);
+            definitions.put(filename + discriminator, childSchema);
 
             processTopData(filename, discriminator, definitions, container);
         }
@@ -303,7 +303,7 @@ public class DefinitionGenerator {
     }
 
     private static ObjectNode processTopData(final String filename, final String discriminator,
-            final ObjectNode definitions, final SchemaNode schemaNode) {
+            final Map<String, Schema> definitions, final SchemaNode schemaNode) {
         final ObjectNode dataNodeProperties = JsonNodeFactory.instance.objectNode();
         final String name = filename + discriminator;
         final String ref = COMPONENTS_PREFIX + name;
@@ -329,13 +329,13 @@ public class DefinitionGenerator {
             use RestDocGenUtil#resolveNodesName for creating property name
          */
         properties.set(schemaNode.getQName().getLocalName(), dataNodeProperties);
-        final ObjectNode finalChildSchema = JsonNodeFactory.instance.objectNode();
-        finalChildSchema.put(TYPE_KEY, OBJECT_TYPE);
-        finalChildSchema.set(PROPERTIES_KEY, properties);
-        finalChildSchema.put(TITLE_KEY, topName);
+        final Schema finalChildSchema = new Schema();
+        finalChildSchema.setType(OBJECT_TYPE);
+        finalChildSchema.setProperties(properties);
+        finalChildSchema.setTitle(topName);
 
 
-        definitions.set(topName + discriminator, finalChildSchema);
+        definitions.put(topName + discriminator, finalChildSchema);
 
         return dataNodeProperties;
     }
@@ -346,18 +346,18 @@ public class DefinitionGenerator {
      * @param definitions     The ObjectNode in which the parsed identity will be put as a 'model' obj
      * @param definitionNames Store for definition names
      */
-    private static void processIdentities(final Module module, final ObjectNode definitions,
+    private static void processIdentities(final Module module, final Map<String, Schema> definitions,
             final DefinitionNames definitionNames, final EffectiveModelContext context) {
         final String moduleName = module.getName();
         final Collection<? extends IdentitySchemaNode> idNodes = module.getIdentities();
         LOG.debug("Processing Identities for module {} . Found {} identity statements", moduleName, idNodes.size());
 
         for (final IdentitySchemaNode idNode : idNodes) {
-            final ObjectNode identityObj = buildIdentityObject(idNode, context);
+            final Schema identityObj = buildIdentityObject(idNode, context);
             final String idName = idNode.getQName().getLocalName();
             final String discriminator = definitionNames.pickDiscriminator(idNode, List.of(idName));
             final String name = idName + discriminator;
-            definitions.set(name, identityObj);
+            definitions.put(name, identityObj);
         }
     }
 
@@ -370,13 +370,13 @@ public class DefinitionGenerator {
     }
 
     private ObjectNode processDataNodeContainer(final DataNodeContainer dataNode, final String parentName,
-            final ObjectNode definitions, final DefinitionNames definitionNames, final boolean isConfig,
+            final Map<String, Schema> definitions, final DefinitionNames definitionNames, final boolean isConfig,
             final SchemaInferenceStack stack) throws IOException {
         if (dataNode instanceof ListSchemaNode || dataNode instanceof ContainerSchemaNode) {
             final Collection<? extends DataSchemaNode> containerChildren = dataNode.getChildNodes();
             final SchemaNode schemaNode = (SchemaNode) dataNode;
             final String localName = schemaNode.getQName().getLocalName();
-            final ObjectNode childSchema = JsonNodeFactory.instance.objectNode();
+            final Schema childSchema = new Schema();
             final String nameAsParent = parentName + "_" + localName;
             final ObjectNode properties =
                     processChildren(childSchema, containerChildren, parentName + "_" + localName, definitions,
@@ -403,43 +403,43 @@ public class DefinitionGenerator {
             }
 
             if (isConfig) {
-                final ObjectNode postSchema = createPostJsonSchema(schemaNode, properties, postNodeName, description);
+                final Schema postSchema = createPostJsonSchema(schemaNode, properties, postNodeName, description);
                 String truePostNodeName = postNodeName + discriminator;
-                definitions.set(truePostNodeName, postSchema);
+                definitions.put(truePostNodeName, postSchema);
 
-                final ObjectNode postXmlSchema = JsonNodeFactory.instance.objectNode();
-                postXmlSchema.put(REF_KEY, COMPONENTS_PREFIX + truePostNodeName);
-                definitions.set(postXmlNodeName + discriminator, postXmlSchema);
+                final Schema postXmlSchema = new Schema();
+                postXmlSchema.setRef(COMPONENTS_PREFIX + truePostNodeName);
+                definitions.put(postXmlNodeName + discriminator, postXmlSchema);
             }
 
-            childSchema.put(TYPE_KEY, OBJECT_TYPE);
-            childSchema.set(PROPERTIES_KEY, properties);
-            childSchema.put(TITLE_KEY, nodeName);
-            childSchema.put(DESCRIPTION_KEY, description);
+            childSchema.setType(OBJECT_TYPE);
+            childSchema.setProperties(properties);
+            childSchema.setTitle(nodeName);
+            childSchema.setDescription(description);
 
             final String defName = nodeName + discriminator;
-            childSchema.set(XML_KEY, buildXmlParameter(schemaNode));
-            definitions.set(defName, childSchema);
+            childSchema.setXml(buildXmlParameter(schemaNode));
+            definitions.put(defName, childSchema);
 
             return processTopData(nodeName, discriminator, definitions, schemaNode);
         }
         return null;
     }
 
-    private static ObjectNode createPostJsonSchema(final SchemaNode dataNode, final ObjectNode properties,
+    private static Schema createPostJsonSchema(final SchemaNode dataNode, final ObjectNode properties,
             final String postNodeName, final String description) {
-        final ObjectNode postSchema = JsonNodeFactory.instance.objectNode();
+        final Schema postSchema = new Schema();
         final ObjectNode postItemProperties;
         if (dataNode instanceof ListSchemaNode) {
             postItemProperties = createListItemProperties(properties, (ListSchemaNode) dataNode);
         } else {
             postItemProperties = properties.deepCopy();
         }
-        postSchema.put(TYPE_KEY, OBJECT_TYPE);
-        postSchema.set(PROPERTIES_KEY, postItemProperties);
-        postSchema.put(TITLE_KEY, postNodeName);
-        postSchema.put(DESCRIPTION_KEY, description);
-        postSchema.set(XML_KEY, buildXmlParameter(dataNode));
+        postSchema.setType(OBJECT_TYPE);
+        postSchema.setProperties(postItemProperties);
+        postSchema.setTitle(postNodeName);
+        postSchema.setDescription(description);
+        postSchema.setXml(buildXmlParameter(dataNode));
         return postSchema;
     }
 
@@ -465,8 +465,8 @@ public class DefinitionGenerator {
     /**
      * Processes the nodes.
      */
-    private ObjectNode processChildren(final ObjectNode parentNode, final Collection<? extends DataSchemaNode> nodes,
-            final String parentName, final ObjectNode definitions, final DefinitionNames definitionNames,
+    private ObjectNode processChildren(final Schema parentNode, final Collection<? extends DataSchemaNode> nodes,
+            final String parentName, final Map<String, Schema> definitions, final DefinitionNames definitionNames,
             final boolean isConfig, final SchemaInferenceStack stack) throws IOException {
         final ObjectNode properties = JsonNodeFactory.instance.objectNode();
         final ArrayNode required = JsonNodeFactory.instance.arrayNode();
@@ -475,14 +475,14 @@ public class DefinitionGenerator {
                 processChildNode(node, parentName, definitions, definitionNames, isConfig, stack, properties);
             }
         }
-        parentNode.set(PROPERTIES_KEY, properties);
+        parentNode.setProperties(properties);
         setRequiredIfNotEmpty(parentNode, required);
         return properties;
     }
 
-    private void processChildNode(final DataSchemaNode node, final String parentName, final ObjectNode definitions,
-            final DefinitionNames definitionNames, final boolean isConfig, final SchemaInferenceStack stack,
-            final ObjectNode properties) throws IOException {
+    private void processChildNode(final DataSchemaNode node, final String parentName,
+            final Map<String, Schema> definitions, final DefinitionNames definitionNames, final boolean isConfig,
+            final SchemaInferenceStack stack, final ObjectNode properties) throws IOException {
 
         stack.enterSchemaTree(node.getQName());
 
@@ -540,7 +540,7 @@ public class DefinitionGenerator {
     }
 
     private ObjectNode processLeafListNode(final LeafListSchemaNode listNode, final SchemaInferenceStack stack,
-            final ObjectNode definitions, final DefinitionNames definitionNames) {
+            final Map<String, Schema> definitions, final DefinitionNames definitionNames) {
         final ObjectNode props = JsonNodeFactory.instance.objectNode();
         props.put(TYPE_KEY, ARRAY_TYPE);
 
@@ -578,7 +578,7 @@ public class DefinitionGenerator {
 
     private ObjectNode processLeafNode(final LeafSchemaNode leafNode, final String jsonLeafName,
             final ObjectNode properties, final ArrayNode required, final SchemaInferenceStack stack,
-            final ObjectNode definitions, final DefinitionNames definitionNames) {
+            final Map<String, Schema> definitions, final DefinitionNames definitionNames) {
         final ObjectNode property = JsonNodeFactory.instance.objectNode();
 
         final String leafDescription = leafNode.getDescription().orElse("");
@@ -633,7 +633,7 @@ public class DefinitionGenerator {
     }
 
     private String processTypeDef(final TypeDefinition<?> leafTypeDef, final DataSchemaNode node,
-            final ObjectNode property, final SchemaInferenceStack stack, final ObjectNode definitions,
+            final ObjectNode property, final SchemaInferenceStack stack, final Map<String, Schema> definitions,
             final DefinitionNames definitionNames) {
         final String jsonType;
         if (leafTypeDef instanceof BinaryTypeDefinition) {
@@ -717,7 +717,7 @@ public class DefinitionGenerator {
     }
 
     private String processIdentityRefType(final IdentityrefTypeDefinition leafTypeDef, final ObjectNode property,
-            final ObjectNode definitions, final DefinitionNames definitionNames,
+            final Map<String, Schema> definitions, final DefinitionNames definitionNames,
             final EffectiveModelContext schemaContext) {
         final String definitionName;
         if (isImported(leafTypeDef)) {
@@ -731,36 +731,37 @@ public class DefinitionGenerator {
     }
 
     private static String addImportedIdentity(final IdentityrefTypeDefinition leafTypeDef,
-            final ObjectNode definitions, final DefinitionNames definitionNames, final EffectiveModelContext context) {
+            final Map<String, Schema> definitions, final DefinitionNames definitionNames,
+            final EffectiveModelContext context) {
         final IdentitySchemaNode idNode = leafTypeDef.getIdentities().iterator().next();
         final String identityName = idNode.getQName().getLocalName();
         if (!definitionNames.isListedNode(idNode)) {
-            final ObjectNode identityObj = buildIdentityObject(idNode, context);
+            final Schema identityObj = buildIdentityObject(idNode, context);
             final String discriminator = definitionNames.pickDiscriminator(idNode, List.of(identityName));
             final String name = identityName + discriminator;
-            definitions.set(name, identityObj);
+            definitions.put(name, identityObj);
             return name;
         } else {
             return identityName + definitionNames.getDiscriminator(idNode);
         }
     }
 
-    private static ObjectNode buildIdentityObject(final IdentitySchemaNode idNode,
+    private static Schema buildIdentityObject(final IdentitySchemaNode idNode,
             final EffectiveModelContext context) {
-        final ObjectNode identityObj = JsonNodeFactory.instance.objectNode();
+        final Schema identityObj = new Schema();
         final String identityName = idNode.getQName().getLocalName();
         LOG.debug("Processing Identity: {}", identityName);
 
-        identityObj.put(TITLE_KEY, identityName);
-        identityObj.put(DESCRIPTION_KEY, idNode.getDescription().orElse(""));
+        identityObj.setTitle(identityName);
+        identityObj.setDescription(idNode.getDescription().orElse(""));
 
         final Collection<? extends IdentitySchemaNode> derivedIds = context.getDerivedIdentities(idNode);
 
         final ArrayNode enumPayload = JsonNodeFactory.instance.arrayNode();
         enumPayload.add(identityName);
         populateEnumWithDerived(derivedIds, enumPayload, context);
-        identityObj.set(ENUM_KEY, enumPayload);
-        identityObj.put(TYPE_KEY, STRING_TYPE);
+        identityObj.setEnum(enumPayload);
+        identityObj.setType(STRING_TYPE);
         return identityObj;
     }
 
@@ -936,9 +937,9 @@ public class DefinitionGenerator {
         }
     }
 
-    private static void setRequiredIfNotEmpty(final ObjectNode node, final ArrayNode required) {
+    private static void setRequiredIfNotEmpty(final Schema node, final ArrayNode required) {
         if (required.size() > 0) {
-            node.set(REQUIRED_KEY, required);
+            node.setRequired(required);
         }
     }
 
index 856fa1aaf7ddc69c2ca744f6897af66335f9ea0b..7f0e17808f09969b328bd1c66fd1d84f6a7b6e71 100644 (file)
@@ -9,23 +9,23 @@ package org.opendaylight.restconf.openapi.model;
 
 import com.fasterxml.jackson.annotation.JsonInclude;
 import com.fasterxml.jackson.annotation.JsonInclude.Include;
-import com.fasterxml.jackson.databind.node.ObjectNode;
+import java.util.Map;
 
 @JsonInclude(Include.NON_NULL)
 public class Components {
-    private ObjectNode schemas;
+    private Map<String, Schema> schemas;
     private SecuritySchemes securitySchemes;
 
-    public Components(ObjectNode schemas, SecuritySchemes securitySchemes) {
+    public Components(Map<String, Schema> schemas, SecuritySchemes securitySchemes) {
         this.schemas = schemas;
         this.securitySchemes = securitySchemes;
     }
 
-    public ObjectNode getSchemas() {
+    public Map<String, Schema> getSchemas() {
         return schemas;
     }
 
-    public void setSchemas(ObjectNode schemas) {
+    public void setSchemas(Map<String, Schema> schemas) {
         this.schemas = schemas;
     }
 
diff --git a/restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/model/Schema.java b/restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/model/Schema.java
new file mode 100644 (file)
index 0000000..848a104
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * 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 com.fasterxml.jackson.annotation.JsonInclude.Include;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+@JsonInclude(value = Include.NON_NULL)
+public class Schema {
+    private ArrayNode schemaEnum;
+    private ArrayNode required;
+    private ObjectNode discriminator;
+    private ObjectNode examples;
+    private ObjectNode externalDocs;
+    private ObjectNode properties;
+    private ObjectNode xml;
+    private String description;
+    private String ref;
+    private String title;
+    private String type;
+
+    public ObjectNode getDiscriminator() {
+        return discriminator;
+    }
+
+    public void setDiscriminator(ObjectNode discriminator) {
+        this.discriminator = discriminator;
+    }
+
+    public ObjectNode getXml() {
+        return xml;
+    }
+
+    public void setXml(ObjectNode xml) {
+        this.xml = xml;
+    }
+
+    public ObjectNode getExternalDocs() {
+        return externalDocs;
+    }
+
+    public void setExternalDocs(ObjectNode externalDocs) {
+        this.externalDocs = externalDocs;
+    }
+
+    public ObjectNode getExamples() {
+        return examples;
+    }
+
+    public void setExamples(ObjectNode examples) {
+        this.examples = examples;
+    }
+
+    public ObjectNode getProperties() {
+        return properties;
+    }
+
+    public void setProperties(ObjectNode properties) {
+        this.properties = properties;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public ArrayNode getRequired() {
+        return required;
+    }
+
+    public void setRequired(ArrayNode required) {
+        this.required = required;
+    }
+
+    public String getRef() {
+        return ref;
+    }
+
+    public void setRef(String ref) {
+        this.ref = ref;
+    }
+
+    public ArrayNode getEnum() {
+        return schemaEnum;
+    }
+
+    public void setEnum(ArrayNode enumKey) {
+        this.schemaEnum = enumKey;
+    }
+}
index fe4894d2b00337a9e8c0621b0ff792c612ff930f..3cea58aea734030cc07f033f631339222682c6bf 100644 (file)
@@ -18,6 +18,7 @@ import java.net.URI;
 import javax.ws.rs.core.UriBuilder;
 import javax.ws.rs.core.UriInfo;
 import org.mockito.ArgumentCaptor;
+import org.opendaylight.restconf.openapi.model.Schema;
 
 public final class DocGenTestHelper {
 
@@ -44,9 +45,9 @@ public final class DocGenTestHelper {
     /**
      * Checks whether object {@code mainObject} contains in properties/items key $ref with concrete value.
      */
-    public static void containsReferences(final JsonNode mainObject, final String childObject,
+    public static void containsReferences(final Schema mainObject, final String childObject,
             final String expectedRef) {
-        final JsonNode properties = mainObject.get("properties");
+        final JsonNode properties = mainObject.getProperties();
         assertNotNull(properties);
 
         final JsonNode childNode = properties.get(childObject);
index 565bebf1470d16d61752b4c91dc1ec2de9221e67..2e260b1454057e79644337b18f35fbd48ae28c40 100644 (file)
@@ -9,10 +9,11 @@ package org.opendaylight.restconf.openapi.impl;
 
 import static org.junit.Assert.assertNotNull;
 
-import com.fasterxml.jackson.databind.node.ObjectNode;
 import java.io.IOException;
+import java.util.Map;
 import org.junit.Test;
 import org.opendaylight.restconf.openapi.AbstractOpenApiTest;
+import org.opendaylight.restconf.openapi.model.Schema;
 import org.opendaylight.yangtools.yang.common.Revision;
 
 public final class DefinitionGeneratorTest extends AbstractOpenApiTest {
@@ -20,7 +21,8 @@ public final class DefinitionGeneratorTest extends AbstractOpenApiTest {
     public void testConvertToJsonSchema() throws IOException {
         final var module = CONTEXT.findModule("opflex", Revision.of("2014-05-28")).orElseThrow();
         final DefinitionGenerator generator = new DefinitionGenerator();
-        final ObjectNode jsonObject = generator.convertToJsonSchema(module, CONTEXT, new DefinitionNames(), true);
+        final Map<String, Schema> jsonObject = generator.convertToJsonSchema(module, CONTEXT, new DefinitionNames(),
+                true);
         assertNotNull(jsonObject);
     }
 
@@ -28,7 +30,8 @@ public final class DefinitionGeneratorTest extends AbstractOpenApiTest {
     public void testActionTypes() throws IOException {
         final var module = CONTEXT.findModule("action-types").orElseThrow();
         final DefinitionGenerator generator = new DefinitionGenerator();
-        final ObjectNode jsonObject = generator.convertToJsonSchema(module, CONTEXT, new DefinitionNames(), true);
+        final Map<String, Schema> jsonObject = generator.convertToJsonSchema(module, CONTEXT, new DefinitionNames(),
+                true);
         assertNotNull(jsonObject);
     }
 
@@ -36,7 +39,8 @@ public final class DefinitionGeneratorTest extends AbstractOpenApiTest {
     public void testStringTypes() throws IOException {
         final var module = CONTEXT.findModule("string-types").orElseThrow();
         final DefinitionGenerator generator = new DefinitionGenerator();
-        final ObjectNode jsonObject = generator.convertToJsonSchema(module, CONTEXT, new DefinitionNames(), true);
+        final Map<String, Schema> jsonObject = generator.convertToJsonSchema(module, CONTEXT, new DefinitionNames(),
+                true);
         assertNotNull(jsonObject);
     }
 }
index 3e9cbb4ef90e0e59f412afe483aa639f6675cb0e..ce132bb913f0f3c36ea222072a0cb98ec6c49783 100644 (file)
@@ -13,14 +13,15 @@ import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
 import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.node.ObjectNode;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 import org.junit.Test;
 import org.opendaylight.restconf.openapi.AbstractOpenApiTest;
 import org.opendaylight.restconf.openapi.DocGenTestHelper;
 import org.opendaylight.restconf.openapi.model.OpenApiObject;
 import org.opendaylight.restconf.openapi.model.Path;
+import org.opendaylight.restconf.openapi.model.Schema;
 import org.opendaylight.yangtools.yang.common.Revision;
 
 public final class OpenApiGeneratorRFC8040Test extends AbstractOpenApiTest {
@@ -29,7 +30,7 @@ public final class OpenApiGeneratorRFC8040Test extends AbstractOpenApiTest {
     private static final String NAME_2 = "toaster";
     private static final String REVISION_DATE_2 = "2009-11-20";
     private static final String CHOICE_TEST_MODULE = "choice-test";
-    private static final String PROPERTIES = "properties";
+
     private final OpenApiGeneratorRFC8040 generator = new OpenApiGeneratorRFC8040(SCHEMA_SERVICE);
 
     /**
@@ -87,50 +88,50 @@ public final class OpenApiGeneratorRFC8040Test extends AbstractOpenApiTest {
         final var module = CONTEXT.findModule(NAME, Revision.of(REVISION_DATE)).orElseThrow();
         final OpenApiObject doc = generator.getOpenApiSpec(module, "http", "localhost:8181", "/", "", CONTEXT);
 
-        final ObjectNode schemas = doc.getComponents().getSchemas();
+        final Map<String, Schema> schemas = doc.getComponents().getSchemas();
         assertNotNull(schemas);
 
-        final JsonNode configLstTop = schemas.get("toaster2_config_lst_TOP");
+        final Schema configLstTop = schemas.get("toaster2_config_lst_TOP");
         assertNotNull(configLstTop);
         DocGenTestHelper.containsReferences(configLstTop, "lst", "#/components/schemas/toaster2_config_lst");
 
-        final JsonNode configLst = schemas.get("toaster2_config_lst");
+        final Schema configLst = schemas.get("toaster2_config_lst");
         assertNotNull(configLst);
         DocGenTestHelper.containsReferences(configLst, "lst1", "#/components/schemas/toaster2_lst_config_lst1");
         DocGenTestHelper.containsReferences(configLst, "cont1", "#/components/schemas/toaster2_lst_config_cont1");
 
-        final JsonNode configLst1Top = schemas.get("toaster2_lst_config_lst1_TOP");
+        final Schema configLst1Top = schemas.get("toaster2_lst_config_lst1_TOP");
         assertNotNull(configLst1Top);
         DocGenTestHelper.containsReferences(configLst1Top, "lst1", "#/components/schemas/toaster2_lst_config_lst1");
 
-        final JsonNode configLst1 = schemas.get("toaster2_lst_config_lst1");
+        final Schema configLst1 = schemas.get("toaster2_lst_config_lst1");
         assertNotNull(configLst1);
 
-        final JsonNode configCont1Top = schemas.get("toaster2_lst_config_cont1_TOP");
+        final Schema configCont1Top = schemas.get("toaster2_lst_config_cont1_TOP");
         assertNotNull(configCont1Top);
         DocGenTestHelper.containsReferences(configCont1Top, "cont1", "#/components/schemas/toaster2_lst_config_cont1");
 
-        final JsonNode configCont1 = schemas.get("toaster2_lst_config_cont1");
+        final Schema configCont1 = schemas.get("toaster2_lst_config_cont1");
         assertNotNull(configCont1);
         DocGenTestHelper.containsReferences(configCont1, "cont11",
                 "#/components/schemas/toaster2_lst_cont1_config_cont11");
         DocGenTestHelper.containsReferences(configCont1, "lst11",
                 "#/components/schemas/toaster2_lst_cont1_config_lst11");
 
-        final JsonNode configCont11Top = schemas.get("toaster2_lst_cont1_config_cont11_TOP");
+        final Schema configCont11Top = schemas.get("toaster2_lst_cont1_config_cont11_TOP");
         assertNotNull(configCont11Top);
         DocGenTestHelper.containsReferences(configCont11Top,
                 "cont11", "#/components/schemas/toaster2_lst_cont1_config_cont11");
 
-        final JsonNode configCont11 = schemas.get("toaster2_lst_cont1_config_cont11");
+        final Schema configCont11 = schemas.get("toaster2_lst_cont1_config_cont11");
         assertNotNull(configCont11);
 
-        final JsonNode configLst11Top = schemas.get("toaster2_lst_cont1_config_lst11_TOP");
+        final Schema configLst11Top = schemas.get("toaster2_lst_cont1_config_lst11_TOP");
         assertNotNull(configLst11Top);
         DocGenTestHelper.containsReferences(configLst11Top, "lst11",
                 "#/components/schemas/toaster2_lst_cont1_config_lst11");
 
-        final JsonNode configLst11 = schemas.get("toaster2_lst_cont1_config_lst11");
+        final Schema configLst11 = schemas.get("toaster2_lst_cont1_config_lst11");
         assertNotNull(configLst11);
     }
 
@@ -143,13 +144,13 @@ public final class OpenApiGeneratorRFC8040Test extends AbstractOpenApiTest {
         final OpenApiObject doc = generator.getOpenApiSpec(module, "http", "localhost:8181", "/", "", CONTEXT);
         assertNotNull(doc);
 
-        final ObjectNode schemas = doc.getComponents().getSchemas();
-        final JsonNode inputTop = schemas.get("toaster_make-toast_input_TOP");
+        final Map<String, Schema> schemas = doc.getComponents().getSchemas();
+        final Schema inputTop = schemas.get("toaster_make-toast_input_TOP");
         assertNotNull(inputTop);
         final String testString = "{\"input\":{\"$ref\":\"#/components/schemas/toaster_make-toast_input\"}}";
-        assertEquals(testString, inputTop.get("properties").toString());
-        final JsonNode input = schemas.get("toaster_make-toast_input");
-        final JsonNode properties = input.get("properties");
+        assertEquals(testString, inputTop.getProperties().toString());
+        final Schema input = schemas.get("toaster_make-toast_input");
+        final JsonNode properties = input.getProperties();
         assertTrue(properties.has("toasterDoneness"));
         assertTrue(properties.has("toasterToastType"));
     }
@@ -161,13 +162,13 @@ public final class OpenApiGeneratorRFC8040Test extends AbstractOpenApiTest {
         assertNotNull(doc);
 
         final var schemas = doc.getComponents().getSchemas();
-        JsonNode firstContainer = schemas.get("choice-test_first-container");
+        final Schema firstContainer = schemas.get("choice-test_first-container");
         assertEquals("default-value",
-                firstContainer.get(PROPERTIES).get("leaf-default").get("default").asText());
-        assertFalse(firstContainer.get(PROPERTIES).has("leaf-non-default"));
+                firstContainer.getProperties().get("leaf-default").get("default").asText());
+        assertFalse(firstContainer.getProperties().has("leaf-non-default"));
 
-        JsonNode secondContainer = schemas.get("choice-test_second-container");
-        assertTrue(secondContainer.get(PROPERTIES).has("leaf-first-case"));
-        assertFalse(secondContainer.get(PROPERTIES).has("leaf-second-case"));
+        final Schema secondContainer = schemas.get("choice-test_second-container");
+        assertTrue(secondContainer.getProperties().has("leaf-first-case"));
+        assertFalse(secondContainer.getProperties().has("leaf-second-case"));
     }
 }