Updated Json Stream Writer to use gson JsonWriter. 74/13574/14
authorPeter Kajsa <pkajsa@cisco.com>
Thu, 11 Dec 2014 15:43:02 +0000 (16:43 +0100)
committerTony Tkacik <ttkacik@cisco.com>
Mon, 16 Feb 2015 11:31:32 +0000 (11:31 +0000)
Custom implementation of JSON writing methods has been replaced with native
com.google.gson.stream.JsonWriter methods. Among other things, this rework
resolves issues (bugs) with escape characters in string values being written
into Json (e.g. new lines in strings etc.).

Important notice: com.google.gson.stream.JsonWriter enforces that output
must start with '{' and end with '}', otherwise
'java.lang.IllegalStateException:Nesting problem' is thrown.

So our original output looks for an example like:
"my-module:top-container": {
...
}

Now, new output looks as following:
{
  "my-module:top-container": {
  ...
  }
}
.

Change-Id: I8073285d003015721d54887ddbff0484d7db89c8
Signed-off-by: Peter Kajsa <pkajsa@cisco.com>
19 files changed:
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/AbstractJSONCodec.java
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/BooleanJSONCodec.java [new file with mode: 0644]
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONCodec.java
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONCodecFactory.java
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONLeafrefCodec.java
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONNormalizedNodeStreamWriter.java
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONStreamWriterContext.java
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONStreamWriterInvisibleContext.java
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONStreamWriterListContext.java
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONStreamWriterNamedObjectContext.java
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONStreamWriterObjectContext.java
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONStreamWriterRootContext.java
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONStreamWriterURIContext.java
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONStringIdentityrefCodec.java
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONStringInstanceIdentifierCodec.java
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JsonWriterFactory.java [new file with mode: 0644]
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/NumberJSONCodec.java [moved from yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/UnquotedJSONCodec.java with 58% similarity]
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/QuotedJSONCodec.java
yang/yang-data-codec-gson/src/test/java/org/opendaylight/yangtools/yang/data/codec/gson/NormalizedNodeToJsonStreamTest.java

index 94646531a8cf0ed607b00af1620abada67117b58..9b3f3d2ac4e12f942b43eb4943b048c677f08bc8 100644 (file)
@@ -8,7 +8,6 @@
 package org.opendaylight.yangtools.yang.data.codec.gson;
 
 import com.google.common.base.Preconditions;
-
 import org.opendaylight.yangtools.concepts.Codec;
 import org.opendaylight.yangtools.yang.data.api.codec.BooleanCodec;
 import org.opendaylight.yangtools.yang.data.api.codec.DecimalCodec;
@@ -39,16 +38,18 @@ abstract class AbstractJSONCodec<T> implements JSONCodec<T> {
      * @param codec underlying codec
      * @return A JSONCodec instance
      */
-    public static <T> JSONCodec<T> create(final Codec<String, T> codec) {
-        if (codec instanceof BooleanCodec || codec instanceof DecimalCodec ||
-                codec instanceof Int8Codec || codec instanceof Int16Codec ||
-                codec instanceof Int32Codec || codec instanceof Int64Codec ||
-                codec instanceof Uint8Codec || codec instanceof Uint16Codec ||
-                codec instanceof Uint32Codec || codec instanceof Uint64Codec) {
-            return new UnquotedJSONCodec<>(codec);
+    public static JSONCodec<?> create(final Codec<String, ?> codec) {
+        if (codec instanceof BooleanCodec) {
+            return new BooleanJSONCodec((BooleanCodec<String>) codec);
+        } else if (codec instanceof DecimalCodec || codec instanceof Int8Codec
+                || codec instanceof Int16Codec || codec instanceof Int32Codec
+                || codec instanceof Int64Codec || codec instanceof Uint8Codec
+                || codec instanceof Uint16Codec || codec instanceof Uint32Codec
+                || codec instanceof Uint64Codec) {
+            return new NumberJSONCodec(codec);
+        } else {
+            return new QuotedJSONCodec<>(codec);
         }
-
-        return new QuotedJSONCodec<>(codec);
     }
 
     @Override
diff --git a/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/BooleanJSONCodec.java b/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/BooleanJSONCodec.java
new file mode 100644 (file)
index 0000000..0840cd4
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.codec.gson;
+
+import com.google.gson.stream.JsonWriter;
+import java.io.IOException;
+import org.opendaylight.yangtools.concepts.Codec;
+
+/**
+ * A {@link JSONCodec} which does not need double quotes in output representation.
+ *
+ * @param <T> Deserialized value type
+ */
+final class BooleanJSONCodec extends AbstractJSONCodec<Boolean> {
+    BooleanJSONCodec(final Codec<String, Boolean> codec) {
+        super(codec);
+    }
+
+    @Override
+    public boolean needQuotes() {
+        return false;
+    }
+
+    /**
+     * Serialize specified value with specified JsonWriter.
+     *
+     * @param writer JsonWriter
+     * @param value
+     */
+    @Override
+    public void serializeToWriter(JsonWriter writer, Boolean value) throws IOException {
+        writer.value(value);
+    };
+}
\ No newline at end of file
index aa52259c588a72d6411f7f26f87f877c2e90809d..003684cbf69d1c0179bbfeabf79816c191963a96 100644 (file)
@@ -7,8 +7,20 @@
  */
 package org.opendaylight.yangtools.yang.data.codec.gson;
 
+import com.google.gson.stream.JsonWriter;
+import java.io.IOException;
 import org.opendaylight.yangtools.concepts.Codec;
 
 interface JSONCodec<T> extends Codec<String, T> {
+    // FIXME: Unused, remove once we are sure we do not need this anymore.
     boolean needQuotes();
+
+
+    /**
+     * Serialize specified value with specified JsonWriter.
+     *
+     * @param writer JsonWriter
+     * @param value
+     */
+    void serializeToWriter(JsonWriter writer, T value) throws IOException;
 }
index 8ee9517ec2db90f976aa64e5b26a883abe3a7c4e..c99d46404885c0b6c9b9e04dc24a64e0dbe0106f 100644 (file)
@@ -12,7 +12,8 @@ import com.google.common.base.Preconditions;
 import com.google.common.cache.CacheBuilder;
 import com.google.common.cache.CacheLoader;
 import com.google.common.cache.LoadingCache;
-
+import com.google.gson.stream.JsonWriter;
+import java.io.IOException;
 import org.opendaylight.yangtools.yang.data.impl.codec.TypeDefinitionAwareCodec;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
@@ -45,6 +46,12 @@ public final class JSONCodecFactory {
         public boolean needQuotes() {
             return false;
         }
+
+        @Override
+        public void serializeToWriter(JsonWriter writer, Object value) throws IOException {
+            // NOOP since codec is unkwown.
+            LOG.warn("Call of the serializeToWriter method on JSONCodecFactory.NULL_CODEC object. No operation performed.");
+        }
     };
 
     private static TypeDefinition<?> resolveBaseTypeFrom(final TypeDefinition<?> type) {
@@ -78,7 +85,7 @@ public final class JSONCodecFactory {
                 return NULL_CODEC;
             }
 
-            return AbstractJSONCodec.create(codec);
+            return (JSONCodec<Object>) AbstractJSONCodec.create(codec);
         }
     });
 
index 5613433bbe5cc148d9e2e6f7ce8ae5f3af5d75e7..51fc686513b091a5901cf23fca0565e8306fa968 100644 (file)
@@ -7,6 +7,8 @@
  */
 package org.opendaylight.yangtools.yang.data.codec.gson;
 
+import com.google.gson.stream.JsonWriter;
+import java.io.IOException;
 import org.opendaylight.yangtools.yang.data.api.codec.LeafrefCodec;
 
 final class JSONLeafrefCodec implements JSONCodec<Object>, LeafrefCodec<String> {
@@ -24,4 +26,15 @@ final class JSONLeafrefCodec implements JSONCodec<Object>, LeafrefCodec<String>
     public boolean needQuotes() {
         return true;
     }
+
+    /**
+     * Serialize specified value with specified JsonWriter.
+     *
+     * @param writer JsonWriter
+     * @param value
+     */
+    @Override
+    public void serializeToWriter(JsonWriter writer, Object value) throws IOException {
+        writer.value(serialize(value));
+    }
 }
\ No newline at end of file
index 59ef1f1e501ffc53011230f5f2f8ba61271f530c..079b8e324aeba0638e2832596059b50c3f279f68 100644 (file)
@@ -7,9 +7,7 @@
  */
 package org.opendaylight.yangtools.yang.data.codec.gson;
 
-import com.google.common.base.CharMatcher;
 import com.google.common.base.Preconditions;
-import com.google.common.base.Strings;
 import com.google.gson.stream.JsonWriter;
 import java.io.IOException;
 import java.io.Writer;
@@ -31,7 +29,6 @@ import org.opendaylight.yangtools.yang.model.api.SchemaPath;
  *
  * Values of leaf and leaf-list are NOT translated according to codecs.
  *
- * FIXME: rewrite this in terms of {@link JsonWriter}.
  */
 public class JSONNormalizedNodeStreamWriter implements NormalizedNodeStreamWriter {
     /**
@@ -40,27 +37,13 @@ public class JSONNormalizedNodeStreamWriter implements NormalizedNodeStreamWrite
      */
     private static final boolean DEFAULT_EMIT_EMPTY_CONTAINERS = true;
 
-    /**
-     * Matcher used to check if a string needs to be escaped.
-     */
-    private static final CharMatcher JSON_ILLEGAL_STRING_CHARACTERS = CharMatcher.anyOf("\\\"\n\r");
-
     private final SchemaTracker tracker;
     private final JSONCodecFactory codecs;
-    private final Writer writer;
-    private final String indent;
+    private final JsonWriter writer;
     private JSONStreamWriterContext context;
 
-    private JSONNormalizedNodeStreamWriter(final JSONCodecFactory codecFactory, final SchemaPath path,
-            final Writer writer, final URI initialNs, final int indentSize) {
-        this.writer = Preconditions.checkNotNull(writer);
-
-        Preconditions.checkArgument(indentSize >= 0, "Indent size must be non-negative");
-        if (indentSize != 0) {
-            indent = Strings.repeat(" ", indentSize);
-        } else {
-            indent = null;
-        }
+    private JSONNormalizedNodeStreamWriter(final JSONCodecFactory codecFactory, final SchemaPath path, final URI initialNs, JsonWriter JsonWriter) {
+        this.writer = JsonWriter;
         this.codecs = Preconditions.checkNotNull(codecFactory);
         this.tracker = SchemaTracker.create(codecFactory.getSchemaContext(), path);
         this.context = new JSONStreamWriterRootContext(initialNs);
@@ -74,7 +57,7 @@ public class JSONNormalizedNodeStreamWriter implements NormalizedNodeStreamWrite
      * @return A stream writer instance
      */
     public static NormalizedNodeStreamWriter create(final SchemaContext schemaContext, final Writer writer) {
-        return new JSONNormalizedNodeStreamWriter(JSONCodecFactory.create(schemaContext), SchemaPath.ROOT, writer, null, 0);
+        return create(schemaContext, SchemaPath.ROOT, null, writer);
     }
 
     /**
@@ -86,7 +69,7 @@ public class JSONNormalizedNodeStreamWriter implements NormalizedNodeStreamWrite
      * @return A stream writer instance
      */
     public static NormalizedNodeStreamWriter create(final SchemaContext schemaContext, final SchemaPath path, final Writer writer) {
-        return new JSONNormalizedNodeStreamWriter(JSONCodecFactory.create(schemaContext), path, writer, null, 0);
+        return create(schemaContext, path, null, writer);
     }
 
     /**
@@ -100,7 +83,7 @@ public class JSONNormalizedNodeStreamWriter implements NormalizedNodeStreamWrite
      */
     public static NormalizedNodeStreamWriter create(final SchemaContext schemaContext, final SchemaPath path,
             final URI initialNs, final Writer writer) {
-        return new JSONNormalizedNodeStreamWriter(JSONCodecFactory.create(schemaContext), path, writer, initialNs, 0);
+        return create(JSONCodecFactory.create(schemaContext), path, initialNs, JsonWriterFactory.createJsonWriter(writer));
     }
 
     /**
@@ -112,7 +95,7 @@ public class JSONNormalizedNodeStreamWriter implements NormalizedNodeStreamWrite
      * @return A stream writer instance
      */
     public static NormalizedNodeStreamWriter create(final SchemaContext schemaContext, final Writer writer, final int indentSize) {
-        return new JSONNormalizedNodeStreamWriter(JSONCodecFactory.create(schemaContext), SchemaPath.ROOT, writer, null, indentSize);
+        return create(JSONCodecFactory.create(schemaContext), SchemaPath.ROOT, null,JsonWriterFactory.createJsonWriter(writer, indentSize));
     }
 
     /**
@@ -125,7 +108,35 @@ public class JSONNormalizedNodeStreamWriter implements NormalizedNodeStreamWrite
      * @return A stream writer instance
      */
     public static NormalizedNodeStreamWriter create(final JSONCodecFactory codecFactory, final Writer writer, final int indentSize) {
-        return new JSONNormalizedNodeStreamWriter(codecFactory, SchemaPath.ROOT, writer, null, indentSize);
+        return create(codecFactory, SchemaPath.ROOT, null, JsonWriterFactory.createJsonWriter(writer,indentSize));
+    }
+
+    /**
+     * Create a new stream writer, which writes to the specified output stream.
+     *
+     * @param schemaContext Schema context
+     * @param path Schema Path
+     * @param initialNs Initial namespace
+     * @param jsonWriter JsonWriter
+     * @return A stream writer instance
+     */
+    public static NormalizedNodeStreamWriter create(SchemaContext schemaContext, SchemaPath path, URI initialNs,
+            JsonWriter jsonWriter) {
+        return create(JSONCodecFactory.create(schemaContext), path, initialNs, jsonWriter);
+    }
+
+    /**
+     * Create a new stream writer, which writes to the specified output stream. The codec factory
+     * can be reused between multiple writers.
+     *
+     * @param codecFactory JSON codec factory
+     * @param path Schema Path
+     * @param initialNs Initial namespace
+     * @param jsonWriter JsonWriter
+     * @return A stream writer instance
+     */
+    public static NormalizedNodeStreamWriter create(JSONCodecFactory codecFactory, SchemaPath path, URI initialNs, JsonWriter jsonWriter) {
+        return new JSONNormalizedNodeStreamWriter(codecFactory, path, initialNs, jsonWriter);
     }
 
     @Override
@@ -133,9 +144,10 @@ public class JSONNormalizedNodeStreamWriter implements NormalizedNodeStreamWrite
         final LeafSchemaNode schema = tracker.leafNode(name);
         final JSONCodec<Object> codec = codecs.codecFor(schema.getType());
 
-        context.emittingChild(codecs.getSchemaContext(), writer, indent);
+        context.emittingChild(codecs.getSchemaContext(), writer);
         context.writeChildJsonIdentifier(codecs.getSchemaContext(), writer, name.getNodeType());
-        writeValue(codec.serialize(value), codec.needQuotes());
+
+        writeValue(value, codec);
     }
 
     @Override
@@ -149,8 +161,9 @@ public class JSONNormalizedNodeStreamWriter implements NormalizedNodeStreamWrite
         final LeafListSchemaNode schema = tracker.leafSetEntryNode();
         final JSONCodec<Object> codec = codecs.codecFor(schema.getType());
 
-        context.emittingChild(codecs.getSchemaContext(), writer, indent);
-        writeValue(codec.serialize(value), codec.needQuotes());
+        context.emittingChild(codecs.getSchemaContext(), writer);
+
+        writeValue(value, codec);
     }
 
     /*
@@ -216,42 +229,23 @@ public class JSONNormalizedNodeStreamWriter implements NormalizedNodeStreamWrite
         final AnyXmlSchemaNode schema = tracker.anyxmlNode(name);
         // FIXME: should have a codec based on this :)
 
-        context.emittingChild(codecs.getSchemaContext(), writer, indent);
+        context.emittingChild(codecs.getSchemaContext(), writer);
         context.writeChildJsonIdentifier(codecs.getSchemaContext(), writer, name.getNodeType());
-        writeValue(String.valueOf(value), true);
+        writer.value(String.valueOf(value));
     }
 
     @Override
     public void endNode() throws IOException {
         tracker.endNode();
-        context = context.endNode(codecs.getSchemaContext(), writer, indent);
+        context = context.endNode(codecs.getSchemaContext(), writer);
+        if(context instanceof JSONStreamWriterRootContext) {
+            context.emitEnd(writer);
+        }
     }
 
-    private void writeValue(final String str, final boolean needQuotes) throws IOException {
-        if (needQuotes) {
-            writer.append('"');
-
-            final int needEscape = JSON_ILLEGAL_STRING_CHARACTERS.countIn(str);
-            if (needEscape != 0) {
-                final char[] escaped = new char[str.length() + needEscape];
-                int offset = 0;
-
-                for (int i = 0; i < str.length(); i++) {
-                    final char c = str.charAt(i);
-                    if (JSON_ILLEGAL_STRING_CHARACTERS.matches(c)) {
-                        escaped[offset++] = '\\';
-                    }
-                    escaped[offset++] = c;
-                }
-                writer.write(escaped);
-            } else {
-                writer.append(str);
-            }
-
-            writer.append('"');
-        } else {
-            writer.append(str);
-        }
+    private void writeValue(Object value, JSONCodec<Object> codec)
+            throws IOException {
+        codec.serializeToWriter(writer,value);
     }
 
     @Override
@@ -265,4 +259,6 @@ public class JSONNormalizedNodeStreamWriter implements NormalizedNodeStreamWrite
         writer.close();
     }
 
+
+
 }
index a3ad80dfb3f28473b523f3b12c1a1cc335063715..a29972aa939e84a88f435225a559ed59ac1eb9f6 100644 (file)
@@ -8,8 +8,9 @@
 package org.opendaylight.yangtools.yang.data.codec.gson;
 
 import com.google.common.base.Preconditions;
+import com.google.gson.stream.JsonWriter;
 import java.io.IOException;
-import java.io.Writer;
+import java.io.StringWriter;
 import java.net.URI;
 import javax.annotation.Nonnull;
 import org.opendaylight.yangtools.yang.common.QName;
@@ -26,7 +27,6 @@ abstract class JSONStreamWriterContext {
     private final boolean mandatory;
     private final int depth;
     private boolean emittedMyself = false;
-    private boolean haveChild = false;
 
     /**
      * Construct a new context.
@@ -55,21 +55,21 @@ abstract class JSONStreamWriterContext {
      * @param qname Namespace/name tuple
      * @throws IOException when the writer reports it
      */
-    final void writeChildJsonIdentifier(final SchemaContext schema, final Writer writer, final QName qname) throws IOException {
-        writer.append('"');
+    final void writeChildJsonIdentifier(final SchemaContext schema, final JsonWriter writer, final QName qname) throws IOException {
 
+        StringWriter strWriter = new StringWriter();
         // Prepend module name if namespaces do not match
         final URI ns = qname.getNamespace();
         if (!ns.equals(getNamespace())) {
             final Module module = schema.findModuleByNamespaceAndRevision(ns, null);
             Preconditions.checkArgument(module != null, "Could not find module for namespace {}", ns);
 
-            writer.append(module.getName());
-            writer.append(':');
+            strWriter.append(module.getName());
+            strWriter.append(':');
         }
+        strWriter.append(qname.getLocalName());
 
-        writer.append(qname.getLocalName());
-        writer.append("\":");
+        writer.name(strWriter.toString());
     }
 
     /**
@@ -81,7 +81,7 @@ abstract class JSONStreamWriterContext {
      * @param qname Namespace/name tuple
      * @throws IOException when the writer reports it
      */
-    protected final void writeMyJsonIdentifier(final SchemaContext schema, final Writer writer, final QName qname) throws IOException {
+    protected final void writeMyJsonIdentifier(final SchemaContext schema, final JsonWriter writer, final QName qname) throws IOException {
         parent.writeChildJsonIdentifier(schema, writer, qname);
     }
 
@@ -99,7 +99,7 @@ abstract class JSONStreamWriterContext {
      * @param writer Output writer
      * @throws IOException
      */
-    protected abstract void emitStart(final SchemaContext schema, final Writer writer) throws IOException;
+    protected abstract void emitStart(final SchemaContext schema, final JsonWriter writer) throws IOException;
 
     /**
      * Emit the end of an element.
@@ -108,12 +108,12 @@ abstract class JSONStreamWriterContext {
      * @param writer Output writer
      * @throws IOException
      */
-    protected abstract void emitEnd(final Writer writer) throws IOException;
+    protected abstract void emitEnd(final JsonWriter writer) throws IOException;
 
-    private final void emitMyself(final SchemaContext schema, final Writer writer, final String indent) throws IOException {
+    private final void emitMyself(final SchemaContext schema, final JsonWriter writer) throws IOException {
         if (!emittedMyself) {
             if (parent != null) {
-                parent.emittingChild(schema, writer, indent);
+                parent.emittingChild(schema, writer);
             }
 
             emitStart(schema, writer);
@@ -128,23 +128,10 @@ abstract class JSONStreamWriterContext {
      *
      * @param schema Schema context
      * @param writer Output writer
-     * @param indent Indentation string
      * @throws IOException when writer reports it
      */
-    final void emittingChild(final SchemaContext schema, final Writer writer, final String indent) throws IOException {
-        emitMyself(schema, writer, indent);
-        if (haveChild) {
-            writer.append(',');
-        }
-
-        if (indent != null) {
-            writer.append('\n');
-
-            for (int i = 0; i < depth; i++) {
-                writer.append(indent);
-            }
-        }
-        haveChild = true;
+    final void emittingChild(final SchemaContext schema, final JsonWriter writer) throws IOException {
+        emitMyself(schema, writer);
     }
 
     /**
@@ -153,14 +140,13 @@ abstract class JSONStreamWriterContext {
      *
      * @param schema Schema context
      * @param writer Output writer
-     * @param indent Indentation string
      * @return Parent node context
      * @throws IOException when writer reports it
      * @throws IllegalArgumentException if this node cannot be ended (e.g. root)
      */
-    final JSONStreamWriterContext endNode(final SchemaContext schema, final Writer writer, final String indent) throws IOException {
+    final JSONStreamWriterContext endNode(final SchemaContext schema, final JsonWriter writer) throws IOException {
         if (!emittedMyself && mandatory) {
-            emitMyself(schema, writer, indent);
+            emitMyself(schema, writer);
         }
 
         if (emittedMyself) {
index 7f22c194664637e2916e521849d8d59d9380cdcd..e43aead9f449496235284f17dbbba6aa474b644b 100644 (file)
@@ -8,8 +8,9 @@
 package org.opendaylight.yangtools.yang.data.codec.gson;
 
 import com.google.common.base.Preconditions;
+import com.google.gson.stream.JsonWriter;
+
 
-import java.io.Writer;
 
 /**
  * A virtual recursion level in {@link JSONNormalizedNodeStreamWriter}, used for nodes
@@ -21,7 +22,7 @@ final class JSONStreamWriterInvisibleContext extends JSONStreamWriterURIContext
     }
 
     @Override
-    protected void emitEnd(final Writer writer) {
+    protected void emitEnd(final JsonWriter writer) {
         // No-op
     }
 }
\ No newline at end of file
index 9c0be476b1bb332e4d91a2a36f85a6e47cced61a..e1505c7b10898d097b75783314b6f8f136c8ec92 100644 (file)
@@ -8,8 +8,8 @@
 package org.opendaylight.yangtools.yang.data.codec.gson;
 
 import com.google.common.base.Preconditions;
+import com.google.gson.stream.JsonWriter;
 import java.io.IOException;
-import java.io.Writer;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 
@@ -23,13 +23,13 @@ final class JSONStreamWriterListContext extends JSONStreamWriterQNameContext {
     }
 
     @Override
-    protected void emitStart(final SchemaContext schema, final Writer writer) throws IOException {
+    protected void emitStart(final SchemaContext schema, final JsonWriter writer) throws IOException {
         writeMyJsonIdentifier(schema, writer, getQName());
-        writer.append('[');
+        writer.beginArray();
     }
 
     @Override
-    protected void emitEnd(final Writer writer) throws IOException {
-        writer.append(']');
+    protected void emitEnd(final JsonWriter writer) throws IOException {
+        writer.endArray();
     }
 }
index 91c6ca70ae2c5a613984610bbdba44ae5aeca598..fe08410cafa5620cc7b3e2b1a1d8dfa72f0455df 100644 (file)
@@ -7,11 +7,12 @@
  */
 package org.opendaylight.yangtools.yang.data.codec.gson;
 
+import com.google.gson.stream.JsonWriter;
 import java.io.IOException;
-import java.io.Writer;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 
+
 /**
  * A recursion level of {@link JSONNormalizedNodeStreamWriter}, which represents
  * a JSON object which has to be prefixed with its identifier -- such as a
@@ -23,7 +24,7 @@ final class JSONStreamWriterNamedObjectContext extends JSONStreamWriterObjectCon
     }
 
     @Override
-    protected void emitStart(final SchemaContext schema, final Writer writer) throws IOException {
+    protected void emitStart(final SchemaContext schema, final JsonWriter writer) throws IOException {
         writeMyJsonIdentifier(schema, writer, getQName());
         super.emitStart(schema, writer);
     }
index d12f0449dd89e58ee4e6f3fd66be552dfb7ab919..fb4e48ed6091073550c02154113496c318e8016c 100644 (file)
@@ -8,10 +8,8 @@
 package org.opendaylight.yangtools.yang.data.codec.gson;
 
 import com.google.common.base.Preconditions;
-
+import com.google.gson.stream.JsonWriter;
 import java.io.IOException;
-import java.io.Writer;
-
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 
@@ -26,12 +24,12 @@ class JSONStreamWriterObjectContext extends JSONStreamWriterQNameContext {
     }
 
     @Override
-    protected void emitStart(final SchemaContext schema, final Writer writer) throws IOException {
-        writer.append('{');
+    protected void emitStart(final SchemaContext schema, final JsonWriter writer) throws IOException {
+        writer.beginObject();
     }
 
     @Override
-    protected void emitEnd(final Writer writer) throws IOException {
-        writer.append('}');
+    protected void emitEnd(final JsonWriter writer) throws IOException {
+        writer.endObject();
     }
 }
\ No newline at end of file
index 36c3ff38c349d7ad05f4474aa024c02d8aff9db6..bb0d49dc8674ea728c8a4951f5598732b76d7e33 100644 (file)
@@ -7,8 +7,11 @@
  */
 package org.opendaylight.yangtools.yang.data.codec.gson;
 
-import java.io.Writer;
+import com.google.gson.stream.JsonWriter;
+import java.io.IOException;
 import java.net.URI;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
 
 /**
  * The root node of a particular {@link JSONNormalizedNodeStreamWriter} instance.
@@ -20,7 +23,12 @@ final class JSONStreamWriterRootContext extends JSONStreamWriterURIContext {
     }
 
     @Override
-    protected void emitEnd(final Writer writer) {
-        throw new IllegalArgumentException("Top-level node reached");
+    protected void emitStart(final SchemaContext schema, final JsonWriter writer) throws IOException {
+        writer.beginObject();
+    }
+
+    @Override
+    protected void emitEnd(final JsonWriter writer) throws IOException {
+        writer.endObject();
     }
 }
index 06c32bf26d3ab37bef9738bc2749f30252103b16..f0d286a42781509bf61cce87fcfa0e1b4c0d4e82 100644 (file)
@@ -7,12 +7,12 @@
  */
 package org.opendaylight.yangtools.yang.data.codec.gson;
 
+import com.google.gson.stream.JsonWriter;
 import java.io.IOException;
-import java.io.Writer;
 import java.net.URI;
-
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 
+
 /**
  * Abstract class tracking a virtual level of {@link JSONNormalizedNodeStreamWriter}
  * recursion. It only tracks the namespace associated with this node.
@@ -31,7 +31,7 @@ abstract class JSONStreamWriterURIContext extends JSONStreamWriterContext {
     }
 
     @Override
-    protected final void emitStart(final SchemaContext schema, final Writer writer) throws IOException {
+    protected void emitStart(final SchemaContext schema, final JsonWriter writer) throws IOException {
         // No-op
     }
 }
\ No newline at end of file
index fcbe473cca8dc6b414814a2e05ed3f92d9e3673e..7e099b4e2d8aa96f35f732e728ee2e9412681ce7 100644 (file)
@@ -8,9 +8,9 @@
 package org.opendaylight.yangtools.yang.data.codec.gson;
 
 import com.google.common.base.Preconditions;
-
+import com.google.gson.stream.JsonWriter;
+import java.io.IOException;
 import java.net.URI;
-
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.util.AbstractModuleStringIdentityrefCodec;
 import org.opendaylight.yangtools.yang.model.api.Module;
@@ -38,4 +38,15 @@ final class JSONStringIdentityrefCodec extends AbstractModuleStringIdentityrefCo
     public boolean needQuotes() {
         return true;
     }
+
+    /**
+     * Serialize QName with specified JsonWriter.
+     *
+     * @param writer JsonWriter
+     * @param value QName
+     */
+    @Override
+    public void serializeToWriter(JsonWriter writer, QName value) throws IOException {
+        writer.value(serialize(value));
+    }
 }
index a1580dd5bb2c3f5681569c1c3541e68d38f51cbf..77fa797efa4f3036d89c93f3063c25433003865a 100644 (file)
@@ -8,9 +8,9 @@
 package org.opendaylight.yangtools.yang.data.codec.gson;
 
 import com.google.common.base.Preconditions;
-
+import com.google.gson.stream.JsonWriter;
+import java.io.IOException;
 import java.net.URI;
-
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.util.AbstractModuleStringInstanceIdentifierCodec;
 import org.opendaylight.yangtools.yang.model.api.Module;
@@ -38,4 +38,15 @@ final class JSONStringInstanceIdentifierCodec extends AbstractModuleStringInstan
     public boolean needQuotes() {
         return true;
     }
+
+    /**
+     * Serialize YangInstanceIdentifier with specified JsonWriter.
+     *
+     * @param writer JsonWriter
+     * @param value YangInstanceIdentifier
+     */
+    @Override
+    public void serializeToWriter(JsonWriter writer, YangInstanceIdentifier value) throws IOException {
+        writer.value(serialize(value));
+    }
 }
diff --git a/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JsonWriterFactory.java b/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JsonWriterFactory.java
new file mode 100644 (file)
index 0000000..3b3bf8d
--- /dev/null
@@ -0,0 +1,47 @@
+/**
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.codec.gson;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Strings;
+import com.google.gson.stream.JsonWriter;
+import java.io.Writer;
+
+/**
+ * Factory Method class for JsonWriter creation
+ */
+@Beta
+public final class JsonWriterFactory {
+
+    private JsonWriterFactory() {
+    }
+    /**
+     * Create a new JsonWriter, which writes to the specified output writer.
+     *
+     * @param writer Output writer
+     * @return A JsonWriter instance
+     */
+    public static JsonWriter createJsonWriter(Writer writer) {
+        return new JsonWriter(writer);
+    }
+
+    /**
+     * Create a new JsonWriter, which writes to the specified output writer.
+     *
+     * @param writer Output writer
+     * @param indentSize size of the indent
+     * @return A JsonWriter instance
+     */
+    public static JsonWriter createJsonWriter(Writer writer, int indentSize) {
+        JsonWriter jsonWriter = new JsonWriter(writer);
+        final String indent = Strings.repeat(" ", indentSize);
+        jsonWriter.setIndent(indent);
+        return jsonWriter;
+    }
+
+}
similarity index 58%
rename from yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/UnquotedJSONCodec.java
rename to yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/NumberJSONCodec.java
index f29db5d1eeeea56e38ac9a3db5b26b98c8062a0f..d262a440ce86681bc2d9508f601b8ee74b502abc 100644 (file)
@@ -7,6 +7,8 @@
  */
 package org.opendaylight.yangtools.yang.data.codec.gson;
 
+import com.google.gson.stream.JsonWriter;
+import java.io.IOException;
 import org.opendaylight.yangtools.concepts.Codec;
 
 /**
@@ -14,8 +16,8 @@ import org.opendaylight.yangtools.concepts.Codec;
  *
  * @param <T> Deserialized value type
  */
-final class UnquotedJSONCodec<T> extends AbstractJSONCodec<T> {
-    UnquotedJSONCodec(final Codec<String, T> codec) {
+final class NumberJSONCodec<T extends Number> extends AbstractJSONCodec<T > {
+    NumberJSONCodec(final Codec<String, T> codec) {
         super(codec);
     }
 
@@ -23,4 +25,15 @@ final class UnquotedJSONCodec<T> extends AbstractJSONCodec<T> {
     public boolean needQuotes() {
         return false;
     }
+
+    /**
+     * Serialize specified value with specified JsonWriter.
+     *
+     * @param writer JsonWriter
+     * @param value
+     */
+    @Override
+    public void serializeToWriter(JsonWriter writer, T value) throws IOException {
+        writer.value(value);
+    }
 }
\ No newline at end of file
index e8606f8d9587f4304d752cfe2215e19d5e6ced0b..45782896cf2b3bbe3d9040da4904713519e69365 100644 (file)
@@ -7,6 +7,8 @@
  */
 package org.opendaylight.yangtools.yang.data.codec.gson;
 
+import com.google.gson.stream.JsonWriter;
+import java.io.IOException;
 import org.opendaylight.yangtools.concepts.Codec;
 
 /**
@@ -23,4 +25,15 @@ final class QuotedJSONCodec<T> extends AbstractJSONCodec<T> {
     public boolean needQuotes() {
         return true;
     }
+
+    /**
+     * Serialize specified value with specified JsonWriter.
+     *
+     * @param writer JsonWriter
+     * @param value
+     */
+    @Override
+    public void serializeToWriter(JsonWriter writer, T value) throws IOException {
+        writer.value(serialize(value));
+    }
 }
\ No newline at end of file
index 39a1f1bc7bbe30c9cd131cd581d7269650ed4b0a..484aa70029c1182660de8863616c12cbc205b295 100644 (file)
@@ -382,11 +382,11 @@ public class NormalizedNodeToJsonStreamTest {
 
     private String normalizedNodeToJsonStreamTransformation(final Writer writer,
             final NormalizedNode<?, ?> inputStructure) throws IOException {
-        writer.write("{\n");
+
         final NormalizedNodeStreamWriter jsonStream = JSONNormalizedNodeStreamWriter.create(schemaContext, writer, 2);
         final NormalizedNodeWriter nodeWriter = NormalizedNodeWriter.forStreamWriter(jsonStream);
         nodeWriter.write(inputStructure);
-        writer.write("\n}");
+
         nodeWriter.close();
         return writer.toString();
     }