Date: Fri Dec 2 18:48:42 2011
New Revision: 1209632
URL: http://svn.apache.org/viewvc?rev=1209632&view=rev
Log:
noggit: refactor JSONWriter, add indenting, change string escaping to avoid illegal javascript chars
Added:
    labs/noggit/src/main/java/org/apache/noggit/JSONWriter.java
      - copied, changed from r1099567, labs/noggit/src/main/java/org/apache/noggit/TextWriter.java
    labs/noggit/src/test/java/org/apache/noggit/TestJSONWriter.java   (with props)
Removed:
    labs/noggit/src/main/java/org/apache/noggit/TextWriter.java
Modified:
    labs/noggit/src/main/java/org/apache/noggit/JSONUtil.java
    labs/noggit/src/test/java/org/apache/noggit/TestObjectBuilder.java
Modified: labs/noggit/src/main/java/org/apache/noggit/JSONUtil.java
URL: http://svn.apache.org/viewvc/labs/noggit/src/main/java/org/apache/noggit/JSONUtil.java?rev=1209632&r1=1209631&r2=1209632&view=diff
==============================================================================
--- labs/noggit/src/main/java/org/apache/noggit/JSONUtil.java (original)
+++ labs/noggit/src/main/java/org/apache/noggit/JSONUtil.java Fri Dec  2 18:48:42 2011
@@ -37,9 +37,19 @@ public class JSONUtil {
   public static String toJSON(Object o) {
     CharArr out = new CharArr();
     new JSONWriter(out).write(o);
-    return out.toString();
+   return out.toString();
   }
 
+  /**
+   * @param o  The object to convert to JSON
+   * @param indentSize  The number of space characters to use as an indent (default 2). 0=newlines but no spaces, -1=no indent at all.
+   * @return
+   */
+  public static String toJSON(Object o, int indentSize) {
+    CharArr out = new CharArr();
+    new JSONWriter(out,indentSize).write(o);
+    return out.toString();
+  }
 
   public static void writeNumber(int number, CharArr out) {
     out.write(Integer.toString(number));
@@ -92,7 +102,12 @@ public class JSONUtil {
           if (ch <= 0x1F) {
             unicodeEscape(ch,out);
           } else {
-            out.write(ch);
+            // These characters are valid JSON, but not valid JavaScript
+            if (ch=='\u2028' || ch=='\u2029') {
+              unicodeEscape(ch,out);
+            } else {
+              out.write(ch);
+            }
           }
       }
     }
@@ -117,7 +132,12 @@ public class JSONUtil {
           if (ch <= 0x1F) {
             unicodeEscape(ch,out);
           } else {
-            out.write(ch);
+            // These characters are valid JSON, but not valid JavaScript
+            if (ch=='\u2028' || ch=='\u2029') {
+              unicodeEscape(ch,out);
+            } else {
+              out.write(ch);
+            }
           }
       }
     }
Copied: labs/noggit/src/main/java/org/apache/noggit/JSONWriter.java (from r1099567, labs/noggit/src/main/java/org/apache/noggit/TextWriter.java)
URL: http://svn.apache.org/viewvc/labs/noggit/src/main/java/org/apache/noggit/JSONWriter.java?p2=labs/noggit/src/main/java/org/apache/noggit/JSONWriter.java&p1=labs/noggit/src/main/java/org/apache/noggit/TextWriter.java&r1=1099567&r2=1209632&rev=1209632&view=diff
==============================================================================
--- labs/noggit/src/main/java/org/apache/noggit/TextWriter.java (original)
+++ labs/noggit/src/main/java/org/apache/noggit/JSONWriter.java Fri Dec  2 18:48:42 2011
@@ -23,48 +23,40 @@ import java.util.*;
  * @author yonik
  * @version $Id$
  */
-public abstract class TextWriter {
-  public abstract void writeNull();
-
-  public abstract void writeString(CharSequence str);
-
-  public abstract void writeString(CharArr str);
-
-  public abstract void writeStringStart();
-  public abstract void writeStringChars(CharArr partialStr);
-  public abstract void writeStringEnd();
-
-  public abstract void write(long number);
-  public abstract void write(int number);
-  public void write(short number) { write ((int)number); }
-  public void write(byte number) { write((int)number); }
-
-  public abstract void write(double number);
-  public abstract void write(float number);
-
-  public abstract void write(boolean bool);
-
-
-  /** A char[] may be either be a string, or a list of characters.
-   * It's up to the implementation to decide.
+public class JSONWriter {
+  int level;
+  int indent;
+  final CharArr out;
+
+  /**
+   * @param out the CharArr to write the output to.
+   * @param indentSize  The number of space characters to use as an indent (default 2). 0=newlines but no spaces, -1=no indent at all.
    */
-  public abstract void write(char[] val);
-
-  public abstract void writeNumber(CharArr digits);
-  
-  public abstract void writePartialNumber(CharArr digits);
-
-  public abstract void startObject();
-
-  public abstract void endObject();
-
-  public abstract void startArray();
+  public JSONWriter(CharArr out, int indentSize) {
+    this.out = out;
+    this.indent = indentSize;
+  }
 
-  public abstract void endArray();
+  public JSONWriter(CharArr out) {
+    this(out, 2);
+  }
 
-  public abstract void writeValueSeparator();
+  public void setIndentSize(int indentSize) {
+    this.indent = indentSize;
+  }
 
-  public abstract void writeNameSeparator();
+  public void indent() {
+    if (indent >= 0) {
+      out.write('\n');
+      if (indent > 0) {
+        int spaces = level*indent;
+        out.reserve(spaces);
+        for (int i=0; i<spaces; i++) {
+          out.unsafeWrite(' ');
+        }
+      }
+    }
+  }
 
   public void write(Object o) {
     if (o == null) {
@@ -106,12 +98,17 @@ public abstract class TextWriter {
     } else if (o instanceof byte[]) {
       write((byte[])o);
     } else {
-      writeString(o.toString());
+      handleUnknownClass(o);
     }
   }
 
+  public void handleUnknownClass(Object o) {
+    writeString(out.toString());
+  }
+
   public void write(Map val) {
     startObject();
+    int sz = val.size();
     boolean first = true;
     for (Map.Entry entry : (Set<Map.Entry>)val.entrySet()) {
       if (first) {
@@ -119,6 +116,7 @@ public abstract class TextWriter {
       } else {
         writeValueSeparator();
       }
+      if (sz>1) indent();
       writeString(entry.getKey().toString());
       writeNameSeparator();
       write(entry.getValue());
@@ -128,6 +126,7 @@ public abstract class TextWriter {
 
   public void write(Collection val) {
     startArray();
+    int sz = val.size();
     boolean first = true;
     for (Object o : val) {
       if (first) {
@@ -135,6 +134,7 @@ public abstract class TextWriter {
       } else {
         writeValueSeparator();
       }
+      if (sz>1) indent();
       write(o);
     }
     endArray();
@@ -241,5 +241,94 @@ public abstract class TextWriter {
     endArray();
   }
 
+
+  public void write(short number) { write ((int)number); }
+  public void write(byte number) { write((int)number); }
+
+
+  public void writeNull() {
+    JSONUtil.writeNull(out);
+  }
+
+  public void writeString(CharSequence str) {
+    JSONUtil.writeString(str,0,str.length(),out);
+  }
+
+  public void writeString(CharArr str) {
+    JSONUtil.writeString(str,out);
+  }
+
+  public void writeStringStart() {
+    out.write('"');
+  }
+
+  public void writeStringChars(CharArr partialStr) {
+    JSONUtil.writeStringPart(partialStr.getArray(), partialStr.getStart(), partialStr.getEnd(), out);
+  }
+
+  public void writeStringEnd() {
+    out.write('"');
+  }
+
+  public void write(long number) {
+    JSONUtil.writeNumber(number,out);
+  }
+
+  public void write(int number) {
+    JSONUtil.writeNumber(number,out);
+  }
+
+  public void write(double number) {
+    JSONUtil.writeNumber(number,out);
+  }
+
+  public void write(float number) {
+    JSONUtil.writeNumber(number,out);
+  }
+
+  public void write(boolean bool) {
+    JSONUtil.writeBoolean(bool,out);
+  }
+
+  public void write(char[] val) {
+    JSONUtil.writeString(val, 0, val.length, out);
+  }
+
+  public void writeNumber(CharArr digits) {
+    out.write(digits);
+  }
+
+  public void writePartialNumber(CharArr digits) {
+    out.write(digits);
+  }
+
+  public void startObject() {
+    out.write('{');
+    level++;
+  }
+
+  public void endObject() {
+    out.write('}');
+    level--;
+  }
+
+  public void startArray() {
+    out.write('[');
+    level++;
+  }
+
+  public void endArray() {
+    out.write(']');
+    level--;
+  }
+
+  public void writeValueSeparator() {
+    out.write(',');
+  }
+
+  public void writeNameSeparator() {
+    out.write(':');
+  }
+
 }
 
Added: labs/noggit/src/test/java/org/apache/noggit/TestJSONWriter.java
URL: http://svn.apache.org/viewvc/labs/noggit/src/test/java/org/apache/noggit/TestJSONWriter.java?rev=1209632&view=auto
==============================================================================
--- labs/noggit/src/test/java/org/apache/noggit/TestJSONWriter.java (added)
+++ labs/noggit/src/test/java/org/apache/noggit/TestJSONWriter.java Fri Dec  2 18:48:42 2011
@@ -0,0 +1,66 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.noggit;
+
+import junit.framework.TestCase;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author yonik
+ * @version $Id$
+ */
+public class TestJSONWriter extends TestCase {
+
+  // note - TestObjectBuilder also exercises JSONWriter
+
+  public void test(String expected, Object val, int indent) throws IOException {
+    expected = expected.replace('\'','"');
+    String s1 = JSONUtil.toJSON(val, indent);
+    assertEquals(s1, expected);
+  }
+
+  public static List L(Object... lst) {
+     return Arrays.asList(lst);
+  }
+  public static Object[] A(Object... lst) {
+     return lst;
+  }
+  public static Map O(Object... lst) {
+    LinkedHashMap map = new LinkedHashMap();
+    for (int i=0; i<lst.length; i+=2) {
+      map.put(lst[i].toString(), lst[i+1]);
+    }
+    return map;
+  }
+
+  // NOTE: the specifics of indentation may change in the future!
+  public void testWriter() throws Exception {
+    test("[]",L(),2);
+    test("{}",O(),2);
+    test("[\n  10,\n  20]", L(10,20), 2);
+    test("{\n 'a':10,\n 'b':{\n  'c':20,\n  'd':30}}", O("a",10,"b",O("c",20,"d",30)), 1);
+
+    test("['\\r\\n\\u0000\\'']", L("\r\n\u0000\""),2);
+
+  }
+}
Propchange: labs/noggit/src/test/java/org/apache/noggit/TestJSONWriter.java
------------------------------------------------------------------------------
    svn:eol-style = native
Propchange: labs/noggit/src/test/java/org/apache/noggit/TestJSONWriter.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL
Modified: labs/noggit/src/test/java/org/apache/noggit/TestObjectBuilder.java
URL: http://svn.apache.org/viewvc/labs/noggit/src/test/java/org/apache/noggit/TestObjectBuilder.java?rev=1209632&r1=1209631&r2=1209632&view=diff
==============================================================================
--- labs/noggit/src/test/java/org/apache/noggit/TestObjectBuilder.java (original)
+++ labs/noggit/src/test/java/org/apache/noggit/TestObjectBuilder.java Fri Dec  2 18:48:42 2011
@@ -32,14 +32,14 @@ public class TestObjectBuilder extends T
     val = val.replace('\'','"');
     Object v = ObjectBuilder.fromJSON(val);
 
-    String s1 = JSONUtil.toJSON(v);
-    String s2 = JSONUtil.toJSON(expected);
+    String s1 = JSONUtil.toJSON(v,-1);
+    String s2 = JSONUtil.toJSON(expected,-1);
     assertEquals(s1, s2);
 
     // not make sure that it round-trips correctly
     JSONParser p2 = TestJSONParser.getParser(s1);
     Object v2 = ObjectBuilder.getVal(p2);
-    String s3 = JSONUtil.toJSON(v2);
+    String s3 = JSONUtil.toJSON(v2,-1);
     assertEquals(s1, s3);
   }
 
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@labs.apache.org
For additional commands, e-mail: commits-help@labs.apache.org
No comments:
Post a Comment