Merge "Bug 2818: Updated implementation of parser."
authorRobert Varga <nite@hq.sk>
Thu, 12 Mar 2015 21:20:01 +0000 (21:20 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Thu, 12 Mar 2015 21:20:02 +0000 (21:20 +0000)
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/ChoiceNodeDataWithSchema.java
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/CompositeNodeDataWithSchema.java
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JsonParserStream.java
yang/yang-data-codec-gson/src/test/java/org/opendaylight/yangtools/yang/data/codec/gson/JsonStreamToNormalizedNodeTest.java
yang/yang-data-codec-gson/src/test/resources/complexjson/keyed-list-yang-json-behaviour.json [new file with mode: 0644]

index cacc6727def1a89e8a842192d6f5600bdee815c6..b7ab6fa19bef10d50eccd9dc9f612c3b0e1f5022 100644 (file)
@@ -27,8 +27,8 @@ class ChoiceNodeDataWithSchema extends CompositeNodeDataWithSchema {
     }
 
     @Override
-    protected CompositeNodeDataWithSchema addCompositeChild(final DataSchemaNode schema, final boolean rootListItem) {
-        final CaseNodeDataWithSchema newChild = new CaseNodeDataWithSchema((ChoiceCaseNode) schema);
+    protected CompositeNodeDataWithSchema addCompositeChild(final DataSchemaNode schema) {
+        CaseNodeDataWithSchema newChild = new CaseNodeDataWithSchema((ChoiceCaseNode) schema);
         caseNodeDataWithSchema = newChild;
         addCompositeChild(newChild);
         return newChild;
index c071bbde826fe3c3d98f5f05de11285967f3830b..70612910d65ae098371ba9635c1004546a410be2 100644 (file)
@@ -59,14 +59,14 @@ class CompositeNodeDataWithSchema extends AbstractNodeDataWithSchema {
         super(schema);
     }
 
-    public AbstractNodeDataWithSchema addChild(final Deque<DataSchemaNode> schemas, final boolean rootListItem) {
+    public AbstractNodeDataWithSchema addChild(final Deque<DataSchemaNode> schemas) {
         Preconditions.checkArgument(!schemas.isEmpty(), "Expecting at least one schema");
 
         // Pop the first node...
         final DataSchemaNode schema = schemas.pop();
         if (schemas.isEmpty()) {
             // Simple, direct node
-            return addChild(schema,rootListItem);
+            return addChild(schema);
         }
 
         // The choice/case mess, reuse what we already popped
@@ -95,12 +95,12 @@ class CompositeNodeDataWithSchema extends AbstractNodeDataWithSchema {
 
         CompositeNodeDataWithSchema caseNodeDataWithSchema = findChoice(childNodes, choiceCandidate, caseCandidate);
         if (caseNodeDataWithSchema == null) {
-            final ChoiceNodeDataWithSchema choiceNodeDataWithSchema = new ChoiceNodeDataWithSchema(choiceNode);
+            ChoiceNodeDataWithSchema choiceNodeDataWithSchema = new ChoiceNodeDataWithSchema(choiceNode);
             addChild(choiceNodeDataWithSchema);
-            caseNodeDataWithSchema = choiceNodeDataWithSchema.addCompositeChild(caseNode,rootListItem);
+            caseNodeDataWithSchema = choiceNodeDataWithSchema.addCompositeChild(caseNode);
         }
 
-        return caseNodeDataWithSchema.addChild(schemas, rootListItem);
+        return caseNodeDataWithSchema.addChild(schemas);
     }
 
     private AbstractNodeDataWithSchema addSimpleChild(final DataSchemaNode schema) {
@@ -128,10 +128,10 @@ class CompositeNodeDataWithSchema extends AbstractNodeDataWithSchema {
     private CaseNodeDataWithSchema findChoice(final Collection<AbstractNodeDataWithSchema> childNodes, final DataSchemaNode choiceCandidate,
             final DataSchemaNode caseCandidate) {
         if (childNodes != null) {
-            for (final AbstractNodeDataWithSchema nodeDataWithSchema : childNodes) {
+            for (AbstractNodeDataWithSchema nodeDataWithSchema : childNodes) {
                 if (nodeDataWithSchema instanceof ChoiceNodeDataWithSchema
                         && nodeDataWithSchema.getSchema().getQName().equals(choiceCandidate.getQName())) {
-                    final CaseNodeDataWithSchema casePrevious = ((ChoiceNodeDataWithSchema) nodeDataWithSchema).getCase();
+                    CaseNodeDataWithSchema casePrevious = ((ChoiceNodeDataWithSchema) nodeDataWithSchema).getCase();
 
                     Preconditions.checkArgument(casePrevious.getSchema().getQName().equals(caseCandidate.getQName()),
                         "Data from case %s are specified but other data from case %s were specified erlier. Data aren't from the same case.",
@@ -144,20 +144,10 @@ class CompositeNodeDataWithSchema extends AbstractNodeDataWithSchema {
         return null;
     }
 
-    AbstractNodeDataWithSchema addCompositeChild(final DataSchemaNode schema, final boolean rootListItem) {
+    AbstractNodeDataWithSchema addCompositeChild(final DataSchemaNode schema) {
         CompositeNodeDataWithSchema newChild;
         if (schema instanceof ListSchemaNode) {
             newChild = new ListNodeDataWithSchema(schema);
-            /*
-             * If we are reading root we may want to emit map also for object which represent one list
-             * item.
-             * */
-            if(rootListItem) {
-                addCompositeChild(newChild);
-                final ListEntryNodeDataWithSchema entry = new ListEntryNodeDataWithSchema(schema);
-                newChild.addChild(entry);
-                return entry;
-            }
         } else if (schema instanceof LeafListSchemaNode) {
             newChild = new LeafListNodeDataWithSchema(schema);
         } else if (schema instanceof ContainerSchemaNode) {
@@ -170,7 +160,7 @@ class CompositeNodeDataWithSchema extends AbstractNodeDataWithSchema {
     }
 
     void addCompositeChild(final CompositeNodeDataWithSchema newChild) {
-        final AugmentationSchema augSchema = findCorrespondingAugment(getSchema(), newChild.getSchema());
+        AugmentationSchema augSchema = findCorrespondingAugment(getSchema(), newChild.getSchema());
         if (augSchema != null) {
             augmentationsToChild.put(augSchema, newChild);
         } else {
@@ -178,9 +168,9 @@ class CompositeNodeDataWithSchema extends AbstractNodeDataWithSchema {
         }
     }
 
-    private AbstractNodeDataWithSchema addChild(final DataSchemaNode schema, final boolean rootListItem) {
-        final AbstractNodeDataWithSchema newChild = addSimpleChild(schema);
-        return newChild == null ? addCompositeChild(schema,rootListItem) : newChild;
+    private AbstractNodeDataWithSchema addChild(final DataSchemaNode schema) {
+        AbstractNodeDataWithSchema newChild = addSimpleChild(schema);
+        return newChild == null ? addCompositeChild(schema) : newChild;
     }
 
     public void addChild(final AbstractNodeDataWithSchema newChild) {
@@ -201,8 +191,8 @@ class CompositeNodeDataWithSchema extends AbstractNodeDataWithSchema {
      */
     AugmentationSchema findCorrespondingAugment(final DataSchemaNode parent, final DataSchemaNode child) {
         if (parent instanceof AugmentationTarget && !((parent instanceof ChoiceCaseNode) || (parent instanceof ChoiceSchemaNode))) {
-            for (final AugmentationSchema augmentation : ((AugmentationTarget) parent).getAvailableAugmentations()) {
-                final DataSchemaNode childInAugmentation = augmentation.getDataChildByName(child.getQName());
+            for (AugmentationSchema augmentation : ((AugmentationTarget) parent).getAvailableAugmentations()) {
+                DataSchemaNode childInAugmentation = augmentation.getDataChildByName(child.getQName());
                 if (childInAugmentation != null) {
                     return augmentation;
                 }
@@ -213,15 +203,15 @@ class CompositeNodeDataWithSchema extends AbstractNodeDataWithSchema {
 
     @Override
     public void write(final NormalizedNodeStreamWriter writer) throws IOException {
-        for (final AbstractNodeDataWithSchema child : children) {
+        for (AbstractNodeDataWithSchema child : children) {
             child.write(writer);
         }
-        for (final Entry<AugmentationSchema, Collection<AbstractNodeDataWithSchema>> augmentationToChild : augmentationsToChild.asMap().entrySet()) {
+        for (Entry<AugmentationSchema, Collection<AbstractNodeDataWithSchema>> augmentationToChild : augmentationsToChild.asMap().entrySet()) {
             final Collection<AbstractNodeDataWithSchema> childsFromAgumentation = augmentationToChild.getValue();
             if (!childsFromAgumentation.isEmpty()) {
                 writer.startAugmentationNode(toAugmentationIdentifier(augmentationToChild.getKey()));
 
-                for (final AbstractNodeDataWithSchema nodeDataWithSchema : childsFromAgumentation) {
+                for (AbstractNodeDataWithSchema nodeDataWithSchema : childsFromAgumentation) {
                     nodeDataWithSchema.write(writer);
                 }
 
index f56d6d2344880a6aa676be7230930be41521256d..4934161bd2757fcc1d0b9ab2d98b793c7721f15c 100644 (file)
@@ -83,7 +83,7 @@ public final class JsonParserStream implements Closeable, Flushable {
             reader.peek();
             isEmpty = false;
             final CompositeNodeDataWithSchema compositeNodeDataWithSchema = new CompositeNodeDataWithSchema(parentNode);
-            read(reader, compositeNodeDataWithSchema,true);
+            read(reader, compositeNodeDataWithSchema);
             compositeNodeDataWithSchema.write(writer);
 
             return this;
@@ -115,7 +115,7 @@ public final class JsonParserStream implements Closeable, Flushable {
         ((SimpleNodeDataWithSchema) parent).setValue(translatedValue);
     }
 
-    public void read(final JsonReader in, final AbstractNodeDataWithSchema parent, final boolean rootRead) throws IOException {
+    public void read(final JsonReader in, AbstractNodeDataWithSchema parent) throws IOException {
         switch (in.peek()) {
         case STRING:
         case NUMBER:
@@ -131,21 +131,24 @@ public final class JsonParserStream implements Closeable, Flushable {
         case BEGIN_ARRAY:
             in.beginArray();
             while (in.hasNext()) {
-                AbstractNodeDataWithSchema newChild = null;
-                if (parent instanceof ListNodeDataWithSchema) {
-                    newChild = new ListEntryNodeDataWithSchema(parent.getSchema());
-                    ((CompositeNodeDataWithSchema) parent).addChild(newChild);
-                } else if (parent instanceof LeafListNodeDataWithSchema) {
-                    newChild = new LeafListEntryNodeDataWithSchema(parent.getSchema());
-                    ((CompositeNodeDataWithSchema) parent).addChild(newChild);
-                }
-                read(in, newChild,false);
+                final AbstractNodeDataWithSchema newChild = newArrayEntry(parent);
+                read(in, newChild);
             }
             in.endArray();
             return;
         case BEGIN_OBJECT:
             final Set<String> namesakes = new HashSet<>();
             in.beginObject();
+            /*
+             * This allows parsing of incorrectly /as showcased/
+             * in testconf nesting of list items - eg.
+             * lists with one value are sometimes serialized
+             * without wrapping array.
+             *
+             */
+            if(isArray(parent)) {
+                parent = newArrayEntry(parent);
+            }
             while (in.hasNext()) {
                 final String jsonElementName = in.nextName();
                 final NamespaceAndName namespaceAndName = resolveNamespace(jsonElementName, parent.getSchema());
@@ -162,13 +165,16 @@ public final class JsonParserStream implements Closeable, Flushable {
                             + getCurrentNamespace() + " doesn't exist.");
                 }
 
-                AbstractNodeDataWithSchema newChild;
-                newChild = ((CompositeNodeDataWithSchema) parent).addChild(childDataSchemaNodes,rootRead);
-//                FIXME:anyxml data shouldn't be skipped but should be loaded somehow. will be specified after 17AUG2014
+                final AbstractNodeDataWithSchema newChild = ((CompositeNodeDataWithSchema) parent).addChild(childDataSchemaNodes);
+                /*
+                 * FIXME:anyxml data shouldn't be skipped but should be loaded somehow.
+                 * will be able to load anyxml which conforms to YANG data using these
+                 * parser, for other anyxml will be harder.
+                 */
                 if (newChild instanceof AnyXmlNodeDataWithSchema) {
                     in.skipValue();
                 } else {
-                    read(in, newChild,false);
+                    read(in, newChild);
                 }
                 removeNamespace();
             }
@@ -182,6 +188,23 @@ public final class JsonParserStream implements Closeable, Flushable {
         }
     }
 
+    private boolean isArray(final AbstractNodeDataWithSchema parent) {
+        return parent instanceof ListNodeDataWithSchema || parent instanceof ListNodeDataWithSchema;
+    }
+
+    private AbstractNodeDataWithSchema newArrayEntry(final AbstractNodeDataWithSchema parent) {
+        AbstractNodeDataWithSchema newChild;
+        if (parent instanceof ListNodeDataWithSchema) {
+            newChild = new ListEntryNodeDataWithSchema(parent.getSchema());
+        } else if (parent instanceof LeafListNodeDataWithSchema) {
+            newChild = new LeafListEntryNodeDataWithSchema(parent.getSchema());
+        } else {
+            throw new IllegalStateException("Incorrec nesting caused by parser.");
+        }
+        ((CompositeNodeDataWithSchema) parent).addChild(newChild);
+        return newChild;
+    }
+
     private Object translateValueByType(final String value, final DataSchemaNode node) {
         final TypeDefinition<? extends Object> typeDefinition = typeDefinition(node);
         if (typeDefinition == null) {
index 6fb7b1ed34cfc2d7e7860d06f67f753ecf6aebaf..c1ff375d2374ba29a7e3a9e61bd02ad768e4ccf2 100644 (file)
@@ -200,6 +200,19 @@ public class JsonStreamToNormalizedNodeTest {
         assertNotNull(transformedInput);
     }
 
+    @Test
+    public void listItemWithArray() throws IOException, URISyntaxException {
+        final String inputJson = loadTextFile("/complexjson/keyed-list-yang-json-behaviour.json");
+
+        final NormalizedNodeResult result = new NormalizedNodeResult();
+        final NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
+        final SchemaNode parentNode = schemaContext.getDataChildByName("cont1");
+        final JsonParserStream jsonParser = JsonParserStream.create(streamWriter, schemaContext, parentNode);
+        jsonParser.parse(new JsonReader(new StringReader(inputJson)));
+        final NormalizedNode<?, ?> transformedInput = result.getResult();
+        assertNotNull(transformedInput);
+    }
+
     private void verifyTransformationToNormalizedNode(final String inputJson,
             final NormalizedNode<?, ?> awaitedStructure) {
         final NormalizedNodeResult result = new NormalizedNodeResult();
diff --git a/yang/yang-data-codec-gson/src/test/resources/complexjson/keyed-list-yang-json-behaviour.json b/yang/yang-data-codec-gson/src/test/resources/complexjson/keyed-list-yang-json-behaviour.json
new file mode 100644 (file)
index 0000000..af6b3ec
--- /dev/null
@@ -0,0 +1,8 @@
+{
+  "lst11": [{
+                "key111":"key111 value",
+                "lf112":"/complexjson:cont1/complexjson:lflst11[.='foo']",
+                "lf113":"lf113 value",
+                "lf111":"lf111 value"
+            }]
+}