Eliminate ObjectNode(s) from Schema class 52/107552/12
authorYaroslav Lastivka <yaroslav.lastivka@pantheon.tech>
Tue, 29 Aug 2023 07:18:50 +0000 (10:18 +0300)
committerIvan Hrasko <ivan.hrasko@pantheon.tech>
Wed, 20 Sep 2023 15:14:05 +0000 (15:14 +0000)
Introduced Property, Xml, Discriminator, ExternalDocumentation records.
All JsonNode fields inside Schema class has been replaced by
corresponding classes or collections. Affected logic has been adapted
to use models instead of JsonNode.

JIRA: NETCONF-938
Change-Id: If3a653b742f977c15a3056675d028a8bdfbd092a
Signed-off-by: Yaroslav Lastivka <yaroslav.lastivka@pantheon.tech>
Signed-off-by: Ivan Hrasko <ivan.hrasko@pantheon.tech>
12 files changed:
restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/impl/DefinitionGenerator.java
restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/model/Discriminator.java [new file with mode: 0644]
restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/model/ExternalDocumentation.java [new file with mode: 0644]
restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/model/Property.java [new file with mode: 0644]
restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/model/Schema.java
restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/model/Xml.java [new file with mode: 0644]
restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/model/builder/OperationBuilder.java
restconf/restconf-openapi/src/test/java/org/opendaylight/restconf/openapi/DocGenTestHelper.java
restconf/restconf-openapi/src/test/java/org/opendaylight/restconf/openapi/OperationalDataTest.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
restconf/restconf-openapi/src/test/java/org/opendaylight/restconf/openapi/impl/OpenApiXmlNamespaceTest.java

index 95c5a711ad05d46540b5666c2f8769a78839cdcf..0e818dc2ad294d1e35962a5dfc5a23f54ce16c5c 100644 (file)
@@ -9,26 +9,23 @@ package org.opendaylight.restconf.openapi.impl;
 
 import static org.opendaylight.restconf.openapi.impl.BaseYangOpenApiGenerator.MODULE_NAME_SUFFIX;
 import static org.opendaylight.restconf.openapi.model.builder.OperationBuilder.COMPONENTS_PREFIX;
-import static org.opendaylight.restconf.openapi.model.builder.OperationBuilder.NAME_KEY;
-import static org.opendaylight.restconf.openapi.model.builder.OperationBuilder.XML_KEY;
 
-import com.fasterxml.jackson.databind.node.ArrayNode;
-import com.fasterxml.jackson.databind.node.JsonNodeFactory;
-import com.fasterxml.jackson.databind.node.ObjectNode;
-import com.fasterxml.jackson.databind.node.TextNode;
 import com.google.common.collect.Range;
 import com.google.common.collect.RangeSet;
 import dk.brics.automaton.RegExp;
 import java.io.IOException;
 import java.math.BigDecimal;
 import java.math.BigInteger;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 import java.util.regex.Pattern;
+import org.opendaylight.restconf.openapi.model.Property;
 import org.opendaylight.restconf.openapi.model.Schema;
+import org.opendaylight.restconf.openapi.model.Xml;
 import org.opendaylight.yangtools.yang.common.Decimal64;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.XMLNamespace;
@@ -89,22 +86,8 @@ public final class DefinitionGenerator {
 
     private static final Logger LOG = LoggerFactory.getLogger(DefinitionGenerator.class);
 
-    private static final String UNIQUE_ITEMS_KEY = "uniqueItems";
-    private static final String MAX_ITEMS = "maxItems";
-    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 REF_KEY = "$ref";
-    private static final String ITEMS_KEY = "items";
     private static final String TYPE_KEY = "type";
-    private static final String DESCRIPTION_KEY = "description";
     private static final String ARRAY_TYPE = "array";
-    private static final String ENUM_KEY = "enum";
-    private static final String TITLE_KEY = "title";
-    private static final String DEFAULT_KEY = "default";
-    private static final String EXAMPLE_KEY = "example";
-    private static final String FORMAT_KEY = "format";
-    private static final String NAMESPACE_KEY = "namespace";
     public static final String INPUT = "input";
     public static final String INPUT_SUFFIX = "_input";
     public static final String OUTPUT = "output";
@@ -165,8 +148,8 @@ public final class DefinitionGenerator {
 
     private static void processModule(final Module module, final Map<String, Schema> definitions,
             final DefinitionNames definitionNames, final EffectiveModelContext schemaContext) {
-        final ObjectNode properties = JsonNodeFactory.instance.objectNode();
-        final ArrayNode required = JsonNodeFactory.instance.arrayNode();
+        final Map<String, Property> properties = new HashMap<>();
+        final List<String> required = new ArrayList<>();
         final String moduleName = module.getName();
         final String definitionName = moduleName + MODULE_NAME_SUFFIX;
         final SchemaInferenceStack stack = SchemaInferenceStack.of(schemaContext);
@@ -179,7 +162,7 @@ public final class DefinitionGenerator {
                         required.add(localName);
                     }
                     for (final DataSchemaNode childNode : ((DataNodeContainer) node).getChildNodes()) {
-                        final ObjectNode childNodeProperties = JsonNodeFactory.instance.objectNode();
+                        final Property.Builder childNodeProperty = new Property.Builder();
 
                         final String ref = COMPONENTS_PREFIX
                                 + moduleName
@@ -187,30 +170,29 @@ public final class DefinitionGenerator {
                                 + definitionNames.getDiscriminator(node);
 
                         if (node instanceof ListSchemaNode) {
-                            childNodeProperties.put(TYPE_KEY, ARRAY_TYPE);
-                            final ObjectNode items = JsonNodeFactory.instance.objectNode();
-                            items.put(REF_KEY, ref);
-                            childNodeProperties.set(ITEMS_KEY, items);
-                            childNodeProperties.put(DESCRIPTION_KEY, childNode.getDescription().orElse(""));
-                            childNodeProperties.put(TITLE_KEY, localName);
+                            childNodeProperty.type(ARRAY_TYPE);
+                            final Property items = new Property.Builder().ref(ref).build();
+                            childNodeProperty.items(items);
+                            childNodeProperty.description(childNode.getDescription().orElse(""));
+                            childNodeProperty.title(localName);
                         } else {
                          /*
                             Description can't be added, because nothing allowed alongside $ref.
                             allOf is not an option, because ServiceNow can't parse it.
                           */
-                            childNodeProperties.put(REF_KEY, ref);
+                            childNodeProperty.ref(ref);
                         }
                         //add module name prefix to property name, when ServiceNow can process colons
-                        properties.set(localName, childNodeProperties);
+                        properties.put(localName, childNodeProperty.build());
                     }
                 } else if (node instanceof LeafSchemaNode) {
                     /*
                         Add module name prefix to property name, when ServiceNow can process colons(second parameter
                         of processLeafNode).
                      */
-                    final ObjectNode leafNode = processLeafNode((LeafSchemaNode) node, localName, required, stack,
+                    final Property leafNode = processLeafNode((LeafSchemaNode) node, localName, required, stack,
                             definitions, definitionNames, module.getNamespace(), module);
-                    properties.set(localName, leafNode);
+                    properties.put(localName, leafNode);
                 }
             }
             stack.exit();
@@ -304,7 +286,7 @@ public final class DefinitionGenerator {
             final Schema.Builder childSchemaBuilder = new Schema.Builder()
                 .title(filename)
                 .type(OBJECT_TYPE)
-                .xml(JsonNodeFactory.instance.objectNode().put(NAME_KEY, isInput ? INPUT : OUTPUT));
+                .xml(new Xml(isInput ? INPUT : OUTPUT, null, null));
             processChildren(childSchemaBuilder, container.getChildNodes(), parentName, definitions, definitionNames,
                 stack, module, false);
             final String discriminator =
@@ -314,27 +296,26 @@ public final class DefinitionGenerator {
         stack.exit();
     }
 
-    private static ObjectNode processRef(final String filename, final String discriminator,
+    private static Property processRef(final String filename, final String discriminator,
             final SchemaNode schemaNode) {
-        final ObjectNode dataNodeProperties = JsonNodeFactory.instance.objectNode();
+        final Property.Builder dataNodeProperties = new Property.Builder();
         final String name = filename + discriminator;
         final String ref = COMPONENTS_PREFIX + name;
 
         if (schemaNode instanceof ListSchemaNode) {
-            dataNodeProperties.put(TYPE_KEY, ARRAY_TYPE);
-            final ObjectNode items = JsonNodeFactory.instance.objectNode();
-            items.put(REF_KEY, ref);
-            dataNodeProperties.set(ITEMS_KEY, items);
-            dataNodeProperties.put(DESCRIPTION_KEY, schemaNode.getDescription().orElse(""));
+            dataNodeProperties.type(ARRAY_TYPE);
+            final Property items = new Property.Builder().ref(ref).build();
+            dataNodeProperties.items(items);
+            dataNodeProperties.description(schemaNode.getDescription().orElse(""));
         } else {
              /*
                 Description can't be added, because nothing allowed alongside $ref.
                 allOf is not an option, because ServiceNow can't parse it.
               */
-            dataNodeProperties.put(REF_KEY, ref);
+            dataNodeProperties.ref(ref);
         }
 
-        return dataNodeProperties;
+        return dataNodeProperties.build();
     }
 
     /**
@@ -359,14 +340,14 @@ public final class DefinitionGenerator {
     }
 
     private static void populateEnumWithDerived(final Collection<? extends IdentitySchemaNode> derivedIds,
-            final ArrayNode enumPayload, final EffectiveModelContext context) {
+            final List<String> enumPayload, final EffectiveModelContext context) {
         for (final IdentitySchemaNode derivedId : derivedIds) {
             enumPayload.add(derivedId.getQName().getLocalName());
             populateEnumWithDerived(context.getDerivedIdentities(derivedId), enumPayload, context);
         }
     }
 
-    private static ObjectNode processDataNodeContainer(final DataNodeContainer dataNode, final String parentName,
+    private static Property processDataNodeContainer(final DataNodeContainer dataNode, final String parentName,
             final Map<String, Schema> definitions, final DefinitionNames definitionNames,
             final SchemaInferenceStack stack, final Module module, final boolean isParentConfig) throws IOException {
         final Collection<? extends DataSchemaNode> containerChildren = dataNode.getChildNodes();
@@ -400,25 +381,25 @@ public final class DefinitionGenerator {
     /**
      * Processes the nodes.
      */
-    private static ObjectNode processChildren(final Schema.Builder parentNodeBuilder,
+    private static Map<String, Property> processChildren(final Schema.Builder parentNodeBuilder,
             final Collection<? extends DataSchemaNode> nodes, final String parentName,
             final Map<String, Schema> definitions, final DefinitionNames definitionNames,
             final SchemaInferenceStack stack, final Module module, final boolean isParentConfig) throws IOException {
-        final ObjectNode properties = JsonNodeFactory.instance.objectNode();
-        final ArrayNode required = JsonNodeFactory.instance.arrayNode();
+        final Map<String, Property> properties = new HashMap<>();
+        final List<String> required = new ArrayList<>();
         for (final DataSchemaNode node : nodes) {
             if (node instanceof ChoiceSchemaNode choice) {
                 stack.enterSchemaTree(node.getQName());
                 final boolean isConfig = isParentConfig && node.isConfiguration();
-                final Map<String, ObjectNode> choiceProperties = processChoiceNodeRecursively(parentName,
+                final Map<String, Property> choiceProperties = processChoiceNodeRecursively(parentName,
                     definitions, definitionNames, isConfig, stack, required, choice, module);
-                choiceProperties.forEach(properties::set);
+                properties.putAll(choiceProperties);
                 stack.exit();
             } else {
-                final ObjectNode property = processChildNode(node, parentName, definitions, definitionNames,
+                final Property property = processChildNode(node, parentName, definitions, definitionNames,
                     stack, required, module, isParentConfig);
                 if (property != null) {
-                    properties.set(node.getQName().getLocalName(), property);
+                    properties.put(node.getQName().getLocalName(), property);
                 }
             }
         }
@@ -426,12 +407,12 @@ public final class DefinitionGenerator {
         return properties;
     }
 
-    private static Map<String, ObjectNode> processChoiceNodeRecursively(final String parentName,
+    private static Map<String, Property> processChoiceNodeRecursively(final String parentName,
             final Map<String, Schema> definitions, final DefinitionNames definitionNames, final boolean isConfig,
-            final SchemaInferenceStack stack, final ArrayNode required, final ChoiceSchemaNode choice,
+            final SchemaInferenceStack stack, final List<String> required, final ChoiceSchemaNode choice,
             final Module module) throws IOException {
         if (!choice.getCases().isEmpty()) {
-            final var properties = new HashMap<String, ObjectNode>();
+            final var properties = new HashMap<String, Property>();
             final var caseSchemaNode = choice.getDefaultCase().orElse(choice.getCases().stream()
                 .findFirst().orElseThrow());
             stack.enterSchemaTree(caseSchemaNode.getQName());
@@ -457,9 +438,9 @@ public final class DefinitionGenerator {
         return Map.of();
     }
 
-    private static ObjectNode processChildNode(final DataSchemaNode node, final String parentName,
+    private static Property processChildNode(final DataSchemaNode node, final String parentName,
             final Map<String, Schema> definitions, final DefinitionNames definitionNames,
-            final SchemaInferenceStack stack, final ArrayNode required, final Module module,
+            final SchemaInferenceStack stack, final List<String> required, final Module module,
             final boolean isParentConfig) throws IOException {
         final XMLNamespace parentNamespace = stack.toSchemaNodeIdentifier().lastNodeIdentifier().getNamespace();
         stack.enterSchemaTree(node.getQName());
@@ -475,9 +456,9 @@ public final class DefinitionGenerator {
             node.isConfiguration()==true.
         */
         final boolean shouldBeAddedAsChild = !isParentConfig || node.isConfiguration();
-        ObjectNode property = null;
+        Property property = null;
         if (node instanceof ListSchemaNode || node instanceof ContainerSchemaNode) {
-            final ObjectNode dataNodeContainer = processDataNodeContainer((DataNodeContainer) node, parentName,
+            final Property dataNodeContainer = processDataNodeContainer((DataNodeContainer) node, parentName,
                 definitions, definitionNames, stack, module, isParentConfig);
             if (shouldBeAddedAsChild) {
                 if (isSchemaNodeMandatory(node)) {
@@ -505,44 +486,46 @@ public final class DefinitionGenerator {
         return property;
     }
 
-    private static ObjectNode processLeafListNode(final LeafListSchemaNode listNode, final SchemaInferenceStack stack,
-            final Map<String, Schema> definitions, final DefinitionNames definitionNames, final Module module) {
-        final ObjectNode props = JsonNodeFactory.instance.objectNode();
-        props.put(TYPE_KEY, ARRAY_TYPE);
+    private static Property processLeafListNode(final LeafListSchemaNode listNode,
+            final SchemaInferenceStack stack, final Map<String, Schema> definitions,
+            final DefinitionNames definitionNames, final Module module) {
+        final Property.Builder props = new Property.Builder();
+        props.type(ARRAY_TYPE);
 
-        final ObjectNode itemsVal = JsonNodeFactory.instance.objectNode();
+        final Property.Builder itemsVal = new Property.Builder();
         final Optional<ElementCountConstraint> optConstraint = listNode.getElementCountConstraint();
         optConstraint.ifPresent(elementCountConstraint -> processElementCount(elementCountConstraint, props));
 
         processTypeDef(listNode.getType(), listNode, itemsVal, stack, definitions, definitionNames, module);
-        props.set(ITEMS_KEY, itemsVal);
 
-        props.put(DESCRIPTION_KEY, listNode.getDescription().orElse(""));
+        props.items(itemsVal.build());
+        props.description(listNode.getDescription().orElse(""));
 
-        return props;
+        return props.build();
     }
 
-    private static void processElementCount(final ElementCountConstraint constraint, final ObjectNode props) {
+    private static void processElementCount(final ElementCountConstraint constraint, final Property.Builder props) {
         final Integer minElements = constraint.getMinElements();
         if (minElements != null) {
-            props.put(MIN_ITEMS, minElements);
+            props.minItems(minElements);
         }
         final Integer maxElements = constraint.getMaxElements();
         if (maxElements != null) {
-            props.put(MAX_ITEMS, maxElements);
+            props.maxItems(maxElements);
         }
     }
 
-    private static void processMandatory(final MandatoryAware node, final String nodeName, final ArrayNode required) {
+    private static void processMandatory(final MandatoryAware node, final String nodeName,
+            final List<String> required) {
         if (node.isMandatory()) {
             required.add(nodeName);
         }
     }
 
-    private static ObjectNode processLeafNode(final LeafSchemaNode leafNode, final String jsonLeafName,
-            final ArrayNode required, final SchemaInferenceStack stack, final Map<String, Schema> definitions,
+    private static Property processLeafNode(final LeafSchemaNode leafNode, final String jsonLeafName,
+            final List<String> required, final SchemaInferenceStack stack, final Map<String, Schema> definitions,
             final DefinitionNames definitionNames, final XMLNamespace parentNamespace, final Module module) {
-        final ObjectNode property = JsonNodeFactory.instance.objectNode();
+        final Property.Builder property = new Property.Builder();
 
         final String leafDescription = leafNode.getDescription().orElse("");
         /*
@@ -550,40 +533,40 @@ public final class DefinitionGenerator {
             allOf is not an option, because ServiceNow can't parse it.
         */
         if (!(leafNode.getType() instanceof IdentityrefTypeDefinition)) {
-            property.put(DESCRIPTION_KEY, leafDescription);
+            property.description(leafDescription);
         }
 
         processTypeDef(leafNode.getType(), leafNode, property, stack, definitions, definitionNames, module);
         if (!leafNode.getQName().getNamespace().equals(parentNamespace)) {
             // If the parent is not from the same model, define the child XML namespace.
-            property.set(XML_KEY, buildXmlParameter(leafNode));
+            property.xml(buildXmlParameter(leafNode));
         }
         processMandatory(leafNode, jsonLeafName, required);
-        return property;
+        return property.build();
     }
 
-    private static ObjectNode processUnknownDataSchemaNode(final DataSchemaNode leafNode, final String name,
-            final ArrayNode required, final XMLNamespace parentNamespace) {
+    private static Property processUnknownDataSchemaNode(final DataSchemaNode leafNode, final String name,
+            final List<String> required, final XMLNamespace parentNamespace) {
         assert (leafNode instanceof AnydataSchemaNode || leafNode instanceof AnyxmlSchemaNode);
 
-        final ObjectNode property = JsonNodeFactory.instance.objectNode();
+        final Property.Builder property = new Property.Builder();
 
         final String leafDescription = leafNode.getDescription().orElse("");
-        property.put(DESCRIPTION_KEY, leafDescription);
+        property.description(leafDescription);
 
         final String localName = leafNode.getQName().getLocalName();
-        setExampleValue(property, String.format("<%s> ... </%s>", localName, localName));
-        property.put(TYPE_KEY, STRING_TYPE);
+        property.example(String.format("<%s> ... </%s>", localName, localName));
+        property.type(STRING_TYPE);
         if (!leafNode.getQName().getNamespace().equals(parentNamespace)) {
             // If the parent is not from the same model, define the child XML namespace.
-            property.set(XML_KEY, buildXmlParameter(leafNode));
+            property.xml(buildXmlParameter(leafNode));
         }
         processMandatory((MandatoryAware) leafNode, name, required);
-        return property;
+        return property.build();
     }
 
     private static String processTypeDef(final TypeDefinition<?> leafTypeDef, final DataSchemaNode node,
-            final ObjectNode property, final SchemaInferenceStack stack,final Map<String, Schema> definitions,
+            final Property.Builder property, final SchemaInferenceStack stack,final Map<String, Schema> definitions,
             final DefinitionNames definitionNames, final Module module) {
         final String jsonType;
         if (leafTypeDef instanceof BinaryTypeDefinition binaryType) {
@@ -607,8 +590,8 @@ public final class DefinitionGenerator {
                 stack, definitions, definitionNames, module);
         } else if (leafTypeDef instanceof BooleanTypeDefinition) {
             jsonType = BOOLEAN_TYPE;
-            leafTypeDef.getDefaultValue().ifPresent(v -> setDefaultValue(property, Boolean.valueOf((String) v)));
-            setExampleValue(property, true);
+            leafTypeDef.getDefaultValue().ifPresent(v -> property.defaultValue(Boolean.valueOf((String) v)));
+            property.example(true);
         } else if (leafTypeDef instanceof RangeRestrictedTypeDefinition<?, ?> rangeRestrictedType) {
             jsonType = processNumberType(rangeRestrictedType, property);
         } else if (leafTypeDef instanceof InstanceIdentifierTypeDefinition instanceIdentifierType) {
@@ -619,57 +602,56 @@ public final class DefinitionGenerator {
         }
         if (!(leafTypeDef instanceof IdentityrefTypeDefinition)) {
             if (TYPE_KEY != null && jsonType != null) {
-                property.put(TYPE_KEY, jsonType);
+                property.type(jsonType);
             }
             if (leafTypeDef.getDefaultValue().isPresent()) {
                 final Object defaultValue = leafTypeDef.getDefaultValue().orElseThrow();
                 if (defaultValue instanceof String stringDefaultValue) {
                     if (leafTypeDef instanceof BooleanTypeDefinition) {
-                        setDefaultValue(property, Boolean.valueOf(stringDefaultValue));
+                        property.defaultValue(Boolean.valueOf(stringDefaultValue));
                     } else if (leafTypeDef instanceof DecimalTypeDefinition
                             || leafTypeDef instanceof Uint64TypeDefinition) {
-                        setDefaultValue(property, new BigDecimal(stringDefaultValue));
+                        property.defaultValue(new BigDecimal(stringDefaultValue));
                     } else if (leafTypeDef instanceof RangeRestrictedTypeDefinition<?, ?> rangeRestrictedType) {
                         //uint8,16,32 int8,16,32,64
                         if (isHexadecimalOrOctal(rangeRestrictedType)) {
-                            setDefaultValue(property, stringDefaultValue);
+                            property.defaultValue(stringDefaultValue);
                         } else {
-                            setDefaultValue(property, Long.valueOf(stringDefaultValue));
+                            property.defaultValue(Long.valueOf(stringDefaultValue));
                         }
                     } else {
-                        setDefaultValue(property, stringDefaultValue);
+                        property.defaultValue(stringDefaultValue);
                     }
                 } else {
                     //we should never get here. getDefaultValue always gives us string
-                    setDefaultValue(property, defaultValue.toString());
+                    property.defaultValue(defaultValue.toString());
                 }
             }
         }
         return jsonType;
     }
 
-    private static String processBinaryType(final BinaryTypeDefinition definition, final ObjectNode property) {
-        definition.getDefaultValue().ifPresent(v -> setDefaultValue(property, ((String) v)));
-        property.put(FORMAT_KEY, "byte");
+    private static String processBinaryType(final BinaryTypeDefinition definition, final Property.Builder property) {
+        definition.getDefaultValue().ifPresent(property::defaultValue);
+        property.format("byte");
         return STRING_TYPE;
     }
 
-    private static String processEnumType(final EnumTypeDefinition enumLeafType, final ObjectNode property) {
+    private static String processEnumType(final EnumTypeDefinition enumLeafType, final Property.Builder property) {
         final List<EnumPair> enumPairs = enumLeafType.getValues();
-        final ArrayNode enumNames = new ArrayNode(JsonNodeFactory.instance);
-        for (final EnumPair enumPair : enumPairs) {
-            enumNames.add(new TextNode(enumPair.getName()));
-        }
+        final List<String> enumNames = enumPairs.stream()
+            .map(EnumPair::getName)
+            .toList();
 
-        property.set(ENUM_KEY, enumNames);
-        enumLeafType.getDefaultValue().ifPresent(v -> setDefaultValue(property, ((String) v)));
-        setExampleValue(property, enumLeafType.getValues().iterator().next().getName());
+        property.enums(enumNames);
+        enumLeafType.getDefaultValue().ifPresent(property::defaultValue);
+        property.example(enumLeafType.getValues().iterator().next().getName());
         return STRING_TYPE;
     }
 
-    private static String processIdentityRefType(final IdentityrefTypeDefinition leafTypeDef, final ObjectNode property,
-            final Map<String, Schema> definitions, final DefinitionNames definitionNames,
-            final EffectiveModelContext schemaContext, final Module module) {
+    private static String processIdentityRefType(final IdentityrefTypeDefinition leafTypeDef,
+            final Property.Builder property, final Map<String, Schema> definitions,
+            final DefinitionNames definitionNames, final EffectiveModelContext schemaContext, final Module module) {
         final String definitionName;
         if (isImported(leafTypeDef, module)) {
             definitionName = addImportedIdentity(leafTypeDef, definitions, definitionNames, schemaContext);
@@ -677,7 +659,7 @@ public final class DefinitionGenerator {
             final SchemaNode node = leafTypeDef.getIdentities().iterator().next();
             definitionName = node.getQName().getLocalName() + definitionNames.getDiscriminator(node);
         }
-        property.put(REF_KEY, COMPONENTS_PREFIX + definitionName);
+        property.ref(COMPONENTS_PREFIX + definitionName);
         return STRING_TYPE;
     }
 
@@ -702,14 +684,15 @@ public final class DefinitionGenerator {
         LOG.debug("Processing Identity: {}", identityName);
 
         final Collection<? extends IdentitySchemaNode> derivedIds = context.getDerivedIdentities(idNode);
-        final ArrayNode enumPayload = JsonNodeFactory.instance.arrayNode();
+        final List<String> enumPayload = new ArrayList<>();
         enumPayload.add(identityName);
         populateEnumWithDerived(derivedIds, enumPayload, context);
+        final List<String> schemaEnum = new ArrayList<>(enumPayload);
 
         return new Schema.Builder()
             .title(identityName)
             .description(idNode.getDescription().orElse(""))
-            .schemaEnum(enumPayload)
+            .schemaEnum(schemaEnum)
             .type(STRING_TYPE)
             .build();
     }
@@ -718,21 +701,20 @@ public final class DefinitionGenerator {
         return !leafTypeDef.getQName().getModule().equals(module.getQNameModule());
     }
 
-    private static String processBitsType(final BitsTypeDefinition bitsType, final ObjectNode property) {
-        property.put(MIN_ITEMS, 0);
-        property.put(UNIQUE_ITEMS_KEY, true);
-        final ArrayNode enumNames = new ArrayNode(JsonNodeFactory.instance);
+    private static String processBitsType(final BitsTypeDefinition bitsType, final Property.Builder property) {
+        property.minItems(0);
+        property.uniqueItems(true);
         final Collection<? extends Bit> bits = bitsType.getBits();
-        for (final Bit bit : bits) {
-            enumNames.add(new TextNode(bit.getName()));
-        }
-        property.set(ENUM_KEY, enumNames);
-        property.put(DEFAULT_KEY, enumNames.iterator().next() + " " + enumNames.get(enumNames.size() - 1));
-        bitsType.getDefaultValue().ifPresent(v -> setDefaultValue(property, (String) v));
+        final List<String> enumNames = bits.stream()
+            .map(Bit::getName)
+            .toList();
+        property.enums(enumNames);
+        property.defaultValue(enumNames.iterator().next() + " " + enumNames.get(enumNames.size() - 1));
+        bitsType.getDefaultValue().ifPresent(property::defaultValue);
         return STRING_TYPE;
     }
 
-    private static String processStringType(final StringTypeDefinition stringType, final ObjectNode property,
+    private static String processStringType(final StringTypeDefinition stringType, final Property.Builder property,
             final String nodeName) {
         var type = stringType;
         while (type.getLengthConstraint().isEmpty() && type.getBaseType() != null) {
@@ -741,8 +723,8 @@ public final class DefinitionGenerator {
 
         type.getLengthConstraint().ifPresent(constraint -> {
             final Range<Integer> range = constraint.getAllowedRanges().span();
-            property.put(MIN_LENGTH_KEY, range.lowerEndpoint());
-            property.put(MAX_LENGTH_KEY, range.upperEndpoint());
+            property.minLength(range.lowerEndpoint());
+            property.maxLength(range.upperEndpoint());
         });
 
         if (type.getPatternConstraints().iterator().hasNext()) {
@@ -760,17 +742,17 @@ public final class DefinitionGenerator {
             } catch (IllegalArgumentException ex) {
                 LOG.warn("Cannot create example string for type: {} with regex: {}.", stringType.getQName(), regex);
             }
-            setExampleValue(property, defaultValue);
+            property.example(defaultValue);
         } else {
-            setExampleValue(property, "Some " + nodeName);
+            property.example("Some " + nodeName);
         }
 
-        stringType.getDefaultValue().ifPresent(v -> setDefaultValue(property, (String) v));
+        stringType.getDefaultValue().ifPresent(property::defaultValue);
         return STRING_TYPE;
     }
 
     private static String processNumberType(final RangeRestrictedTypeDefinition<?, ?> leafTypeDef,
-            final ObjectNode property) {
+            final Property.Builder property) {
         final Optional<Number> maybeLower = leafTypeDef.getRangeConstraint()
                 .map(RangeConstraint::getAllowedRanges).map(RangeSet::span).map(Range::lowerEndpoint);
 
@@ -779,9 +761,9 @@ public final class DefinitionGenerator {
         }
 
         if (leafTypeDef instanceof DecimalTypeDefinition) {
-            leafTypeDef.getDefaultValue().ifPresent(number ->
-                    setDefaultValue(property, Decimal64.valueOf((String) number).decimalValue()));
-            maybeLower.ifPresent(number -> setExampleValue(property, ((Decimal64) number).decimalValue()));
+            leafTypeDef.getDefaultValue().ifPresent(number -> property.defaultValue(Decimal64.valueOf((String) number)
+                .decimalValue()));
+            maybeLower.ifPresent(number -> property.example(((Decimal64) number).decimalValue()));
             return NUMBER_TYPE;
         }
         if (leafTypeDef instanceof Uint8TypeDefinition
@@ -790,22 +772,19 @@ public final class DefinitionGenerator {
                 || leafTypeDef instanceof Int16TypeDefinition
                 || leafTypeDef instanceof Int32TypeDefinition) {
 
-            property.put(FORMAT_KEY, INT32_FORMAT);
-            leafTypeDef.getDefaultValue().ifPresent(number -> setDefaultValue(property,
-                Integer.valueOf((String) number)));
-            maybeLower.ifPresent(number -> setExampleValue(property, Integer.valueOf(number.toString())));
+            property.format(INT32_FORMAT);
+            leafTypeDef.getDefaultValue().ifPresent(number -> property.defaultValue(Integer.valueOf((String) number)));
+            maybeLower.ifPresent(number -> property.example(Integer.valueOf(number.toString())));
         } else if (leafTypeDef instanceof Uint32TypeDefinition
                 || leafTypeDef instanceof Int64TypeDefinition) {
 
-            property.put(FORMAT_KEY, INT64_FORMAT);
-            leafTypeDef.getDefaultValue().ifPresent(number -> setDefaultValue(property,
-                Long.valueOf((String) number)));
-            maybeLower.ifPresent(number -> setExampleValue(property, Long.valueOf(number.toString())));
+            property.format(INT64_FORMAT);
+            leafTypeDef.getDefaultValue().ifPresent(number -> property.defaultValue(Long.valueOf((String) number)));
+            maybeLower.ifPresent(number -> property.example(Long.valueOf(number.toString())));
         } else {
             //uint64
-            leafTypeDef.getDefaultValue().ifPresent(number -> setDefaultValue(property,
-                new BigInteger((String) number)));
-            setExampleValue(property, 0);
+            leafTypeDef.getDefaultValue().ifPresent(number -> property.defaultValue(new BigInteger((String) number)));
+            property.example(0);
         }
         return INTEGER_TYPE;
     }
@@ -820,71 +799,23 @@ public final class DefinitionGenerator {
     }
 
     private static String processInstanceIdentifierType(final InstanceIdentifierTypeDefinition iidType,
-            final DataSchemaNode node, final ObjectNode property, final EffectiveModelContext schemaContext) {
+            final DataSchemaNode node, final Property.Builder property, final EffectiveModelContext schemaContext) {
         // create example instance-identifier to the first container of node's module if exists or leave it empty
         final var module = schemaContext.findModule(node.getQName().getModule());
         if (module.isPresent()) {
             final var container = module.orElseThrow().getChildNodes().stream()
                     .filter(n -> n instanceof ContainerSchemaNode)
                     .findFirst();
-            container.ifPresent(c -> setExampleValue(property, String.format("/%s:%s", module.orElseThrow().getPrefix(),
-                    c.getQName().getLocalName())));
+            container.ifPresent(c -> property.example(String.format("/%s:%s", module.orElseThrow().getPrefix(),
+                c.getQName().getLocalName())));
         }
         // set default value
-        iidType.getDefaultValue().ifPresent(c -> setDefaultValue(property, (String) c));
+        iidType.getDefaultValue().ifPresent(property::defaultValue);
         return STRING_TYPE;
     }
 
-    private static ObjectNode buildXmlParameter(final SchemaNode node) {
-        final ObjectNode xml = JsonNodeFactory.instance.objectNode();
+    private static Xml buildXmlParameter(final SchemaNode node) {
         final QName qName = node.getQName();
-        xml.put(NAME_KEY, qName.getLocalName());
-        xml.put(NAMESPACE_KEY, qName.getNamespace().toString());
-        return xml;
-    }
-
-    private static void setExampleValue(final ObjectNode property, final String value) {
-        property.put(EXAMPLE_KEY, value);
+        return new Xml(qName.getLocalName(), qName.getNamespace().toString(), null);
     }
-
-    private static void setExampleValue(final ObjectNode property, final Integer value) {
-        property.put(EXAMPLE_KEY, value);
-    }
-
-    private static void setExampleValue(final ObjectNode property, final Long value) {
-        property.put(EXAMPLE_KEY, value);
-    }
-
-    private static void setExampleValue(final ObjectNode property, final BigDecimal value) {
-        property.put(EXAMPLE_KEY, value);
-    }
-
-    private static void setExampleValue(final ObjectNode property, final Boolean value) {
-        property.put(EXAMPLE_KEY, value);
-    }
-
-    private static void setDefaultValue(final ObjectNode property, final String value) {
-        property.put(DEFAULT_KEY, value);
-    }
-
-    private static void setDefaultValue(final ObjectNode property, final Integer value) {
-        property.put(DEFAULT_KEY, value);
-    }
-
-    private static void setDefaultValue(final ObjectNode property, final Long value) {
-        property.put(DEFAULT_KEY, value);
-    }
-
-    private static void setDefaultValue(final ObjectNode property, final BigInteger value) {
-        property.put(DEFAULT_KEY, value);
-    }
-
-    private static void setDefaultValue(final ObjectNode property, final BigDecimal value) {
-        property.put(DEFAULT_KEY, value);
-    }
-
-    private static void setDefaultValue(final ObjectNode property, final Boolean value) {
-        property.put(DEFAULT_KEY, value);
-    }
-
 }
diff --git a/restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/model/Discriminator.java b/restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/model/Discriminator.java
new file mode 100644 (file)
index 0000000..3016079
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * 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 org.eclipse.jdt.annotation.Nullable;
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public record Discriminator(
+    @Nullable String propertyName,
+    @Nullable Map<String, String> mapping) {
+
+    public Discriminator {
+        mapping = mapping != null ? Map.copyOf(mapping) : null;
+    }
+}
diff --git a/restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/model/ExternalDocumentation.java b/restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/model/ExternalDocumentation.java
new file mode 100644 (file)
index 0000000..1b1faad
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * 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 ExternalDocumentation(
+        @Nullable String description,
+        @Nullable String url) {
+}
diff --git a/restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/model/Property.java b/restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/model/Property.java
new file mode 100644 (file)
index 0000000..a6f1e01
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * 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.JsonProperty;
+import java.util.List;
+import org.eclipse.jdt.annotation.Nullable;
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public record Property(
+        @Nullable String description,
+        @Nullable String type,
+        @Nullable Property items,
+        @Nullable Object example,
+        @JsonProperty("default") @Nullable Object defaultValue,
+        @Nullable String format,
+        @Nullable Xml xml,
+        @Nullable String title,
+        @JsonProperty("$ref") @Nullable String ref,
+        @Nullable Integer minItems,
+        @Nullable Integer maxItems,
+        boolean uniqueItems,
+        @JsonProperty("enum") List<String> enums,
+        @Nullable Integer minLength,
+        @Nullable Integer maxLength) {
+
+    public Property {
+        enums = enums != null ? List.copyOf(enums) : null;
+    }
+
+    private Property(final Builder builder) {
+        this(builder.description, builder.type, builder.items, builder.example, builder.defaultValue, builder.format,
+            builder.xml, builder.title, builder.ref, builder.minItems, builder.maxItems, builder.uniqueItems,
+            builder.enums, builder.minLength, builder.maxLength);
+    }
+
+    @SuppressWarnings("checkstyle:hiddenField")
+    public static class Builder {
+        private String description;
+        private String type;
+        private Property items;
+        private Object example;
+        private Object defaultValue;
+        private String format;
+        private Xml xml;
+        private String title;
+        private String ref;
+        private Integer minItems;
+        private Integer maxItems;
+        private boolean uniqueItems;
+        private List<String> enums;
+        private Integer minLength;
+        private Integer maxLength;
+
+        public Builder description(final String description) {
+            this.description = description;
+            return this;
+        }
+
+        public Builder type(final String type) {
+            this.type = type;
+            return this;
+        }
+
+        public Builder items(final Property items) {
+            this.items = items;
+            return this;
+        }
+
+        public Builder example(final Object example) {
+            this.example = example;
+            return this;
+        }
+
+        public Builder defaultValue(final Object defaultValue) {
+            this.defaultValue = defaultValue;
+            return this;
+        }
+
+        public Builder format(final String format) {
+            this.format = format;
+            return this;
+        }
+
+        public Builder xml(final Xml xml) {
+            this.xml = xml;
+            return this;
+        }
+
+        public Builder title(final String title) {
+            this.title = title;
+            return this;
+        }
+
+        public Builder ref(final String ref) {
+            this.ref = ref;
+            return this;
+        }
+
+        public Builder minItems(final Integer minItems) {
+            this.minItems = minItems;
+            return this;
+        }
+
+        public Builder maxItems(final Integer maxItems) {
+            this.maxItems = maxItems;
+            return this;
+        }
+
+        public Builder uniqueItems(final boolean uniqueItems) {
+            this.uniqueItems = uniqueItems;
+            return this;
+        }
+
+        public Builder enums(final List<String> enums) {
+            this.enums = enums;
+            return this;
+        }
+
+        public Builder minLength(final Integer minLength) {
+            this.minLength = minLength;
+            return this;
+        }
+
+        public Builder maxLength(final Integer maxLength) {
+            this.maxLength = maxLength;
+            return this;
+        }
+
+        public Property build() {
+            return new Property(this);
+        }
+    }
+}
index f1ac8f9d2fa2b14e9a63c934d9871b4da859b069..34ae4c3bbee345be450c52ac457aeb7dd693cfb4 100644 (file)
@@ -10,13 +10,29 @@ package org.opendaylight.restconf.openapi.model;
 import com.fasterxml.jackson.annotation.JsonInclude;
 import com.fasterxml.jackson.annotation.JsonInclude.Include;
 import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.databind.node.ArrayNode;
-import com.fasterxml.jackson.databind.node.ObjectNode;
+import java.util.List;
+import java.util.Map;
+import org.eclipse.jdt.annotation.Nullable;
 
 @JsonInclude(value = Include.NON_NULL)
-public record Schema(@JsonProperty("enum") ArrayNode schemaEnum, ArrayNode required, ObjectNode discriminator,
-        ObjectNode examples, ObjectNode externalDocs, ObjectNode properties, ObjectNode xml, String description,
-        @JsonProperty("$ref") String ref, String title, String type) {
+public record Schema(
+        @JsonProperty("enum") List<String> schemaEnum,
+        @Nullable List<String> required,
+        @Nullable Discriminator discriminator,
+        @Nullable String examples,
+        @Nullable ExternalDocumentation externalDocs,
+        @Nullable Map<String, Property> properties,
+        @Nullable Xml xml,
+        @Nullable String description,
+        @JsonProperty("$ref") String ref,
+        @Nullable String title,
+        @Nullable String type) {
+
+    public Schema {
+        schemaEnum = schemaEnum != null ? List.copyOf(schemaEnum) : null;
+        required = required != null ? List.copyOf(required) : null;
+        properties = properties != null ? Map.copyOf(properties) : null;
+    }
 
     private Schema(final Builder builder) {
         this(builder.schemaEnum, builder.required, builder.discriminator, builder.examples, builder.externalDocs,
@@ -25,49 +41,49 @@ public record Schema(@JsonProperty("enum") ArrayNode schemaEnum, ArrayNode requi
 
     @SuppressWarnings("checkstyle:hiddenField")
     public static class Builder {
-        private ArrayNode schemaEnum;
-        private ArrayNode required;
-        private ObjectNode discriminator;
-        private ObjectNode examples;
-        private ObjectNode externalDocs;
-        private ObjectNode properties;
-        private ObjectNode xml;
+        private List<String> schemaEnum;
+        private List<String> required;
+        private Discriminator discriminator;
+        private String examples;
+        private ExternalDocumentation externalDocs;
+        private Map<String, Property> properties;
+        private Xml xml;
         private String description;
         private String ref;
         private String title;
         private String type;
 
-        public Builder schemaEnum(final ArrayNode schemaEnum) {
+        public Builder schemaEnum(final List<String> schemaEnum) {
             this.schemaEnum = schemaEnum;
             return this;
         }
 
-        public Builder required(final ArrayNode required) {
+        public Builder required(final List<String> required) {
             this.required = required;
             return this;
         }
 
-        public Builder discriminator(final ObjectNode discriminator) {
+        public Builder discriminator(final Discriminator discriminator) {
             this.discriminator = discriminator;
             return this;
         }
 
-        public Builder examples(final ObjectNode examples) {
+        public Builder examples(final String examples) {
             this.examples = examples;
             return this;
         }
 
-        public Builder externalDocs(final ObjectNode externalDocs) {
+        public Builder externalDocs(final ExternalDocumentation externalDocs) {
             this.externalDocs = externalDocs;
             return this;
         }
 
-        public Builder properties(final ObjectNode properties) {
+        public Builder properties(final Map<String, Property> properties) {
             this.properties = properties;
             return this;
         }
 
-        public Builder xml(final ObjectNode xml) {
+        public Builder xml(final Xml xml) {
             this.xml = xml;
             return this;
         }
diff --git a/restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/model/Xml.java b/restconf/restconf-openapi/src/main/java/org/opendaylight/restconf/openapi/model/Xml.java
new file mode 100644 (file)
index 0000000..2c5a086
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * 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 Xml(
+        @Nullable String name,
+        @Nullable String namespace,
+        @Nullable String prefix,
+        boolean attribute,
+        boolean wrapped) {
+
+    public Xml(@Nullable final String name, @Nullable final String namespace, @Nullable final String prefix) {
+        this(name, namespace, prefix, false, false);
+    }
+}
index ddde629e33b051c2d26b6adcefcbf75a9c8e5603..68b6065c969a128ffcbb5cdd85b5ea7f50ea115b 100644 (file)
@@ -11,7 +11,6 @@ import static org.opendaylight.restconf.openapi.impl.DefinitionGenerator.INPUT;
 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.ArrayNode;
 import com.fasterxml.jackson.databind.node.JsonNodeFactory;
 import com.fasterxml.jackson.databind.node.ObjectNode;
 import java.util.ArrayList;
@@ -116,10 +115,7 @@ public final class OperationBuilder {
     }
 
     private static Parameter buildQueryParameters(final boolean isConfig) {
-        final ArrayNode cases = JsonNodeFactory.instance.arrayNode()
-            .add("config")
-            .add("nonconfig")
-            .add("all");
+        final List<String> cases = List.of("config", "nonconfig", "all");
 
         return new Parameter.Builder()
             .in("query")
index 720102ec23b424fba4b9eb0741e454424eee3f62..0b91b0979a91fcd219c85b4010fd57b68f619e69 100644 (file)
@@ -13,11 +13,12 @@ import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
-import com.fasterxml.jackson.databind.JsonNode;
 import java.net.URI;
+import java.util.Map;
 import javax.ws.rs.core.UriBuilder;
 import javax.ws.rs.core.UriInfo;
 import org.mockito.ArgumentCaptor;
+import org.opendaylight.restconf.openapi.model.Property;
 import org.opendaylight.restconf.openapi.model.Schema;
 
 public final class DocGenTestHelper {
@@ -47,18 +48,14 @@ public final class DocGenTestHelper {
      */
     public static void containsReferences(final Schema mainObject, final String childObject,
             final String expectedRef) {
-        final JsonNode properties = mainObject.properties();
+        final Map<String, Property> properties = mainObject.properties();
         assertNotNull(properties);
 
-        final JsonNode childNode = properties.get(childObject);
+        final Property childNode = properties.get(childObject);
         assertNotNull(childNode);
 
         //list case
-        JsonNode refWrapper = childNode.get("items");
-        if (refWrapper == null) {
-            //container case
-            refWrapper = childNode;
-        }
-        assertEquals(expectedRef, refWrapper.get("$ref").asText());
+        String refWrapper = childNode.items() == null ? childNode.ref() : childNode.items().ref();
+        assertEquals(expectedRef, refWrapper);
     }
 }
index 55bf21034b78e649aeff71a058b2d6c291e5dd50..2b168b30509a791882b2317958167fb5a6d4b9bb 100644 (file)
@@ -17,10 +17,6 @@ import com.fasterxml.jackson.databind.JsonNode;
 import java.util.Map;
 import java.util.Optional;
 import java.util.Set;
-import java.util.Spliterator;
-import java.util.Spliterators;
-import java.util.stream.Collectors;
-import java.util.stream.StreamSupport;
 import org.junit.Before;
 import org.junit.Test;
 import org.opendaylight.mdsal.dom.api.DOMMountPoint;
@@ -140,7 +136,7 @@ public class OperationalDataTest {
     public void testOperationalConfigRootSchemaProperties() {
         final var configRoot = schemas.get("operational_root");
         assertNotNull(configRoot);
-        final var actualProperties = getSetOfProperties(configRoot);
+        final var actualProperties = configRoot.properties().keySet();
         assertEquals(Set.of("leaf-config", "config-container"), actualProperties);
     }
 
@@ -149,7 +145,7 @@ public class OperationalDataTest {
         final var configContOperList = schemas.get(
             "operational_root_config-container_config-container-oper-list");
         assertNotNull(configContOperList);
-        final var actualProperties = getSetOfProperties(configContOperList);
+        final var actualProperties = configContOperList.properties().keySet();
         assertEquals(Set.of("oper-container-list-leaf"), actualProperties);
     }
 
@@ -157,7 +153,7 @@ public class OperationalDataTest {
     public void testOperationalContListSchemaProperties() {
         final var operContList = schemas.get("operational_root_oper-container_oper-container-list");
         assertNotNull(operContList);
-        final var actualProperties = getSetOfProperties(operContList);
+        final var actualProperties = operContList.properties().keySet();
         assertEquals(Set.of("oper-container-list-leaf"), actualProperties);
     }
 
@@ -165,7 +161,7 @@ public class OperationalDataTest {
     public void testOperationalConConfigContSchemaProperties() {
         final var operConConfigCont = schemas.get("operational_root_oper-container_config-container");
         assertNotNull(operConConfigCont);
-        final var actualProperties = getSetOfProperties(operConConfigCont);
+        final var actualProperties = operConConfigCont.properties().keySet();
         assertEquals(Set.of("config-container-config-leaf", "opconfig-container-oper-leaf"), actualProperties);
     }
 
@@ -173,7 +169,7 @@ public class OperationalDataTest {
     public void testOperationalConfigContSchemaProperties() {
         final var configCont = schemas.get("operational_root_config-container");
         assertNotNull(configCont);
-        final var actualProperties = getSetOfProperties(configCont);
+        final var actualProperties = configCont.properties().keySet();
         assertEquals(Set.of("config-container-config-leaf", "leaf-second-case"), actualProperties);
     }
 
@@ -181,7 +177,7 @@ public class OperationalDataTest {
     public void testOperationalContSchemaProperties() {
         final var operCont = schemas.get("operational_root_oper-container");
         assertNotNull(operCont);
-        final var actualProperties = getSetOfProperties(operCont);
+        final var actualProperties = operCont.properties().keySet();
         assertEquals(Set.of("config-container", "oper-container-list", "leaf-first-case", "oper-leaf-first-case",
             "oper-container-config-leaf-list"), actualProperties);
     }
@@ -190,7 +186,7 @@ public class OperationalDataTest {
     public void testListActionSchemaProperties() {
         final var configRoot = schemas.get("action-types_list");
         assertNotNull(configRoot);
-        final var actualProperties = getSetOfProperties(configRoot);
+        final var actualProperties = configRoot.properties().keySet();
         assertEquals(Set.of("name"), actualProperties);
     }
 
@@ -198,7 +194,7 @@ public class OperationalDataTest {
     public void testListActionInputSchemaProperties() {
         final var configRoot = schemas.get("action-types_list-action_input");
         assertNotNull(configRoot);
-        final var actualProperties = getSetOfProperties(configRoot);
+        final var actualProperties = configRoot.properties().keySet();
         assertEquals(Set.of("la-input"), actualProperties);
     }
 
@@ -206,7 +202,7 @@ public class OperationalDataTest {
     public void testListActionOutputSchemaProperties() {
         final var configRoot = schemas.get("action-types_list-action_output");
         assertNotNull(configRoot);
-        final var actualProperties = getSetOfProperties(configRoot);
+        final var actualProperties = configRoot.properties().keySet();
         assertEquals(Set.of("la-output"), actualProperties);
     }
 
@@ -214,7 +210,7 @@ public class OperationalDataTest {
     public void testContainerActionSchemaProperties() {
         final var configRoot = schemas.get("action-types_container");
         assertNotNull(configRoot);
-        final var actualProperties = getSetOfProperties(configRoot);
+        final var actualProperties = configRoot.properties().keySet();
         assertEquals(Set.of(), actualProperties);
     }
 
@@ -222,7 +218,7 @@ public class OperationalDataTest {
     public void testContainerActionInputSchemaProperties() {
         final var configRoot = schemas.get("action-types_container-action_input");
         assertNotNull(configRoot);
-        final var actualProperties = getSetOfProperties(configRoot);
+        final var actualProperties = configRoot.properties().keySet();
         assertEquals(Set.of("ca-input"), actualProperties);
     }
 
@@ -230,7 +226,7 @@ public class OperationalDataTest {
     public void testContainerActionOutputSchemaProperties() {
         final var configRoot = schemas.get("action-types_container-action_output");
         assertNotNull(configRoot);
-        final var actualProperties = getSetOfProperties(configRoot);
+        final var actualProperties = configRoot.properties().keySet();
         assertEquals(Set.of("ca-output"), actualProperties);
     }
 
@@ -270,11 +266,4 @@ public class OperationalDataTest {
         assertTrue("Reference [" + refValue + "] not found in EXPECTED Schemas",
                 EXPECTED_SCHEMAS.contains(schemaElement));
     }
-
-    private static Set<String> getSetOfProperties(final Schema schema) {
-        final var fieldNames = schema.properties().fieldNames();
-        final var fieldNamesSpliterator = Spliterators.spliteratorUnknownSize(fieldNames, Spliterator.ORDERED);
-        return StreamSupport.stream(fieldNamesSpliterator, false)
-            .collect(Collectors.toSet());
-    }
 }
index 20a76747d453da8e983abaaee0e659e336791d91..f619fd33379ee5a9aa6cef4acfb39f0c43a60dcd 100644 (file)
@@ -59,8 +59,8 @@ public final class DefinitionGeneratorTest {
         assertNotNull(jsonObject);
 
         final var properties = jsonObject.get("strings-from-regex_test").properties();
-        assertEquals("00:00:00:00:00:00", properties.get("mac-address").get("example").asText());
-        assertEquals("0000-00-00T00:00:00Z", properties.get("login-date-time").get("example").asText());
-        assertEquals("0.0.0.0", properties.get("ipv4-address").get("example").asText());
+        assertEquals("00:00:00:00:00:00", properties.get("mac-address").example().toString());
+        assertEquals("0000-00-00T00:00:00Z", properties.get("login-date-time").example().toString());
+        assertEquals("0.0.0.0", properties.get("ipv4-address").example().toString());
     }
 }
index da26b1254bbaf652c35818f5ee26f86233eaef73..62c869282fde7ea2eda0a55c5afcb237a074641c 100644 (file)
@@ -24,8 +24,6 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.stream.Collectors;
-import java.util.stream.StreamSupport;
 import javax.ws.rs.core.UriInfo;
 import org.junit.BeforeClass;
 import org.junit.Test;
@@ -34,6 +32,7 @@ import org.opendaylight.restconf.openapi.DocGenTestHelper;
 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.Property;
 import org.opendaylight.restconf.openapi.model.Schema;
 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
@@ -153,9 +152,9 @@ public final class OpenApiGeneratorRFC8040Test {
 
         final Map<String, Schema> schemas = doc.components().schemas();
         final Schema input = schemas.get("toaster_make-toast_input");
-        final JsonNode properties = input.properties();
-        assertTrue(properties.has("toasterDoneness"));
-        assertTrue(properties.has("toasterToastType"));
+        final Map<String, Property> properties = input.properties();
+        assertTrue(properties.containsKey("toasterDoneness"));
+        assertTrue(properties.containsKey("toasterToastType"));
     }
 
     @Test
@@ -165,12 +164,12 @@ public final class OpenApiGeneratorRFC8040Test {
 
         final var schemas = doc.components().schemas();
         final var firstContainer = schemas.get("choice-test_first-container");
-        assertEquals("default-value", firstContainer.properties().get("leaf-default").get("default").asText());
-        assertFalse(firstContainer.properties().has("leaf-non-default"));
+        assertEquals("default-value", firstContainer.properties().get("leaf-default").defaultValue().toString());
+        assertFalse(firstContainer.properties().containsKey("leaf-non-default"));
 
         final var secondContainer = schemas.get("choice-test_second-container");
-        assertTrue(secondContainer.properties().has("leaf-first-case"));
-        assertFalse(secondContainer.properties().has("leaf-second-case"));
+        assertTrue(secondContainer.properties().containsKey("leaf-first-case"));
+        assertFalse(secondContainer.properties().containsKey("leaf-second-case"));
     }
 
     @Test
@@ -180,20 +179,20 @@ public final class OpenApiGeneratorRFC8040Test {
         final var schemas = doc.components().schemas();
         final var containersWithRequired = new ArrayList<String>();
 
-        final var reqRootContainerElements = Set.of("mandatory-root-leaf", "mandatory-container",
+        final var reqRootContainerElements = List.of("mandatory-root-leaf", "mandatory-container",
             "mandatory-first-choice", "mandatory-list");
         verifyRequiredField(schemas.get(CONFIG_ROOT_CONTAINER), reqRootContainerElements);
         containersWithRequired.add(CONFIG_ROOT_CONTAINER);
 
-        final var reqMandatoryContainerElements = Set.of("mandatory-leaf", "leaf-list-with-min-elements");
+        final var reqMandatoryContainerElements = List.of("mandatory-leaf", "leaf-list-with-min-elements");
         verifyRequiredField(schemas.get(CONFIG_MANDATORY_CONTAINER), reqMandatoryContainerElements);
         containersWithRequired.add(CONFIG_MANDATORY_CONTAINER);
 
-        final var reqMandatoryListElements = Set.of("mandatory-list-field");
+        final var reqMandatoryListElements = List.of("mandatory-list-field");
         verifyRequiredField(schemas.get(CONFIG_MANDATORY_LIST), reqMandatoryListElements);
         containersWithRequired.add(CONFIG_MANDATORY_LIST);
 
-        final var testModuleMandatoryArray = Set.of("root-container", "root-mandatory-list");
+        final var testModuleMandatoryArray = List.of("root-container", "root-mandatory-list");
         verifyRequiredField(schemas.get(MANDATORY_TEST_MODULE), testModuleMandatoryArray);
         containersWithRequired.add(MANDATORY_TEST_MODULE);
 
@@ -440,14 +439,10 @@ public final class OpenApiGeneratorRFC8040Test {
         }
     }
 
-    private static void verifyRequiredField(final Schema rootContainer, final Set<String> expected) {
+    private static void verifyRequiredField(final Schema rootContainer, final List<String> expected) {
         assertNotNull(rootContainer);
         final var required = rootContainer.required();
         assertNotNull(required);
-        assertTrue(required.isArray());
-        final var actualContainerArray = StreamSupport.stream(required.spliterator(), false)
-            .map(JsonNode::textValue)
-            .collect(Collectors.toSet());
-        assertEquals(expected, actualContainerArray);
+        assertEquals(expected, required);
     }
 }
index 3f437bd04957def59cb4f5834d28ffd0df95cf70..8ea5ec5a5191ab2a29dd8828ecf17b4f0b14f208 100644 (file)
@@ -9,7 +9,7 @@ package org.opendaylight.restconf.openapi.impl;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertNull;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
@@ -128,46 +128,44 @@ public class OpenApiXmlNamespaceTest {
     @Test
     public void testAugmentedListInContainer() {
         final var simpleList1 = schemas.get("module_root_simple-root_list-1");
-        assertEquals(TEST_AUGMENTATION_NAMESPACE, simpleList1.xml().path("namespace").asText());
-        assertTrue(simpleList1.properties().path("leaf-x").path("xml").isMissingNode());
+        assertEquals(TEST_AUGMENTATION_NAMESPACE, simpleList1.xml().namespace());
+        assertNull(simpleList1.properties().get("leaf-x").xml());
     }
 
     @Test
     public void testAugmentedContainerInContainer() {
         final var simpleAbc = schemas.get("module_root_simple-root_abc");
-        assertEquals(TEST_AUGMENTATION_NAMESPACE, simpleAbc.xml().path("namespace").asText());
-        assertTrue(simpleAbc.properties().path("leaf-abc").path("xml").isMissingNode());
+        assertEquals(TEST_AUGMENTATION_NAMESPACE, simpleAbc.xml().namespace());
+        assertNull(simpleAbc.properties().get("leaf-abc").xml());
     }
 
     @Test
     public void testAugmentedLeafInContainer() {
         final var simple = schemas.get("module_root_simple-root");
-        assertEquals(TEST_MODULE_NAMESPACE, simple.xml().path("namespace").asText());
-        assertEquals(TEST_AUGMENTATION_NAMESPACE, simple.properties().path("leaf-y").path("xml")
-            .path("namespace").asText());
-        assertTrue(simple.properties().path("leaf-a").path("xml").isMissingNode());
+        assertEquals(TEST_MODULE_NAMESPACE, simple.xml().namespace());
+        assertEquals(TEST_AUGMENTATION_NAMESPACE, simple.properties().get("leaf-y").xml().namespace());
+        assertNull(simple.properties().get("leaf-a").xml());
     }
 
     @Test
     public void testAugmentedListInList() {
         final var topList1 = schemas.get("module_root_top-list_list-1");
-        assertEquals(TEST_AUGMENTATION_NAMESPACE, topList1.xml().path("namespace").asText());
-        assertTrue(topList1.properties().path("leaf-x").path("xml").isMissingNode());
+        assertEquals(TEST_AUGMENTATION_NAMESPACE, topList1.xml().namespace());
+        assertNull(topList1.properties().get("leaf-x").xml());
     }
 
     @Test
     public void testAugmentedContainerInList() {
         final var topAbc = schemas.get("module_root_top-list_abc");
-        assertEquals(TEST_AUGMENTATION_NAMESPACE, topAbc.xml().path("namespace").asText());
-        assertTrue(topAbc.properties().path("leaf-abc").path("xml").isMissingNode());
+        assertEquals(TEST_AUGMENTATION_NAMESPACE, topAbc.xml().namespace());
+        assertNull(topAbc.properties().get("leaf-abc").xml());
     }
 
     @Test
     public void testAugmentedLeafInList() {
         final var top = schemas.get("module_root_top-list");
-        assertEquals(TEST_MODULE_NAMESPACE, top.xml().path("namespace").asText());
-        assertEquals(TEST_AUGMENTATION_NAMESPACE, top.properties().path("leaf-y").path("xml")
-            .path("namespace").asText());
-        assertTrue(top.properties().path("key-1").path("xml").isMissingNode());
+        assertEquals(TEST_MODULE_NAMESPACE, top.xml().namespace());
+        assertEquals(TEST_AUGMENTATION_NAMESPACE, top.properties().get("leaf-y").xml().namespace());
+        assertNull(top.properties().get("key-1").xml());
     }
 }