From: Balaji Varadaraju Date: Tue, 17 Apr 2018 23:08:32 +0000 (-0500) Subject: YANGTOOLS-804: Netconf payload fails to render in JSON for anyxml X-Git-Tag: v2.0.5~17 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=commitdiff_plain;h=4a8280dbad8a080d4b5253e25fc68ec279a3d99d;p=yangtools.git YANGTOOLS-804: Netconf payload fails to render in JSON for anyxml When a YANG model contains an anyxml element the output does not render correctly in JSON in Restconf. XML output works however. Upon investigation we found issue was with recognising and handling collections in XML. This patch addresses the same and also enhanced and added more unit tests. Change-Id: Icb238dd95a3b9af9c4d0f48ff673a7c285925364 Signed-off-by: Balaji Varadaraju Signed-off-by: Robert Varga --- diff --git a/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONNormalizedNodeStreamWriter.java b/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONNormalizedNodeStreamWriter.java index 23aa8565c4..6311b7ce54 100644 --- a/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONNormalizedNodeStreamWriter.java +++ b/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONNormalizedNodeStreamWriter.java @@ -8,7 +8,6 @@ package org.opendaylight.yangtools.yang.data.codec.gson; import static java.util.Objects.requireNonNull; -import static org.opendaylight.yangtools.yang.data.codec.gson.JsonParserStream.ANYXML_ARRAY_ELEMENT_ID; import static org.w3c.dom.Node.ELEMENT_NODE; import static org.w3c.dom.Node.TEXT_NODE; @@ -278,34 +277,69 @@ public abstract class JSONNormalizedNodeStreamWriter implements NormalizedNodeSt } private void writeXmlNode(final Node node) throws IOException { + if (isArrayElement(node)) { + writeArrayContent(node); + return; + } final Element firstChildElement = getFirstChildElement(node); if (firstChildElement == null) { writeXmlValue(node); - } else if (ANYXML_ARRAY_ELEMENT_ID.equals(firstChildElement.getNodeName())) { - writer.beginArray(); - writeArray(firstChildElement); - writer.endArray(); } else { - writer.beginObject(); - writeObject(firstChildElement); - writer.endObject(); + writeObjectContent(firstChildElement); } } - private void writeArray(Node node) throws IOException { - while (node != null) { - if (ELEMENT_NODE == node.getNodeType()) { - writeXmlNode(node); + private void writeArrayContent(final Node node) throws IOException { + writer.beginArray(); + handleArray(node); + writer.endArray(); + } + + private void writeObjectContent(final Element firstChildElement) throws IOException { + writer.beginObject(); + writeObject(firstChildElement); + writer.endObject(); + } + + private static boolean isArrayElement(final Node node) { + if (ELEMENT_NODE == node.getNodeType()) { + final String nodeName = node.getNodeName(); + for (Node nextNode = node.getNextSibling(); nextNode != null; nextNode = nextNode.getNextSibling()) { + if (ELEMENT_NODE == nextNode.getNodeType() && nodeName.equals(nextNode.getNodeName())) { + return true; + } + } + } + return false; + } + + private void handleArray(final Node node) throws IOException { + final Element parentNode = (Element)node.getParentNode(); + final NodeList elementsList = parentNode.getElementsByTagName(node.getNodeName()); + for (int i = 0, length = elementsList.getLength(); i < length; i++) { + final Node arrayElement = elementsList.item(i); + final Element parent = (Element)arrayElement.getParentNode(); + if (parentNode.isSameNode(parent)) { + final Element firstChildElement = getFirstChildElement(arrayElement); + if (firstChildElement != null) { + writeObjectContent(firstChildElement); + } else { + // It may be scalar + writeXmlValue(arrayElement); + } } - node = node.getNextSibling(); } } private void writeObject(Node node) throws IOException { + String previousNodeName = ""; while (node != null) { if (ELEMENT_NODE == node.getNodeType()) { - writer.name(node.getNodeName()); - writeXmlNode(node); + if (!node.getNodeName().equals(previousNodeName)) { + previousNodeName = node.getNodeName(); + writer.name(node.getNodeName()); + writeXmlNode(node); + } } node = node.getNextSibling(); } diff --git a/yang/yang-data-codec-gson/src/test/java/org/opendaylight/yangtools/yang/data/codec/gson/AnyXmlSupportTest.java b/yang/yang-data-codec-gson/src/test/java/org/opendaylight/yangtools/yang/data/codec/gson/AnyXmlSupportTest.java index 75f5622346..7dfd241d47 100644 --- a/yang/yang-data-codec-gson/src/test/java/org/opendaylight/yangtools/yang/data/codec/gson/AnyXmlSupportTest.java +++ b/yang/yang-data-codec-gson/src/test/java/org/opendaylight/yangtools/yang/data/codec/gson/AnyXmlSupportTest.java @@ -5,7 +5,6 @@ * 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.yangtools.yang.data.codec.gson; import static org.junit.Assert.assertEquals; @@ -119,7 +118,6 @@ public class AnyXmlSupportTest { final DOMSource Lf12AnyActualValue = getParsedAnyXmlValue(transformedInput, LF12_ANY); final DOMSource Lf12AnyExpectedValue = createLf12AnyXmlCompositeValue("ns:complex:json", "lf12-any"); verifyTransformedAnyXmlNodeValue(Lf12AnyExpectedValue, Lf12AnyActualValue); - // lf13-any check final DOMSource Lf13AnyActualValue = getParsedAnyXmlValue(transformedInput, LF13_ANY); final DOMSource Lf13AnyExpectedValue = createLf13AnyXmlCompositeValue("ns:complex:json", "lf13-any"); @@ -135,15 +133,37 @@ public class AnyXmlSupportTest { SchemaPath.ROOT); final JsonParser parser = new JsonParser(); - final JsonElement expected = parser.parse(inputJson); + final String expectedJson = loadTextFile("/bug8927/json/composite.json"); + final JsonElement expected = parser.parse(expectedJson); final JsonElement actual = parser.parse(serializationResult); assertTrue(expected.equals(actual)); } @Test - public void bug8927Test() throws Exception { + public void bug8927TestComplexArrayWithOthers() throws Exception { + executebug8927Test("/bug8927/xml/complex_array_with_other_elements.xml", + "/bug8927/json/complex_array_with_other_elements.json"); + } + + @Test + public void bug8927TestComplexArray() throws Exception { + executebug8927Test("/bug8927/xml/complex_array.xml", "/bug8927/json/complex_array.json"); + } + + @Test + public void bug8927TestScalarArrayWithOthers() throws Exception { + executebug8927Test("/bug8927/xml/scalar_array_with_other_elements.xml", + "/bug8927/json/scalar_array_with_other_elements.json"); + } + + @Test + public void bug8927TestScalarArray() throws Exception { + executebug8927Test("/bug8927/xml/scalar_array.xml", "/bug8927/json/scalar_array.json"); + } + + private void executebug8927Test(final String inputXmlFile, final String expectedJsonFile) throws Exception { final InputStream resourceAsStream = YangModeledAnyXmlSupportTest.class - .getResourceAsStream("/bug8927/xml/input.xml"); + .getResourceAsStream(inputXmlFile); final NormalizedNodeResult result = new NormalizedNodeResult(); loadXmlToNormalizedNodes(resourceAsStream, result, schemaContext); @@ -154,12 +174,10 @@ public class AnyXmlSupportTest { .getChild(new NodeIdentifier(QName.create("bug8927.test", "2017-01-01", "foo"))); assertTrue(data.isPresent()); final String jsonOutput = normalizedNodesToJsonString(data.get(), schemaContext, SchemaPath.ROOT); - final JsonParser parser = new JsonParser(); final JsonElement expextedJson = parser - .parse(new FileReader(new File(getClass().getResource("/bug8927/json/expected.json").toURI()))); + .parse(new FileReader(new File(getClass().getResource(expectedJsonFile).toURI()))); final JsonElement serializedJson = parser.parse(jsonOutput); - assertEquals(expextedJson, serializedJson); } diff --git a/yang/yang-data-codec-gson/src/test/resources/bug8927/json/complex_array.json b/yang/yang-data-codec-gson/src/test/resources/bug8927/json/complex_array.json new file mode 100644 index 0000000000..0d14d9785a --- /dev/null +++ b/yang/yang-data-codec-gson/src/test/resources/bug8927/json/complex_array.json @@ -0,0 +1,23 @@ +{ + "bug8927:foo": { + "alarm-information": { + "alarm-detail": [{ + "alarm-time": "2017-08-02 19:03:44 UTC", + "alarm-class": "Minor", + "alarm-description": [{ + "test": 123 + }, { + "test": 456 + }], + "alarm-short-description": "gnf-creation", + "alarm-type": "License" + }, { + "alarm-time": "2017-07-25 16:04:31 UTC", + "alarm-class": ["Minor", "Minor1"], + "alarm-description": "VMHost RE 0 host application failed", + "alarm-short-description": "VMHost RE 0 host ap", + "alarm-type": "Chassis" + }] + } + } +} diff --git a/yang/yang-data-codec-gson/src/test/resources/bug8927/json/complex_array_with_other_elements.json b/yang/yang-data-codec-gson/src/test/resources/bug8927/json/complex_array_with_other_elements.json new file mode 100644 index 0000000000..ff4ef05074 --- /dev/null +++ b/yang/yang-data-codec-gson/src/test/resources/bug8927/json/complex_array_with_other_elements.json @@ -0,0 +1,122 @@ +{ + "bug8927:foo": { + "alarm-information": { + "alarm-summary": { + "active-alarm-count": "" + }, + "alarm-detail":[ { + "alarm-time": "2017-08-02 19:03:44 UTC", + "alarm-class": "Minor", + "alarm-description": "desc", + "alarm-short-description": "gnf-creation", + "alarm-type": "License" + }, + { + "alarm-time": "2017-07-25 16:04:31 UTC", + "alarm-class": "Minor", + "alarm-description": "VMHost RE 0 host application failed", + "alarm-short-description": "VMHost RE 0 host ap", + "alarm-type": "Chassis" + }, + { + "alarm-time": "2017-07-25 16:04:31 UTC", + "alarm-class": "Major", + "alarm-description": "PDM 0 incompatible with chassis type", + "alarm-short-description": "PDM 0 incompatible", + "alarm-type": "Chassis" + }, + { + "alarm-time": "2017-07-25 16:04:31 UTC", + "alarm-class": "Major", + "alarm-description": "PDM 1 incompatible with chassis type", + "alarm-short-description": "PDM 1 incompatible", + "alarm-type": "Chassis" + }, + { + "alarm-time": "2017-07-25 16:04:31 UTC", + "alarm-class": "Major", + "alarm-description": "PDM 2 incompatible with chassis type", + "alarm-short-description": "PDM 2 incompatible", + "alarm-type": "Chassis" + }, + { + "alarm-time": "2017-07-25 16:04:31 UTC", + "alarm-class": "Major", + "alarm-description": "PDM 3 incompatible with chassis type", + "alarm-short-description": "PDM 3 incompatible", + "alarm-type": "Chassis" + }, + { + "alarm-time": "2017-07-25 16:04:31 UTC", + "alarm-class": "Major", + "alarm-description": "No Input Feed Selected for PSM 1", + "alarm-short-description": "No Input Feed Selec", + "alarm-type": "Chassis" + }, + { + "alarm-time": "2017-07-25 16:04:31 UTC", + "alarm-class": "Major", + "alarm-description": "No Input Feed Selected for PSM 2", + "alarm-short-description": "No Input Feed Selec", + "alarm-type": "Chassis" + }, + { + "alarm-time": "2017-07-25 16:04:31 UTC", + "alarm-class": "Major", + "alarm-description": "No Input Feed Selected for PSM 3", + "alarm-short-description": "No Input Feed Selec", + "alarm-type": "Chassis" + }, + { + "alarm-time": "2017-07-25 16:04:31 UTC", + "alarm-class": "Major", + "alarm-description": "No Input Feed Selected for PSM 4", + "alarm-short-description": "No Input Feed Selec", + "alarm-type": "Chassis" + }, + { + "alarm-time": "2017-07-25 16:04:31 UTC", + "alarm-class": "Major", + "alarm-description": "No Input Feed Selected for PSM 10", + "alarm-short-description": "No Input Feed Selec", + "alarm-type": "Chassis" + }, + { + "alarm-time": "2017-07-25 16:04:31 UTC", + "alarm-class": "Major", + "alarm-description": "No Input Feed Selected for PSM 11", + "alarm-short-description": "No Input Feed Selec", + "alarm-type": "Chassis" + }, + { + "alarm-time": "2017-07-25 16:04:31 UTC", + "alarm-class": "Major", + "alarm-description": "No Input Feed Selected for PSM 12", + "alarm-short-description": "No Input Feed Selec", + "alarm-type": "Chassis" + }, + { + "alarm-time": "2017-07-25 16:04:31 UTC", + "alarm-class": "Major", + "alarm-description": "No Input Feed Selected for PSM 13", + "alarm-short-description": "No Input Feed Selec", + "alarm-type": "Chassis" + }, + { + "alarm-time": "2017-07-25 16:04:31 UTC", + "alarm-class": "Minor", + "alarm-description": "VMHost RE 1 host application failed", + "alarm-short-description": "VMHost RE 1 host ap", + "alarm-type": "Chassis" + }, + { + "alarm-time": "2017-07-25 16:04:31 UTC", + "alarm-class": "Minor", + "alarm-description": "Check plane 1 Fabric Chip", + "alarm-short-description": "Check plane 1 FCHIP", + "alarm-type": "Chassis" + } + ] + } + } +} diff --git a/yang/yang-data-codec-gson/src/test/resources/bug8927/json/composite.json b/yang/yang-data-codec-gson/src/test/resources/bug8927/json/composite.json new file mode 100644 index 0000000000..a9eb3332fd --- /dev/null +++ b/yang/yang-data-codec-gson/src/test/resources/bug8927/json/composite.json @@ -0,0 +1,41 @@ +{ + "complexjson:cont1": { + "lf14-any": { + "anyxml-object-a": { + "data-a1": 10, + "data-a2": 11 + }, + "anyxml-object-b": { + "child-object-b1": { + "data-b1": 5.5 + }, + "child-object-b2": { + "data-b2": "b2-val" + } + } + }, + "lf12-any": { + "array-element": [true, { + "baz": { + "array-element": [120, "str-val", false] + } + }, { + "foo": null + }] + }, + "lf13-any": { + "anyxml-array-a": { + "array-element": [{ + "foo": true + }, 10, { + "bar": false + }] + }, + "anyxml-array-b": { + "array-element": [1, 2, { + "array-element": [4, 5] + }, 7] + } + } + } +} diff --git a/yang/yang-data-codec-gson/src/test/resources/bug8927/json/scalar_array.json b/yang/yang-data-codec-gson/src/test/resources/bug8927/json/scalar_array.json new file mode 100644 index 0000000000..a2181aedcc --- /dev/null +++ b/yang/yang-data-codec-gson/src/test/resources/bug8927/json/scalar_array.json @@ -0,0 +1,10 @@ +{ + "bug8927:foo": { + "alarm-information": { + "alarm-summary": { + "active-alarm-count": "" + }, + "elmt": [1, 2, 3] + } + } +} diff --git a/yang/yang-data-codec-gson/src/test/resources/bug8927/json/scalar_array_with_other_elements.json b/yang/yang-data-codec-gson/src/test/resources/bug8927/json/scalar_array_with_other_elements.json new file mode 100644 index 0000000000..56a03fea65 --- /dev/null +++ b/yang/yang-data-codec-gson/src/test/resources/bug8927/json/scalar_array_with_other_elements.json @@ -0,0 +1,11 @@ +{ + "bug8927:foo": { + "alarm-information": { + "alarm-summary": { + "active-alarm-count": "" + }, + "elmt": [1, 2, 3], + "test": 123 + } + } +} diff --git a/yang/yang-data-codec-gson/src/test/resources/bug8927/xml/complex_array.xml b/yang/yang-data-codec-gson/src/test/resources/bug8927/xml/complex_array.xml new file mode 100644 index 0000000000..ce49a3f394 --- /dev/null +++ b/yang/yang-data-codec-gson/src/test/resources/bug8927/xml/complex_array.xml @@ -0,0 +1,31 @@ + + + + + + + 2017-08-02 19:03:44 UTC + + Minor + + 123 + + + 456 + + gnf-creation + License + + + + 2017-07-25 16:04:31 UTC + + Minor + Minor1 + VMHost RE 0 host application failed + VMHost RE 0 host ap + Chassis + + + + \ No newline at end of file diff --git a/yang/yang-data-codec-gson/src/test/resources/bug8927/xml/complex_array_with_other_elements.xml b/yang/yang-data-codec-gson/src/test/resources/bug8927/xml/complex_array_with_other_elements.xml new file mode 100644 index 0000000000..034c9fe3e8 --- /dev/null +++ b/yang/yang-data-codec-gson/src/test/resources/bug8927/xml/complex_array_with_other_elements.xml @@ -0,0 +1,155 @@ + + + + + + + + + + + 2017-08-02 19:03:44 UTC + + Minor + desc + gnf-creation + License + + + + 2017-07-25 16:04:31 UTC + + Minor + VMHost RE 0 host application failed + VMHost RE 0 host ap + Chassis + + + + 2017-07-25 16:04:31 UTC + + Major + PDM 0 incompatible with chassis type + PDM 0 incompatible + Chassis + + + + 2017-07-25 16:04:31 UTC + + Major + PDM 1 incompatible with chassis type + PDM 1 incompatible + Chassis + + + + 2017-07-25 16:04:31 UTC + + Major + PDM 2 incompatible with chassis type + PDM 2 incompatible + Chassis + + + + 2017-07-25 16:04:31 UTC + + Major + PDM 3 incompatible with chassis type + PDM 3 incompatible + Chassis + + + + 2017-07-25 16:04:31 UTC + + Major + No Input Feed Selected for PSM 1 + No Input Feed Selec + Chassis + + + + 2017-07-25 16:04:31 UTC + + Major + No Input Feed Selected for PSM 2 + No Input Feed Selec + Chassis + + + + 2017-07-25 16:04:31 UTC + + Major + No Input Feed Selected for PSM 3 + No Input Feed Selec + Chassis + + + + 2017-07-25 16:04:31 UTC + + Major + No Input Feed Selected for PSM 4 + No Input Feed Selec + Chassis + + + + 2017-07-25 16:04:31 UTC + + Major + No Input Feed Selected for PSM 10 + No Input Feed Selec + Chassis + + + + 2017-07-25 16:04:31 UTC + + Major + No Input Feed Selected for PSM 11 + No Input Feed Selec + Chassis + + + + 2017-07-25 16:04:31 UTC + + Major + No Input Feed Selected for PSM 12 + No Input Feed Selec + Chassis + + + + 2017-07-25 16:04:31 UTC + + Major + No Input Feed Selected for PSM 13 + No Input Feed Selec + Chassis + + + + 2017-07-25 16:04:31 UTC + + Minor + VMHost RE 1 host application failed + VMHost RE 1 host ap + Chassis + + + + 2017-07-25 16:04:31 UTC + + Minor + Check plane 1 Fabric Chip + Check plane 1 FCHIP + Chassis + + + + \ No newline at end of file diff --git a/yang/yang-data-codec-gson/src/test/resources/bug8927/xml/input4.xml b/yang/yang-data-codec-gson/src/test/resources/bug8927/xml/input4.xml new file mode 100644 index 0000000000..29c1432a19 --- /dev/null +++ b/yang/yang-data-codec-gson/src/test/resources/bug8927/xml/input4.xml @@ -0,0 +1,42 @@ + + + + true + + 120 + str-val + false + + + + + + + true + + 10 + + false + + 1 + 2 + 4 + 5 + 7 + + + + 10 + 11 + + + + 5.5 + + + b2-val + + + + + diff --git a/yang/yang-data-codec-gson/src/test/resources/bug8927/xml/scalar_array.xml b/yang/yang-data-codec-gson/src/test/resources/bug8927/xml/scalar_array.xml new file mode 100644 index 0000000000..be0a9b2f7f --- /dev/null +++ b/yang/yang-data-codec-gson/src/test/resources/bug8927/xml/scalar_array.xml @@ -0,0 +1,13 @@ + + + + + + + + 1 + 2 + 3 + + + \ No newline at end of file diff --git a/yang/yang-data-codec-gson/src/test/resources/bug8927/xml/scalar_array_with_other_elements.xml b/yang/yang-data-codec-gson/src/test/resources/bug8927/xml/scalar_array_with_other_elements.xml new file mode 100644 index 0000000000..08b29e2d5d --- /dev/null +++ b/yang/yang-data-codec-gson/src/test/resources/bug8927/xml/scalar_array_with_other_elements.xml @@ -0,0 +1,14 @@ + + + + + + + + 1 + 2 + 3 + 123 + + + \ No newline at end of file