[ONOS-6165] Demo 1: Integration - Json Serializer Encode failed
Fix the problem with encoder failed to process JSON's array child.
Change-Id: I9825836e03f1d69e05066fbbef91b8971b6a9a37
diff --git a/serializers/json/src/main/java/org/onosproject/yang/serializers/json/DefaultJsonBuilder.java b/serializers/json/src/main/java/org/onosproject/yang/serializers/json/DefaultJsonBuilder.java
index 4344df5..f93bfee 100644
--- a/serializers/json/src/main/java/org/onosproject/yang/serializers/json/DefaultJsonBuilder.java
+++ b/serializers/json/src/main/java/org/onosproject/yang/serializers/json/DefaultJsonBuilder.java
@@ -174,6 +174,11 @@
return node;
}
+ @Override
+ public void removeExtraTerminator() {
+ removeCommaIfExist();
+ }
+
private void appendField(String fieldName) {
if (fieldName != null && !fieldName.isEmpty()) {
treeString.append(QUOTE);
diff --git a/serializers/json/src/main/java/org/onosproject/yang/serializers/json/EncoderUtils.java b/serializers/json/src/main/java/org/onosproject/yang/serializers/json/EncoderUtils.java
index c0e7ccc..7127553 100644
--- a/serializers/json/src/main/java/org/onosproject/yang/serializers/json/EncoderUtils.java
+++ b/serializers/json/src/main/java/org/onosproject/yang/serializers/json/EncoderUtils.java
@@ -21,19 +21,15 @@
import org.onosproject.yang.model.InnerNode;
import org.onosproject.yang.model.NodeKey;
+import java.util.ArrayList;
+import java.util.HashMap;
import java.util.Iterator;
+import java.util.List;
import java.util.Map;
import static com.google.common.base.Preconditions.checkNotNull;
-import static org.onosproject.yang.model.DataNode.Type.MULTI_INSTANCE_LEAF_VALUE_NODE;
-import static org.onosproject.yang.model.DataNode.Type.MULTI_INSTANCE_NODE;
-import static org.onosproject.yang.model.DataNode.Type.SINGLE_INSTANCE_NODE;
-import static org.onosproject.yang.serializers.json.DataNodeSiblingPositionType.FIRST_INSTANCE;
-import static org.onosproject.yang.serializers.json.DataNodeSiblingPositionType.LAST_INSTANCE;
-import static org.onosproject.yang.serializers.json.DataNodeSiblingPositionType.MIDDLE_INSTANCE;
-import static org.onosproject.yang.serializers.json.DataNodeSiblingPositionType.NOT_MULTI_INSTANCE_NODE;
-import static org.onosproject.yang.serializers.json.DataNodeSiblingPositionType.SINGLE_INSTANCE_IN_MULTI_NODE;
-import static org.onosproject.yang.serializers.json.DataNodeSiblingPositionType.UNKNOWN_TYPE;
+import static org.onosproject.yang.model.DataNode.Type.*;
+import static org.onosproject.yang.serializers.json.DataNodeSiblingPositionType.*;
/**
* Utilities for converting Data Nodes into JSON format.
@@ -59,6 +55,7 @@
DataNodeSiblingPositionType siblingType = NOT_MULTI_INSTANCE_NODE;
walkDataNodeTree(treeNodeListener, dataNode, siblingType);
+ jsonBuilder.removeExtraTerminator();
ObjectNode resultData = jsonBuilder.getTreeNode();
return resultData;
}
@@ -102,8 +99,10 @@
DataNodeSiblingPositionType prevChildType = UNKNOWN_TYPE;
DataNodeSiblingPositionType currChildType = UNKNOWN_TYPE;
- Iterator it = childrenList.entrySet().iterator();
- DataNode currChild = ((Map.Entry<NodeKey, DataNode>) it.next()).getValue();
+ List<DataNode> sortedChildList = sortChildrenList(childrenList);
+ checkNotNull(sortedChildList, "sorted children list cannot be null");
+ Iterator<DataNode> it = sortedChildList.iterator();
+ DataNode currChild = it.next();
DataNode nextChild = null;
boolean lastChildNotProcessed = true;
while (lastChildNotProcessed) {
@@ -114,7 +113,7 @@
* this info the walker.
*/
if (it.hasNext()) {
- nextChild = ((Map.Entry<NodeKey, DataNode>) it.next()).getValue();
+ nextChild = it.next();
} else {
/*
* Current child is the last child.
@@ -143,22 +142,22 @@
DataNodeSiblingPositionType curChildSiblingType = UNKNOWN_TYPE;
switch (prevChildType) {
case UNKNOWN_TYPE:
+ case LAST_INSTANCE:
+ case NOT_MULTI_INSTANCE_NODE:
/*
- * If type of previous child is unknown, that means
- * the current child is the first sibling. If the next
- * child is null, then that means the current child is
- * the only child.
+ * If type of previous child is unknown or last instance,
+ * that means the current child is the first sibling. If
+ * the next child is null or has a different node name,
+ * then that means the current child is the only child.
*/
- if (nextChild == null) {
+ if (nextChild == null ||
+ !nextChild.key().schemaId().name().
+ equals(currChild.key().schemaId().name())) {
curChildSiblingType = SINGLE_INSTANCE_IN_MULTI_NODE;
} else {
curChildSiblingType = FIRST_INSTANCE;
}
break;
- case NOT_MULTI_INSTANCE_NODE:
- case LAST_INSTANCE:
- curChildSiblingType = FIRST_INSTANCE;
- break;
case FIRST_INSTANCE:
case MIDDLE_INSTANCE:
/*
@@ -177,7 +176,38 @@
default:
curChildSiblingType = UNKNOWN_TYPE;
}
-
return curChildSiblingType;
}
+
+ private static List<DataNode> sortChildrenList(
+ Map<NodeKey, DataNode> childrenList) {
+ if (childrenList == null || childrenList.isEmpty()) {
+ // the children list is either not yet created or empty.
+ return null;
+ }
+
+ List<DataNode> sortedList = new ArrayList<>();
+ Map<String, List<DataNode>> groupedBucket = new HashMap<>();
+
+ Iterator it = childrenList.entrySet().iterator();
+
+ while (it.hasNext()) {
+ DataNode dataNode = ((Map.Entry<NodeKey, DataNode>) it.next()).getValue();
+ String nodeName = dataNode.key().schemaId().name();
+ List<DataNode> group = groupedBucket.get(nodeName);
+ if (group == null) {
+ group = new ArrayList<>();
+ groupedBucket.put(nodeName, group);
+ }
+
+ group.add(dataNode);
+
+ }
+
+ for (Map.Entry<String, List<DataNode>> entry : groupedBucket.entrySet()) {
+ sortedList.addAll(entry.getValue());
+ }
+
+ return sortedList;
+ }
}
diff --git a/serializers/json/src/main/java/org/onosproject/yang/serializers/json/JsonBuilder.java b/serializers/json/src/main/java/org/onosproject/yang/serializers/json/JsonBuilder.java
index 98f162b..cb53cdd 100644
--- a/serializers/json/src/main/java/org/onosproject/yang/serializers/json/JsonBuilder.java
+++ b/serializers/json/src/main/java/org/onosproject/yang/serializers/json/JsonBuilder.java
@@ -87,4 +87,6 @@
* @return the final ObjectNode JSON tree after build operations
*/
ObjectNode getTreeNode();
+
+ void removeExtraTerminator();
}
diff --git a/serializers/json/src/test/java/org/onosproject/yang/serializers/json/JsonSerializerTest.java b/serializers/json/src/test/java/org/onosproject/yang/serializers/json/JsonSerializerTest.java
index 6d4b165..b2025bd 100644
--- a/serializers/json/src/test/java/org/onosproject/yang/serializers/json/JsonSerializerTest.java
+++ b/serializers/json/src/test/java/org/onosproject/yang/serializers/json/JsonSerializerTest.java
@@ -16,6 +16,8 @@
package org.onosproject.yang.serializers.json;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
import org.apache.commons.io.IOUtils;
import org.junit.BeforeClass;
import org.junit.Test;
@@ -25,10 +27,15 @@
import org.onosproject.yang.model.LeafNode;
import org.onosproject.yang.model.NodeKey;
import org.onosproject.yang.model.ResourceData;
+import org.onosproject.yang.model.ResourceId;
import org.onosproject.yang.model.SchemaId;
import org.onosproject.yang.runtime.CompositeData;
import org.onosproject.yang.runtime.CompositeStream;
+import org.onosproject.yang.runtime.DefaultCompositeData;
import org.onosproject.yang.runtime.DefaultCompositeStream;
+import org.onosproject.yang.runtime.DefaultResourceData;
+import org.onosproject.yang.runtime.DefaultRuntimeContext;
+import org.onosproject.yang.runtime.RuntimeContext;
import org.onosproject.yang.runtime.YangSerializer;
import org.onosproject.yang.runtime.YangSerializerContext;
@@ -137,6 +144,41 @@
assertEquals(WRONG_STRUCTURE, expectString, convertInputStreamToString(inputStream));
}
+ @Test
+ public void demo1Test() {
+ String path = "src/test/resources/test.json";
+ // decode
+ DefaultCompositeStream external =
+ new DefaultCompositeStream("demo1:device", parseInput(path));
+ CompositeData compositeData = jsonSerializer.decode(external, context);
+ ResourceData resourceData = compositeData.resourceData();
+ ResourceId rid = resourceData.resourceId();
+ DataNode rootNode = resourceData.dataNodes().get(0);
+
+ // encode
+ RuntimeContext.Builder runtimeContextBuilder = DefaultRuntimeContext.builder();
+ runtimeContextBuilder.setDataFormat("JSON");
+ DefaultResourceData.Builder resourceDataBuilder = DefaultResourceData.builder();
+ resourceDataBuilder.addDataNode(rootNode);
+ resourceDataBuilder.resourceId(rid);
+
+ ResourceData resourceDataOutput = resourceDataBuilder.build();
+ DefaultCompositeData.Builder compositeDataBuilder = DefaultCompositeData.builder();
+ compositeDataBuilder.resourceData(resourceDataOutput);
+ CompositeData compositeData1 = compositeDataBuilder.build();
+ // CompositeData --- YangRuntimeService ---> CompositeStream.
+ CompositeStream compositeStreamOutPut = jsonSerializer.encode(compositeData1,
+ context);
+ InputStream inputStreamOutput = compositeStreamOutPut.resourceData();
+ ObjectNode rootNodeOutput;
+ ObjectMapper mapper = new ObjectMapper();
+ try {
+ rootNodeOutput = (ObjectNode) mapper.readTree(inputStreamOutput);
+ } catch (IOException e) {
+ System.out.println("inputstream failed to parse");
+ }
+ }
+
/**
* Reads JSON contents from file path and returns input stream.
*
diff --git a/serializers/json/src/test/resources/demo1.json b/serializers/json/src/test/resources/demo1.json
new file mode 100644
index 0000000..77714fd
--- /dev/null
+++ b/serializers/json/src/test/resources/demo1.json
@@ -0,0 +1,35 @@
+{
+
+ "device": [
+ {
+ "deviceid": "string1-deviceid",
+ "Customs-supervisor": "string2",
+ "Merchandiser-supervisor": "string3",
+ "Warehouse-supervisor": [
+ "string4.1",
+ "string4.2",
+ "string4.3"
+ ],
+ "Trading-supervisor": "string4",
+ "Employee-id": [
+ "string4.1",
+ "string4.2",
+ "string4.3"
+ ],
+ "Material-supervisor": [
+ {
+ "name": "string5",
+ "departmentId": "string6"
+ }
+ ],
+ "Purchasing-supervisor": {
+ "purchasing-specialist": "string7",
+ "support": [
+ "string8.1",
+ "string8.2",
+ "string8.3"
+ ]
+ }
+ }
+ ]
+}
diff --git a/serializers/json/src/test/resources/demo1.yang b/serializers/json/src/test/resources/demo1.yang
new file mode 100644
index 0000000..feeccd6
--- /dev/null
+++ b/serializers/json/src/test/resources/demo1.yang
@@ -0,0 +1,63 @@
+module demo1 {
+ yang-version 1;
+ namespace "namespace1";
+ prefix "demo1";
+ revision "2013-07-15";
+ container device {
+ list device {
+ key deviceid;
+ leaf deviceid {
+ type string;
+ }
+ leaf Customs-supervisor {
+ type string;
+ description "name of the customs-supervisor.";
+ }
+
+ leaf Merchandiser-supervisor {
+ type string;
+ description "name of merchandiser-supervisor";
+ }
+
+ list Material-supervisor {
+ key "name";
+ leaf name {
+ type string;
+ description "name of logistics-supervisor";
+ }
+
+ leaf departmentId {
+ type string;
+ description "name of department";
+ }
+ }
+
+ container Purchasing-supervisor {
+ leaf purchasing-specialist {
+ type string;
+ description "name of the purchasing-specialist person";
+ }
+
+ leaf-list support {
+ type string;
+ description "name of the support person";
+ }
+ }
+
+ leaf-list Warehouse-supervisor {
+ type string;
+ description "name of the warehouse-supervisor's";
+ }
+
+ leaf Trading-supervisor {
+ type string;
+ description "name of the trading-supervisor";
+ }
+
+ leaf-list Employee-id {
+ type string;
+ description "list of the employee id";
+ }
+ }
+ }
+}
diff --git a/serializers/json/src/test/resources/test.json b/serializers/json/src/test/resources/test.json
new file mode 100644
index 0000000..0235997
--- /dev/null
+++ b/serializers/json/src/test/resources/test.json
@@ -0,0 +1,34 @@
+{
+ "device": [
+ {
+ "deviceid": "string1-deviceid",
+ "Customs-supervisor": "string2",
+ "Merchandiser-supervisor": "string3",
+ "Warehouse-supervisor": [
+ "string41",
+ "string42",
+ "string43"
+ ],
+ "Trading-supervisor": "string4",
+ "Employee-id": [
+ "string41",
+ "string42",
+ "string43"
+ ],
+ "Material-supervisor": [
+ {
+ "name": "string5",
+ "departmentId": "string6"
+ }
+ ],
+ "Purchasing-supervisor": {
+ "purchasing-specialist": "string7",
+ "support": [
+ "string81",
+ "string82",
+ "string83"
+ ]
+ }
+ }
+ ]
+}
\ No newline at end of file