Merge "JSON serializer implementation"
diff --git a/pom.xml b/pom.xml
index 9483615..91c9de8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -37,6 +37,7 @@
         <module>compiler</module>
         <module>model</module>
         <module>runtime</module>
+        <module>serializers</module>
     </modules>
 
     <!-- FIXME this can be removed if/when buck-api is released -->
diff --git a/serializers/json/pom.xml b/serializers/json/pom.xml
new file mode 100644
index 0000000..7a9fc74
--- /dev/null
+++ b/serializers/json/pom.xml
@@ -0,0 +1,107 @@
+<!--
+  ~ Copyright 2017-present Open Networking Laboratory
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.onosproject</groupId>
+        <artifactId>onos-yang-serializers</artifactId>
+        <version>1.12-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>onos-yang-serializers-json</artifactId>
+    <packaging>jar</packaging>
+
+    <dependencies>
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+            <version>2.4</version>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+            <version>1.7.21</version>
+        </dependency>
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-yang-model</artifactId>
+            <version>1.12-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-yang-runtime</artifactId>
+            <version>1.12-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-databind</artifactId>
+            <version>2.8.6</version>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-annotations</artifactId>
+            <version>2.8.6</version>
+        </dependency>
+        <!-- TODO: remove
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-yang-compiler-api</artifactId>
+            <version>1.12-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-yang-compiler-datamodel</artifactId>
+            <version>1.12-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-yang-compiler-plugin-utils</artifactId>
+            <version>1.12-SNAPSHOT</version>
+        </dependency>
+        -->
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <version>RELEASE</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jar-plugin</artifactId>
+                <version>3.0.2</version>
+                <configuration>
+                    <skipIfEmpty>true</skipIfEmpty>
+                </configuration>
+                <executions>
+                    <execution>
+                        <id>default</id>
+                        <goals>
+                            <goal>test-jar</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/serializers/json/src/main/java/org/onosproject/yang/serializers/json/DataNodeJsonVisitor.java b/serializers/json/src/main/java/org/onosproject/yang/serializers/json/DataNodeJsonVisitor.java
new file mode 100644
index 0000000..c4fcaf6
--- /dev/null
+++ b/serializers/json/src/main/java/org/onosproject/yang/serializers/json/DataNodeJsonVisitor.java
@@ -0,0 +1,112 @@
+/*
+ *  Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.yang.serializers.json;
+
+import com.fasterxml.jackson.databind.node.JsonNodeType;
+import org.onosproject.yang.model.DataNode;
+import org.onosproject.yang.model.LeafNode;
+import org.onosproject.yang.model.SchemaId;
+
+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.SINGLE_INSTANCE_IN_MULTI_NODE;
+
+public class DataNodeJsonVisitor implements DataNodeVisitor {
+    private static final String COLON = ":";
+
+    private JsonBuilder jsonBuilder;
+
+    public DataNodeJsonVisitor(JsonBuilder jsonBuilder) {
+        this.jsonBuilder = jsonBuilder;
+    }
+
+    @Override
+    public void enterDataNode(DataNode dataNode,
+                              DataNodeSiblingPositionType siblingType) {
+        String nodeName = getNodeNameWithNamespace(dataNode.key().schemaId());
+        switch (dataNode.type()) {
+            case SINGLE_INSTANCE_NODE:
+                jsonBuilder.addNodeTopHalf(nodeName, JsonNodeType.OBJECT);
+                break;
+            case MULTI_INSTANCE_NODE:
+                if (siblingType == FIRST_INSTANCE ||
+                        siblingType == SINGLE_INSTANCE_IN_MULTI_NODE) {
+                    jsonBuilder.addNodeTopHalf(nodeName, JsonNodeType.ARRAY);
+                }
+                jsonBuilder.addNodeTopHalf("", JsonNodeType.OBJECT);
+                break;
+            case SINGLE_INSTANCE_LEAF_VALUE_NODE:
+                jsonBuilder.addNodeWithValueTopHalf(nodeName,
+                                                    ((LeafNode) dataNode).value().toString());
+                break;
+            case MULTI_INSTANCE_LEAF_VALUE_NODE:
+                if (siblingType == FIRST_INSTANCE ||
+                        siblingType == SINGLE_INSTANCE_IN_MULTI_NODE) {
+                    jsonBuilder.addNodeTopHalf(nodeName, JsonNodeType.ARRAY);
+                }
+                jsonBuilder.addValueToLeafListNode(((LeafNode) dataNode).value().toString());
+                break;
+            default:
+                break;
+        }
+    }
+
+    private String getNodeNameWithNamespace(SchemaId schemaId) {
+        String nodeName = schemaId.name();
+        String nameSpace = schemaId.namespace();
+
+        StringBuilder builder = new StringBuilder();
+
+        builder.append(nodeName);
+
+        if (nameSpace != null) {
+            builder.append(COLON);
+            builder.append(nameSpace);
+        }
+
+        return builder.toString();
+    }
+
+    @Override
+    public void exitDataNode(DataNode dataNode,
+                             DataNodeSiblingPositionType siblingType) {
+        switch (dataNode.type()) {
+            case SINGLE_INSTANCE_NODE:
+                jsonBuilder.addNodeBottomHalf(JsonNodeType.OBJECT);
+                break;
+            case MULTI_INSTANCE_NODE:
+                jsonBuilder.addNodeBottomHalf(JsonNodeType.OBJECT);
+                if (siblingType == LAST_INSTANCE ||
+                        siblingType == SINGLE_INSTANCE_IN_MULTI_NODE) {
+                    jsonBuilder.addNodeBottomHalf(JsonNodeType.ARRAY);
+                }
+                break;
+            case SINGLE_INSTANCE_LEAF_VALUE_NODE:
+                jsonBuilder.addNodeBottomHalf(JsonNodeType.STRING);
+                break;
+            case MULTI_INSTANCE_LEAF_VALUE_NODE:
+                jsonBuilder.addNodeBottomHalf(JsonNodeType.STRING);
+                if (siblingType == LAST_INSTANCE ||
+                        siblingType == SINGLE_INSTANCE_IN_MULTI_NODE) {
+                    jsonBuilder.addNodeBottomHalf(JsonNodeType.ARRAY);
+                }
+                break;
+            default:
+                break;
+        }
+    }
+}
diff --git a/serializers/json/src/main/java/org/onosproject/yang/serializers/json/DataNodeSiblingPositionType.java b/serializers/json/src/main/java/org/onosproject/yang/serializers/json/DataNodeSiblingPositionType.java
new file mode 100644
index 0000000..f88aeeb
--- /dev/null
+++ b/serializers/json/src/main/java/org/onosproject/yang/serializers/json/DataNodeSiblingPositionType.java
@@ -0,0 +1,53 @@
+/*
+ *  Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.yang.serializers.json;
+
+/**
+ * Denotation of the relative position of a multi-instance data node
+ * relative to its siblings.
+ */
+public enum DataNodeSiblingPositionType {
+    /**
+     * Denotes that the given node is not a multi-instance or leaf-list node.
+     */
+    NOT_MULTI_INSTANCE_NODE,
+
+    /**
+     * Denotes that the node is the first instance in the sibling list.
+     */
+    FIRST_INSTANCE,
+
+    /**
+     * Denotes that the node is the last instance in the sibling list.
+     */
+    LAST_INSTANCE,
+
+    /**
+     * Denotes that the node is one of the middle instances.
+     */
+    MIDDLE_INSTANCE,
+
+    /**
+     * Denotes that the given node is the only instance in the multi-instance
+     * data node.
+     */
+    SINGLE_INSTANCE_IN_MULTI_NODE,
+    /**
+     * Used for error case or as uninitialized data.
+     */
+    UNKNOWN_TYPE,
+}
diff --git a/serializers/json/src/main/java/org/onosproject/yang/serializers/json/DataNodeVisitor.java b/serializers/json/src/main/java/org/onosproject/yang/serializers/json/DataNodeVisitor.java
new file mode 100644
index 0000000..1d4f59b
--- /dev/null
+++ b/serializers/json/src/main/java/org/onosproject/yang/serializers/json/DataNodeVisitor.java
@@ -0,0 +1,48 @@
+/*
+ *  Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.yang.serializers.json;
+
+import org.onosproject.yang.model.DataNode;
+
+/**
+ * Representation of the visitor to data nodes during the
+ * data tree traversal.
+ */
+public interface DataNodeVisitor {
+    /**
+     * Enters the data node by the visitor. The function is called by
+     * the walker of the data tree when it enters the given data node.
+     * The visitor uses this function to process the data of this node.
+     *
+     * @param dataNode    data node which the tree walker visits
+     * @param siblingType indicates whether the data node the the first
+     *                    or last sibling instance of a multi-instance node
+     */
+    void enterDataNode(DataNode dataNode, DataNodeSiblingPositionType siblingType);
+
+    /**
+     * Exits the data node by the visitor. The function is called by
+     * the walker of the data tree when it's about to leave the given
+     * data node. The visitor uses this function to run cleanup work
+     * of the data processing.
+     *
+     * @param dataNode    data node which the tree walker finishes the visit
+     * @param siblingType indicates whether the data node the the first
+     *                    or last sibling instance of a multi-instance node
+     */
+    void exitDataNode(DataNode dataNode, DataNodeSiblingPositionType siblingType);
+}
diff --git a/serializers/json/src/main/java/org/onosproject/yang/serializers/json/DecoderUtils.java b/serializers/json/src/main/java/org/onosproject/yang/serializers/json/DecoderUtils.java
new file mode 100644
index 0000000..753b699
--- /dev/null
+++ b/serializers/json/src/main/java/org/onosproject/yang/serializers/json/DecoderUtils.java
@@ -0,0 +1,281 @@
+/*
+ *  Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.yang.serializers.json;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.common.base.Splitter;
+import com.google.common.collect.Lists;
+import org.onosproject.yang.model.DataNode;
+import org.onosproject.yang.model.ResourceId;
+import org.onosproject.yang.runtime.YangSerializerContext;
+import org.onosproject.yang.runtime.helperutils.SerializerHelper;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.util.ArrayList;
+import java.util.List;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+
+/**
+ * Utilities for parsing URI and JSON strings.
+ */
+public final class DecoderUtils {
+    private static final Splitter SLASH_SPLITTER = Splitter.on('/');
+    private static final Splitter COMMA_SPLITTER = Splitter.on(',');
+    private static final String EQUAL = "=";
+    private static final String COMMA = ",";
+    private static final String COLON = ":";
+    private static final String SLASH = "/";
+    private static final String URI_ENCODING_CHAR_SET = "ISO-8859-1";
+    private static final String ERROR_LIST_MSG = "List/Leaf-list node should be " +
+            "in format \"nodeName=key\"or \"nodeName=instance-value\"";
+
+
+    // no instantiation
+    private DecoderUtils() {
+    }
+
+    /**
+     * Converts a URI string to resource identifier.
+     *
+     * @param uriString given URI
+     * @param context   YANG schema context information
+     * @return resource ID
+     */
+    public static ResourceId convertUriToRid(String uriString,
+                                             YangSerializerContext context) {
+        if (uriString == null || uriString.isEmpty()) {
+            return null;
+        }
+
+        List<String> paths = urlPathArgsDecode(SLASH_SPLITTER.split(uriString));
+
+        if (!paths.isEmpty()) {
+            ResourceId.Builder ridBuilder =
+                    SerializerHelper.initializeResourceId(context);
+            processPathSegments(paths, ridBuilder);
+            return ridBuilder.build();
+        }
+
+        return null;
+    }
+
+    /**
+     * Converts JSON data to a data node. This method should be used when
+     * the URI corresponding to the JSON body is null (Thus the caller can
+     * only provide a serializer context rather than a resource ID).
+     *
+     * @param rootNode given JSON data
+     * @param context  YANG serializer context corresponding
+     *                 to the target data node
+     * @return data node
+     */
+    public static DataNode convertJsonToDataNode(ObjectNode rootNode,
+                                                 YangSerializerContext context) {
+        if (rootNode == null || context == null) {
+            return null;
+        }
+
+        DataNode.Builder dataNodeBuilder = SerializerHelper.
+                initializeDataNode(context);
+
+        JsonWalker jsonWalker = new DefaultJsonWalker(dataNodeBuilder);
+        jsonWalker.walkJsonNode(null, rootNode);
+
+        return dataNodeBuilder.build();
+    }
+
+    /**
+     * Converts JSON data to a data node. This method should be used when
+     * the JSON body has a valid URI associated with it (so that the caller
+     * can convert the URI to a resource ID).
+     *
+     * @param rootNode   given JSON data
+     * @param ridBuilder resource ID builder corresponding
+     *                   to the target data node
+     * @return data node
+     */
+    public static DataNode convertJsonToDataNode(ObjectNode rootNode,
+                                                 ResourceId.Builder ridBuilder) {
+        if (rootNode == null || ridBuilder == null) {
+            return null;
+        }
+
+        DataNode.Builder dataNodeBuilder = SerializerHelper.
+                initializeDataNode(ridBuilder);
+
+        JsonWalker jsonWalker = new DefaultJsonWalker(dataNodeBuilder);
+        jsonWalker.walkJsonNode(null, rootNode);
+
+        return dataNodeBuilder.build();
+    }
+
+    /**
+     * Converts a list of path from the original format to ISO-8859-1 code.
+     *
+     * @param paths the original paths
+     * @return list of decoded paths
+     */
+    public static List<String> urlPathArgsDecode(Iterable<String> paths) {
+        try {
+            List<String> decodedPathArgs = new ArrayList<>();
+            for (String pathArg : paths) {
+                String decode = URLDecoder.decode(pathArg,
+                                                  URI_ENCODING_CHAR_SET);
+                decodedPathArgs.add(decode);
+            }
+            return decodedPathArgs;
+        } catch (UnsupportedEncodingException e) {
+            throw new SerializerException("Invalid URL path arg '" +
+                                                  paths + "': ", e);
+        }
+    }
+
+    private static ResourceId.Builder processPathSegments(List<String> paths,
+                                                          ResourceId.Builder builder) {
+        if (paths.isEmpty()) {
+            return builder;
+        }
+
+        boolean isLastSegment = paths.size() == 1;
+
+        String segment = paths.iterator().next();
+        processSinglePathSegment(segment, builder);
+
+        if (isLastSegment) {
+            // We have hit the base case of recursion.
+            return builder;
+        }
+
+        /*
+         * Chop off the first segment, and recursively process the rest
+         * of the path segments.
+         */
+        List<String> remainPaths = paths.subList(1, paths.size());
+        processPathSegments(remainPaths, builder);
+
+        return builder;
+    }
+
+    private static void processSinglePathSegment(String pathSegment,
+                                                 ResourceId.Builder builder) {
+        if (pathSegment.contains(COLON)) {
+            processPathSegmentWithNamespace(pathSegment, builder);
+        } else {
+            processPathSegmentWithoutNamespace(pathSegment, builder);
+        }
+    }
+
+    private static void processPathSegmentWithNamespace(String pathSegment,
+                                                        ResourceId.Builder builder) {
+
+        String nodeName = getLatterSegment(pathSegment, COLON);
+        String namespace = getPreSegment(pathSegment, COLON);
+        addNodeNameToRid(nodeName, namespace, builder);
+    }
+
+    private static void processPathSegmentWithoutNamespace(String nodeName,
+                                                           ResourceId.Builder builder) {
+        addNodeNameToRid(nodeName, null, builder);
+    }
+
+    private static void addNodeNameToRid(String nodeName,
+                                         String namespace,
+                                         ResourceId.Builder builder) {
+        if (nodeName.contains(EQUAL)) {
+            addListOrLeafList(nodeName, namespace, builder);
+        } else {
+            addLeaf(nodeName, namespace, builder);
+        }
+    }
+
+    private static void addListOrLeafList(String path,
+                                          String namespace,
+                                          ResourceId.Builder builder) {
+        String nodeName = getPreSegment(path, EQUAL);
+        String keyStr = getLatterSegment(path, EQUAL);
+        if (keyStr == null) {
+            throw new SerializerException(ERROR_LIST_MSG);
+        }
+
+        if (keyStr.contains(COMMA)) {
+            List<String> keys = Lists.
+                    newArrayList(COMMA_SPLITTER.split(keyStr));
+            SerializerHelper.addToResourceId(builder, nodeName, namespace, keys);
+        } else {
+            SerializerHelper.addToResourceId(builder, nodeName, namespace,
+                                             Lists.newArrayList(keyStr));
+        }
+    }
+
+    private static void addLeaf(String nodeName,
+                                String namespace,
+                                ResourceId.Builder builder) {
+        checkNotNull(nodeName);
+        SerializerHelper.addToResourceId(builder, nodeName, namespace, "");
+    }
+
+    /**
+     * Returns the previous segment of a path which is separated by a split char.
+     * For example:
+     * <pre>
+     * "foo:bar", ":"   -->  "foo"
+     * </pre>
+     *
+     * @param path      the original path string
+     * @param splitChar char used to split the path
+     * @return the previous segment of the path
+     */
+    private static String getPreSegment(String path, String splitChar) {
+        int idx = path.indexOf(splitChar);
+        if (idx == -1) {
+            return null;
+        }
+
+        if (path.indexOf(splitChar, idx + 1) != -1) {
+            return null;
+        }
+
+        return path.substring(0, idx);
+    }
+
+    /**
+     * Returns the latter segment of a path which is separated by a split char.
+     * For example:
+     * <pre>
+     * "foo:bar", ":"   -->  "bar"
+     * </pre>
+     *
+     * @param path      the original path string
+     * @param splitChar char used to split the path
+     * @return the latter segment of the path
+     */
+    private static String getLatterSegment(String path, String splitChar) {
+        int idx = path.indexOf(splitChar);
+        if (idx == -1) {
+            return path;
+        }
+
+        if (path.indexOf(splitChar, idx + 1) != -1) {
+            return null;
+        }
+
+        return path.substring(idx + 1);
+    }
+}
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
new file mode 100644
index 0000000..4344df5
--- /dev/null
+++ b/serializers/json/src/main/java/org/onosproject/yang/serializers/json/DefaultJsonBuilder.java
@@ -0,0 +1,191 @@
+/*
+ *  Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.yang.serializers.json;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.JsonNodeType;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.util.Set;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Strings.isNullOrEmpty;
+
+/**
+ * Represents implementation of interfaces to build and obtain JSON data tree.
+ */
+public class DefaultJsonBuilder implements JsonBuilder {
+    private Logger log = LoggerFactory.getLogger(getClass());
+    private StringBuilder treeString;
+    private static final String LEFT_BRACE = "{";
+    private static final String RIGHT_BRACE = "}";
+    private static final String LEFT_BRACKET = "[";
+    private static final String RIGHT_BRACKET = "]";
+    private static final String COMMA = ",";
+    private static final String COLON = ":";
+    private static final String QUOTE = "\"";
+
+
+    public DefaultJsonBuilder(String rootName) {
+        checkNotNull(rootName);
+        this.treeString = new StringBuilder(rootName);
+    }
+
+    public DefaultJsonBuilder() {
+        this.treeString = new StringBuilder();
+    }
+
+    @Override
+    public void addNodeTopHalf(String nodeName, JsonNodeType nodeType) {
+        appendField(nodeName);
+
+        switch (nodeType) {
+            case OBJECT:
+                treeString.append(LEFT_BRACE);
+                break;
+            case ARRAY:
+                treeString.append(LEFT_BRACKET);
+                break;
+            default:
+                log.error("Unknown support type {} for this method.", nodeType);
+        }
+
+    }
+
+    @Override
+    public void addNodeWithValueTopHalf(String nodeName, String value) {
+        if (isNullOrEmpty(nodeName)) {
+            return;
+        }
+        appendField(nodeName);
+        if (value.isEmpty()) {
+            return;
+        }
+        treeString.append(QUOTE);
+        treeString.append(value);
+        treeString.append(QUOTE);
+        treeString.append(COMMA);
+    }
+
+    @Override
+    public void addNodeWithSetTopHalf(String nodeName, Set<String> sets) {
+        if (isNullOrEmpty(nodeName)) {
+            return;
+        }
+        appendField(nodeName);
+        treeString.append(LEFT_BRACKET);
+        for (String el : sets) {
+            treeString.append(QUOTE);
+            treeString.append(el);
+            treeString.append(QUOTE);
+            treeString.append(COMMA);
+        }
+    }
+
+    @Override
+    public void addValueToLeafListNode(String value) {
+        if (isNullOrEmpty(value)) {
+            return;
+        }
+
+        treeString.append(QUOTE);
+        treeString.append(value);
+        treeString.append(QUOTE);
+        treeString.append(COMMA);
+    }
+
+    @Override
+    public void addNodeBottomHalf(JsonNodeType nodeType) {
+
+        switch (nodeType) {
+            case OBJECT:
+                removeCommaIfExist();
+                treeString.append(RIGHT_BRACE);
+                treeString.append(COMMA);
+                break;
+            case ARRAY:
+                removeCommaIfExist();
+                treeString.append(RIGHT_BRACKET);
+                treeString.append(COMMA);
+                break;
+            case BINARY:
+            case BOOLEAN:
+            case MISSING:
+            case NULL:
+            case NUMBER:
+            case POJO:
+            case STRING:
+                break;
+            default:
+                log.info("Unknown json node type {}", nodeType);
+        }
+    }
+
+    @Override
+    public String getTreeString() {
+        removeCommaIfExist();
+        removeFirstFieldNameIfExist();
+        return treeString.toString();
+    }
+
+    private void removeFirstFieldNameIfExist() {
+        int index1 = treeString.indexOf(LEFT_BRACE);
+        int index2 = treeString.indexOf(LEFT_BRACKET);
+        if (index1 < 0 && index2 < 0) {
+            return;
+        }
+        int index;
+
+        if (index1 < 0) {
+            index = index2;
+        } else if (index2 < 0) {
+            index = index1;
+        } else {
+            index = (index1 < index2) ? index1 : index2;
+        }
+        treeString.delete(0, index);
+    }
+
+    @Override
+    public ObjectNode getTreeNode() {
+        ObjectNode node = null;
+        try {
+            node = (ObjectNode) (new ObjectMapper()).readTree(getTreeString());
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        return node;
+    }
+
+    private void appendField(String fieldName) {
+        if (fieldName != null && !fieldName.isEmpty()) {
+            treeString.append(QUOTE);
+            treeString.append(fieldName);
+            treeString.append(QUOTE);
+            treeString.append(COLON);
+        }
+    }
+
+    private void removeCommaIfExist() {
+        if (treeString.charAt(treeString.length() - 1) == COMMA.charAt(0)) {
+            treeString.deleteCharAt(treeString.length() - 1);
+        }
+    }
+}
diff --git a/serializers/json/src/main/java/org/onosproject/yang/serializers/json/DefaultJsonWalker.java b/serializers/json/src/main/java/org/onosproject/yang/serializers/json/DefaultJsonWalker.java
new file mode 100644
index 0000000..a4edcab
--- /dev/null
+++ b/serializers/json/src/main/java/org/onosproject/yang/serializers/json/DefaultJsonWalker.java
@@ -0,0 +1,231 @@
+/*
+ *  Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.yang.serializers.json;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.JsonNodeType;
+import org.onosproject.yang.model.DataNode;
+import org.onosproject.yang.runtime.helperutils.SerializerHelper;
+
+import java.util.Iterator;
+import java.util.Map;
+
+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_LEAF_VALUE_NODE;
+import static org.onosproject.yang.model.DataNode.Type.SINGLE_INSTANCE_NODE;
+
+/**
+ * Represents implementation of JSON walk, which walks the JSON object node.
+ */
+public class DefaultJsonWalker implements JsonWalker {
+    private static final String COLON = ":";
+
+    private DataNode.Builder dataNodeBuilder;
+
+    public DefaultJsonWalker(DataNode.Builder dataNodeBuilder) {
+        this.dataNodeBuilder = dataNodeBuilder;
+    }
+
+    @Override
+    public void walkJsonNode(String fieldName, JsonNode jsonNode) {
+
+        JsonNodeType nodeType = jsonNode.getNodeType();
+
+        if (!jsonNode.isContainerNode()) {
+            //the node has no children, so add it as leaf node to the data tree.
+            addLeafNodeToDataTree(fieldName, jsonNode);
+            SerializerHelper.exitDataNode(dataNodeBuilder);
+            return;
+        }
+
+        /*
+         * For an array node, there are 2 cases:
+         *
+         * 1. It is a leaflist node
+         * 2. It is a multi-instance node.
+         */
+        if (jsonNode.isArray()) {
+            // Let's deal with the leaflist case first.
+            if (isJsonNodeLeafList((ArrayNode) jsonNode)) {
+                addLeafListNodeToDataTree(fieldName, (ArrayNode) jsonNode);
+                SerializerHelper.exitDataNode(dataNodeBuilder);
+                return;
+            }
+
+            /*
+             * This is a multi-instance node. Each element in the
+             * array is an instance of multi-instance node in the data tree.
+             */
+            Iterator<JsonNode> elements = jsonNode.elements();
+            while (elements.hasNext()) {
+                JsonNode element = elements.next();
+                addMultiInstanceNodeToDataTree(fieldName);
+
+                // Recursively build the subtree of element
+                walkJsonNode(null, element);
+
+                // We are done with this array element
+                SerializerHelper.exitDataNode(dataNodeBuilder);
+            }
+
+            // We are done with this array node.
+            SerializerHelper.exitDataNode(dataNodeBuilder);
+            return;
+        }
+
+        /*
+         * If we reach here, then this node is an object node. An object node
+         * has a set of name-value pairs. ("value" can be object node.)
+         */
+        if (fieldName != null) {
+            // If fieldName is null, then the caller does not want to
+            // add the node into the data tree. Rather, it just want to add
+            // the children nodes to the current node of the data tree.
+            addSingleInstanceNodeToDataTree(fieldName);
+        }
+
+        Iterator<Map.Entry<String, JsonNode>> fields = jsonNode.fields();
+        while (fields.hasNext()) {
+            //get the children entry of the node
+            Map.Entry<String, JsonNode> currentChild = fields.next();
+            String key = currentChild.getKey();
+            JsonNode value = currentChild.getValue();
+            walkJsonNode(key, value);
+            // NOTE: Don't move up, because walkJsonNode will do so.
+            // SerializerHelper.exitDataNode(dataNodeBuilder);
+        }
+
+        if (fieldName != null) {
+            // move up since we finish creating a container node.
+            SerializerHelper.exitDataNode(dataNodeBuilder);
+        }
+    }
+
+    private void addDataNode(String fieldName, String value, DataNode.Type nodeType) {
+        String nodeName = getLatterSegment(fieldName, COLON);
+        String namespace = getPreSegment(fieldName, COLON);
+        SerializerHelper.addDataNode(dataNodeBuilder,
+                                     nodeName,
+                                     namespace,
+                                     value,
+                                     nodeType);
+    }
+
+    private void addNoneLeafDataNode(String fieldName, DataNode.Type nodeType) {
+        addDataNode(fieldName, null, nodeType);
+    }
+
+    private void addLeafDataNode(String fieldName, String value, DataNode.Type nodeType) {
+        addDataNode(fieldName, value, nodeType);
+    }
+
+    private void addSingleInstanceNodeToDataTree(String fieldName) {
+        addNoneLeafDataNode(fieldName, SINGLE_INSTANCE_NODE);
+    }
+
+    private void addMultiInstanceNodeToDataTree(String fieldName) {
+        addNoneLeafDataNode(fieldName, MULTI_INSTANCE_NODE);
+    }
+
+    private void addLeafNodeToDataTree(String fieldName, JsonNode jsonNode) {
+        String value = jsonNode.asText();
+        addLeafDataNode(fieldName, value,
+                        SINGLE_INSTANCE_LEAF_VALUE_NODE);
+    }
+
+    private void addLeafListNodeToDataTree(String fieldName,
+                                           ArrayNode jsonNode) {
+        Iterator<JsonNode> elements = jsonNode.elements();
+        while (elements.hasNext()) {
+            JsonNode element = elements.next();
+            JsonNodeType eleType = element.getNodeType();
+
+            if (eleType == JsonNodeType.STRING || eleType == JsonNodeType.NUMBER) {
+                addLeafDataNode(fieldName, element.asText(),
+                                MULTI_INSTANCE_LEAF_VALUE_NODE);
+                SerializerHelper.exitDataNode(dataNodeBuilder);
+            }
+        }
+    }
+
+    private boolean isJsonNodeLeafList(ArrayNode jsonNode) {
+        if (!jsonNode.isArray()) {
+            return false;
+        }
+
+        Iterator<JsonNode> elements = jsonNode.elements();
+        while (elements.hasNext()) {
+            JsonNode element = elements.next();
+            JsonNodeType eleType = element.getNodeType();
+            if (eleType != JsonNodeType.STRING && eleType != JsonNodeType.NUMBER) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * Returns the previous segment of a path which is separated by a split char.
+     * For example:
+     * <pre>
+     * "foo:bar", ":"   -->  "foo"
+     * </pre>
+     *
+     * @param path      the original path string
+     * @param splitChar char used to split the path
+     * @return the previous segment of the path
+     */
+    private String getPreSegment(String path, String splitChar) {
+        int idx = path.indexOf(splitChar);
+        if (idx == -1) {
+            return null;
+        }
+
+        if (path.indexOf(splitChar, idx + 1) != -1) {
+            return null;
+        }
+
+        return path.substring(0, idx);
+    }
+
+    /**
+     * Returns the latter segment of a path which is separated by a split char.
+     * For example:
+     * <pre>
+     * "foo:bar", ":"   -->  "bar"
+     * </pre>
+     *
+     * @param path      the original path string
+     * @param splitChar char used to split the path
+     * @return the latter segment of the path
+     */
+    private String getLatterSegment(String path, String splitChar) {
+        int idx = path.indexOf(splitChar);
+        if (idx == -1) {
+            return path;
+        }
+
+        if (path.indexOf(splitChar, idx + 1) != -1) {
+            return null;
+        }
+
+        return path.substring(idx + 1);
+    }
+}
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
new file mode 100644
index 0000000..00022e5
--- /dev/null
+++ b/serializers/json/src/main/java/org/onosproject/yang/serializers/json/EncoderUtils.java
@@ -0,0 +1,275 @@
+/*
+ *  Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.yang.serializers.json;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.common.base.Splitter;
+import org.onosproject.yang.model.DataNode;
+import org.onosproject.yang.model.InnerNode;
+import org.onosproject.yang.model.KeyLeaf;
+import org.onosproject.yang.model.LeafListKey;
+import org.onosproject.yang.model.ListKey;
+import org.onosproject.yang.model.NodeKey;
+import org.onosproject.yang.model.ResourceId;
+
+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;
+
+/**
+ * Utilities for converting Data Nodes into JSON format.
+ */
+public final class EncoderUtils {
+    private static final Splitter SLASH_SPLITTER = Splitter.on('/');
+    private static final Splitter COMMA_SPLITTER = Splitter.on(',');
+    private static final String EQUAL = "=";
+    private static final String COMMA = ",";
+    private static final String COLON = ":";
+    private static final String SLASH = "/";
+
+    // no instantiation
+    private EncoderUtils() {
+    }
+
+    /**
+     * Converts a resource identifier to URI string.
+     *
+     * @param rid resource identifier
+     * @return URI
+     */
+    public static String convertRidToUri(ResourceId rid) {
+        if (rid == null) {
+            return null;
+        }
+
+        StringBuilder uriBuilder = new StringBuilder();
+        List<NodeKey> nodeKeyList = rid.nodeKeys();
+        String curNameSpace = null;
+        for (NodeKey key : nodeKeyList) {
+            curNameSpace = addNodeKeyToUri(key, curNameSpace, uriBuilder);
+        }
+        return uriBuilder.toString();
+    }
+
+    private static String addNodeKeyToUri(NodeKey key,
+                                          String curNameSpace,
+                                          StringBuilder uriBuilder) {
+        String newNameSpace;
+        if (key instanceof LeafListKey) {
+            newNameSpace = addLeafListNodeToUri((LeafListKey) key, curNameSpace, uriBuilder);
+        } else if (key instanceof ListKey) {
+            newNameSpace = addListNodeToUri((ListKey) key, curNameSpace, uriBuilder);
+        } else {
+            uriBuilder.append(SLASH);
+            newNameSpace = addNodeNameToUri(key, curNameSpace, uriBuilder);
+        }
+        return newNameSpace;
+    }
+
+    private static String addLeafListNodeToUri(LeafListKey key,
+                                               String curNameSpace,
+                                               StringBuilder uriBuilder) {
+
+        String newNameSpace = addNodeNameToUri(key, curNameSpace, uriBuilder);
+        uriBuilder.append(EQUAL);
+        uriBuilder.append(key.asString());
+        return newNameSpace;
+    }
+
+    private static String addListNodeToUri(ListKey key,
+                                           String curNameSpace,
+                                           StringBuilder uriBuilder) {
+        String newNameSpace = addNodeNameToUri(key, curNameSpace, uriBuilder);
+        uriBuilder.append(EQUAL);
+        String prefix = "";
+        for (KeyLeaf keyLeaf : key.keyLeafs()) {
+            uriBuilder.append(prefix);
+            prefix = COMMA;
+            uriBuilder.append(keyLeaf.leafValue().toString());
+        }
+
+        return newNameSpace;
+    }
+
+    private static String addNodeNameToUri(NodeKey key,
+                                           String curNameSpace,
+                                           StringBuilder uriBuilder) {
+        String nodeName = key.schemaId().name();
+        String newNameSpace = key.schemaId().namespace();
+
+        uriBuilder.append(nodeName);
+
+        if (newNameSpace == null) {
+            return curNameSpace;
+        }
+
+        if (!newNameSpace.equals(curNameSpace)) {
+            uriBuilder.append(COLON);
+            uriBuilder.append(newNameSpace);
+        }
+
+        return newNameSpace;
+    }
+
+    /**
+     * Converts a data node to JSON data.
+     *
+     * @param dataNode given data node
+     * @return JSON
+     */
+    public static ObjectNode convertDataNodeToJson(DataNode dataNode) {
+        checkNotNull(dataNode, "data node cannot be null");
+
+        JsonBuilder jsonBuilder = new DefaultJsonBuilder();
+        DataNodeVisitor treeNodeListener = new DataNodeJsonVisitor(jsonBuilder);
+
+        DataNodeSiblingPositionType siblingType = NOT_MULTI_INSTANCE_NODE;
+        walkDataNodeTree(treeNodeListener, dataNode, siblingType);
+
+        ObjectNode resultData = jsonBuilder.getTreeNode();
+        return resultData;
+    }
+
+    private static void walkDataNodeTree(DataNodeVisitor dataNodeVisitor,
+                                         DataNode dataNode,
+                                         DataNodeSiblingPositionType siblingType) {
+        checkNotNull(dataNode, "data tree cannot be null");
+        checkNotNull(dataNodeVisitor, "dataNodeVisitor cannot be null");
+
+        // depth-first walk of the data node tree
+        dataNodeVisitor.enterDataNode(dataNode, siblingType);
+
+        if (dataNode.type() == SINGLE_INSTANCE_NODE ||
+                dataNode.type() == MULTI_INSTANCE_NODE) {
+            // Walk through every child on the children list
+            walkChildNodeList(dataNodeVisitor, dataNode);
+        }
+
+        dataNodeVisitor.exitDataNode(dataNode, siblingType);
+    }
+
+    private static void walkChildNodeList(DataNodeVisitor dataNodeVisitor,
+                                          DataNode dataNode) {
+        if (dataNode.type() != SINGLE_INSTANCE_NODE &&
+                dataNode.type() != MULTI_INSTANCE_NODE) {
+            // Only inner nodes could have children.
+            return;
+        }
+
+        Map<NodeKey, DataNode> childrenList = ((InnerNode) dataNode).childNodes();
+        if (childrenList == null || childrenList.isEmpty()) {
+            // the children list is either not yet created or empty.
+            return;
+        }
+
+        /*
+         * We now have a none empty children list to walk through.
+         */
+
+        DataNodeSiblingPositionType prevChildType = UNKNOWN_TYPE;
+        DataNodeSiblingPositionType currChildType = UNKNOWN_TYPE;
+
+        Iterator it = childrenList.entrySet().iterator();
+        DataNode currChild = ((Map.Entry<NodeKey, DataNode>) it.next()).getValue();
+        DataNode nextChild = null;
+        boolean lastChildNotProcessed = true;
+        while (lastChildNotProcessed) {
+            /*
+             * Iterate through the children list. Invoke data node walker
+             * for every child. If the child is a multi-instance node, we
+             * need to determine if it is the first or last sibling and pass
+             * this info the walker.
+             */
+            if (it.hasNext()) {
+                nextChild = ((Map.Entry<NodeKey, DataNode>) it.next()).getValue();
+            } else {
+                /*
+                 * Current child is the last child.
+                 * So mark this iteration as the last one.
+                 */
+                lastChildNotProcessed = false;
+                nextChild = null;
+            }
+            currChildType = getCurrentChildSiblingType(currChild,
+                                                       nextChild,
+                                                       prevChildType);
+            walkDataNodeTree(dataNodeVisitor, currChild, currChildType);
+            prevChildType = currChildType;
+            currChild = nextChild;
+        }
+    }
+
+    private static DataNodeSiblingPositionType getCurrentChildSiblingType(DataNode currChild,
+                                                                          DataNode nextChild,
+                                                                          DataNodeSiblingPositionType prevChildType) {
+        if (currChild.type() != MULTI_INSTANCE_NODE &&
+                currChild.type() != MULTI_INSTANCE_LEAF_VALUE_NODE) {
+            return NOT_MULTI_INSTANCE_NODE;
+        }
+
+        DataNodeSiblingPositionType curChildSiblingType = UNKNOWN_TYPE;
+        switch (prevChildType) {
+            case UNKNOWN_TYPE:
+                /*
+                 * 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 (nextChild == null) {
+                    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:
+                /*
+                 * If we still have a next child and the next child's name
+                 * is the same name as the current node, then the current
+                 * node is not the last sibling yet.
+                 */
+                if (nextChild != null &&
+                        nextChild.key().schemaId().name().
+                                equals(currChild.key().schemaId().name())) {
+                    curChildSiblingType = MIDDLE_INSTANCE;
+                } else {
+                    curChildSiblingType = LAST_INSTANCE;
+                }
+                break;
+            default:
+                curChildSiblingType = UNKNOWN_TYPE;
+        }
+
+        return curChildSiblingType;
+    }
+}
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
new file mode 100644
index 0000000..98f162b
--- /dev/null
+++ b/serializers/json/src/main/java/org/onosproject/yang/serializers/json/JsonBuilder.java
@@ -0,0 +1,90 @@
+/*
+ *  Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.yang.serializers.json;
+
+import com.fasterxml.jackson.databind.node.JsonNodeType;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+import java.util.Set;
+
+/**
+ * Abstraction of an entity which provides interfaces to build and obtain JSON
+ * data tree.
+ */
+public interface JsonBuilder {
+
+    /**
+     * Adds a to half(a left brace/bracket and the field name) of a JSON
+     * object/array to the JSON tree. This method is used by protocols which
+     * knows the nature (object/array) of node.
+     *
+     * @param nodeName name of child to be added
+     * @param nodeType the type of the child
+     */
+    void addNodeTopHalf(String nodeName, JsonNodeType nodeType);
+
+    /**
+     * Adds a child with value and a comma to the JSON tree.
+     * Protocols unaware of nature of node (single/multiple) will use it to add
+     * both single instance and multi instance node. Protocols aware of nature
+     * of node will use it for single instance value node addition.
+     *
+     * @param nodeName name of child to be added
+     * @param value    value of the child node
+     */
+    void addNodeWithValueTopHalf(String nodeName, String value);
+
+    /**
+     * Adds a child with list of values to JSON data tree. This method is
+     * used by protocols which knows the nature (object/array) of node for
+     * ArrayNode addition.
+     *
+     * @param nodeName name of child to be added
+     * @param sets     the value list of the child
+     */
+    void addNodeWithSetTopHalf(String nodeName, Set<String> sets);
+
+    /**
+     * Adds value to a leaf list node.
+     *
+     * @param value value to be added
+     */
+    void addValueToLeafListNode(String value);
+
+    /**
+     * Adds the bottom half(a right brace/bracket) of a JSON
+     * object/array to the JSON tree. for the text, a comma should be
+     * taken out.
+     *
+     * @param nodeType the type of the child
+     */
+    void addNodeBottomHalf(JsonNodeType nodeType);
+
+    /**
+     * Returns the JSON tree after build operations in the format of string.
+     *
+     * @return the final string JSON tree after build operations
+     */
+    String getTreeString();
+
+    /**
+     * Returns the JSON tree after build operations in the format of string.
+     *
+     * @return the final ObjectNode JSON tree after build operations
+     */
+    ObjectNode getTreeNode();
+}
diff --git a/serializers/json/src/main/java/org/onosproject/yang/serializers/json/JsonSerializer.java b/serializers/json/src/main/java/org/onosproject/yang/serializers/json/JsonSerializer.java
new file mode 100644
index 0000000..a7c9197
--- /dev/null
+++ b/serializers/json/src/main/java/org/onosproject/yang/serializers/json/JsonSerializer.java
@@ -0,0 +1,139 @@
+/*
+ *  Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.yang.serializers.json;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.apache.commons.io.IOUtils;
+import org.onosproject.yang.model.DataNode;
+import org.onosproject.yang.model.ResourceId;
+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.ResourceData;
+import org.onosproject.yang.runtime.YangSerializer;
+import org.onosproject.yang.runtime.YangSerializerContext;
+import org.slf4j.Logger;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onosproject.yang.serializers.json.DecoderUtils.convertJsonToDataNode;
+import static org.onosproject.yang.serializers.json.DecoderUtils.convertUriToRid;
+import static org.onosproject.yang.serializers.json.EncoderUtils.convertDataNodeToJson;
+import static org.onosproject.yang.serializers.json.EncoderUtils.convertRidToUri;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Implementation of the JSON serializer.
+ */
+public class JsonSerializer implements YangSerializer {
+    private static final String JSON_FORMAT = "JSON";
+
+    private final Logger log = getLogger(getClass());
+    private final ObjectMapper mapper = new ObjectMapper();
+
+    public ObjectMapper mapper() {
+        return mapper;
+    }
+
+    @Override
+    public String supportsFormat() {
+        return JSON_FORMAT;
+    }
+
+    @Override
+    public CompositeData decode(CompositeStream compositeStream,
+                                YangSerializerContext yangSerializerContext) {
+        try {
+            ResourceId rid = convertUriToRid(compositeStream.resourceId(),
+                                             yangSerializerContext);
+
+            ObjectNode rootNode = null;
+
+            if (compositeStream.resourceData() != null) {
+                rootNode = (ObjectNode) mapper().
+                        readTree(compositeStream.resourceData());
+            }
+
+            DataNode dataNode;
+            /*
+             * initializeDataNode by passing yangSerializerContext is
+             * intended to be used in a scenario wherein URL is NULL.
+             * initializeDataNode by passing resourceIdBuilder is
+             * intended to be used in a scenario when URL is not NULL
+             * and in this case the resourceId builder which was constructed
+             * for a URL, needs to be given as an Input parameter.
+             */
+            if (rid != null) {
+                dataNode = convertJsonToDataNode(rootNode,
+                                                 new ResourceId.Builder(rid));
+
+            } else {
+                dataNode = convertJsonToDataNode(rootNode,
+                                                 yangSerializerContext);
+            }
+
+            ResourceData resourceData = DefaultResourceData.builder().
+                    addDataNode(dataNode).resourceId(rid).build();
+            return DefaultCompositeData.builder().resourceData(resourceData).build();
+        } catch (CloneNotSupportedException e) {
+            log.error("ERROR: JsonProcessingException {}",
+                      e.getMessage());
+            log.debug("Exception in decode:", e);
+            throw new SerializerException("JSON serializer decode failure");
+        } catch (JsonProcessingException e) {
+            log.error("ERROR: JsonProcessingException {}",
+                      e.getMessage());
+            log.debug("Exception in decode:", e);
+            throw new SerializerException("JSON serializer decode failure");
+        } catch (IOException ex) {
+            log.error("ERROR: decode ", ex);
+            throw new SerializerException("JSON serializer decode failure");
+        }
+    }
+
+
+    @Override
+    public CompositeStream encode(CompositeData compositeData,
+                                  YangSerializerContext yangSerializerContext) {
+        checkNotNull(compositeData, "compositeData cannot be null");
+
+        String uriString = convertRidToUri(compositeData.resourceData().
+                resourceId());
+        InputStream inputStream = null;
+        ObjectNode rootNode = null;
+
+        if (compositeData.resourceData().dataNodes() != null) {
+            rootNode = convertDataNodeToJson(compositeData.
+                    resourceData().dataNodes().get(0));
+        }
+
+        if (rootNode != null) {
+            inputStream = IOUtils.toInputStream(rootNode.toString());
+        }
+
+        CompositeStream compositeStream = new DefaultCompositeStream(uriString,
+                                                                     inputStream);
+
+        return compositeStream;
+    }
+}
diff --git a/serializers/json/src/main/java/org/onosproject/yang/serializers/json/JsonWalker.java b/serializers/json/src/main/java/org/onosproject/yang/serializers/json/JsonWalker.java
new file mode 100644
index 0000000..aa3e935
--- /dev/null
+++ b/serializers/json/src/main/java/org/onosproject/yang/serializers/json/JsonWalker.java
@@ -0,0 +1,38 @@
+/*
+ *  Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.yang.serializers.json;
+
+import com.fasterxml.jackson.databind.JsonNode;
+
+/**
+ * Abstraction of an entity which provides interfaces for Json walk. This interface serve as common tools
+ * for anyone who needs to parse the json node with depth-first algorithm.
+ */
+public interface JsonWalker {
+
+    /**
+     * Walks the JSON data tree. Protocols implements JSON listener service
+     * and walks JSON tree with input as implemented object. JSON walker provides
+     * call backs to implemented methods. For the original json node(come from NB),
+     * there is a field name which is something like the module name of a YANG model.
+     * If not, the fieldName can be null.
+     *
+     * @param fieldName the original object node field
+     * @param jsonNode  the json node which needs to be walk
+     */
+    void walkJsonNode(String fieldName, JsonNode jsonNode);
+}
diff --git a/serializers/json/src/main/java/org/onosproject/yang/serializers/json/SerializerException.java b/serializers/json/src/main/java/org/onosproject/yang/serializers/json/SerializerException.java
new file mode 100644
index 0000000..b7d899d
--- /dev/null
+++ b/serializers/json/src/main/java/org/onosproject/yang/serializers/json/SerializerException.java
@@ -0,0 +1,43 @@
+/*
+ *  Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.yang.serializers.json;
+
+/**
+ * Represents class of errors related to JSON parse utils.
+ */
+public class SerializerException extends RuntimeException {
+
+    /**
+     * Constructs an exception with the specified message.
+     *
+     * @param message the message describing the specific nature of the error
+     */
+    public SerializerException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs an exception with the specified message and the underlying
+     * cause.
+     *
+     * @param message the message describing the specific nature of the error
+     * @param cause   the underlying cause of this error
+     */
+    public SerializerException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/serializers/json/src/main/java/org/onosproject/yang/serializers/json/package-info.java b/serializers/json/src/main/java/org/onosproject/yang/serializers/json/package-info.java
new file mode 100644
index 0000000..56ecc6a
--- /dev/null
+++ b/serializers/json/src/main/java/org/onosproject/yang/serializers/json/package-info.java
@@ -0,0 +1,20 @@
+/*
+ *  Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * The JSON codec implementation of the YangSerializer interface.
+ */
+package org.onosproject.yang.serializers.json;
\ No newline at end of file
diff --git a/serializers/pom.xml b/serializers/pom.xml
new file mode 100644
index 0000000..6846261
--- /dev/null
+++ b/serializers/pom.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2017-present Open Networking Laboratory
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.onosproject</groupId>
+        <artifactId>onos-yang-tools</artifactId>
+        <version>1.12-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>onos-yang-serializers</artifactId>
+    <packaging>pom</packaging>
+
+    <modules>
+        <module>json</module>
+    </modules>
+
+    <description>Serializers for various codecs</description>
+</project>