You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by jw...@apache.org on 2015/12/12 00:30:17 UTC

[2/7] groovy git commit: Support for Array and Iterable not just Collection in StreamingJsonBuilder (closes #203)

Support for Array and Iterable not just Collection in StreamingJsonBuilder (closes #203)


Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/61651590
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/61651590
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/61651590

Branch: refs/heads/GROOVY_2_4_X
Commit: 616515909b80c3a01474251af96b8bac5fb44e82
Parents: 5e034d3
Author: graemerocher <gr...@gmail.com>
Authored: Wed Dec 2 11:13:25 2015 +0100
Committer: John Wagenleitner <jw...@apache.org>
Committed: Fri Dec 11 14:39:57 2015 -0800

----------------------------------------------------------------------
 .../src/main/java/groovy/json/JsonOutput.java   |  18 +-
 .../java/groovy/json/StreamingJsonBuilder.java  | 171 +++++++++++++------
 .../groovy/json/StreamingJsonBuilderTest.groovy |  45 +++++
 3 files changed, 175 insertions(+), 59 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/groovy/blob/61651590/subprojects/groovy-json/src/main/java/groovy/json/JsonOutput.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/JsonOutput.java b/subprojects/groovy-json/src/main/java/groovy/json/JsonOutput.java
index b9a4e4b..8bee49d 100644
--- a/subprojects/groovy-json/src/main/java/groovy/json/JsonOutput.java
+++ b/subprojects/groovy-json/src/main/java/groovy/json/JsonOutput.java
@@ -305,10 +305,7 @@ public class JsonOutput {
             } else if (Enum.class.isAssignableFrom(objectClass)) {
                 buffer.addQuoted(((Enum<?>) object).name());
             }else if (File.class.isAssignableFrom(objectClass)){
-                Map<?, ?> properties = DefaultGroovyMethods.getProperties(object);
-                properties.remove("class");
-                properties.remove("declaringClass");
-                properties.remove("metaClass");
+                Map<?, ?> properties = getObjectProperties(object);
                 //Clean up all recursive references to File objects
                 Iterator<? extends Map.Entry<?, ?>> iterator = properties.entrySet().iterator();
                 while(iterator.hasNext()){
@@ -320,15 +317,20 @@ public class JsonOutput {
 
                 writeMap(properties, buffer);
             } else {
-                Map<?, ?> properties = DefaultGroovyMethods.getProperties(object);
-                properties.remove("class");
-                properties.remove("declaringClass");
-                properties.remove("metaClass");
+                Map<?, ?> properties = getObjectProperties(object);
                 writeMap(properties, buffer);
             }
         }
     }
 
+    private static Map<?, ?> getObjectProperties(Object object) {
+        Map<?, ?> properties = DefaultGroovyMethods.getProperties(object);
+        properties.remove("class");
+        properties.remove("declaringClass");
+        properties.remove("metaClass");
+        return properties;
+    }
+
 
     /**
      * Serializes any char sequence and writes it into specified buffer.

http://git-wip-us.apache.org/repos/asf/groovy/blob/61651590/subprojects/groovy-json/src/main/java/groovy/json/StreamingJsonBuilder.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/StreamingJsonBuilder.java b/subprojects/groovy-json/src/main/java/groovy/json/StreamingJsonBuilder.java
index f96d8f6..f37789c 100644
--- a/subprojects/groovy-json/src/main/java/groovy/json/StreamingJsonBuilder.java
+++ b/subprojects/groovy-json/src/main/java/groovy/json/StreamingJsonBuilder.java
@@ -205,10 +205,8 @@ public class StreamingJsonBuilder extends GroovyObjectSupport {
      * @param coll a collection
      * @param c a closure used to convert the objects of coll
      */
-    public Object call(Collection coll, @DelegatesTo(StreamingJsonDelegate.class) Closure c) throws IOException {
-        StreamingJsonDelegate.writeCollectionWithClosure(writer, coll, c);
-
-        return null;
+    public Object call(Iterable coll, @DelegatesTo(StreamingJsonDelegate.class) Closure c) throws IOException {
+        return StreamingJsonDelegate.writeCollectionWithClosure(writer, coll, c);
     }
 
     /**
@@ -287,7 +285,7 @@ public class StreamingJsonBuilder extends GroovyObjectSupport {
      * @param coll a collection
      * @param c a closure used to convert the objects of coll
      */
-    public void call(String name, Collection coll, @DelegatesTo(StreamingJsonDelegate.class) Closure c) throws IOException {
+    public void call(String name, Iterable coll, @DelegatesTo(StreamingJsonDelegate.class) Closure c) throws IOException {
         writer.write(JsonOutput.OPEN_BRACE);
         writer.write(JsonOutput.toJson(name));
         writer.write(JsonOutput.COLON);
@@ -405,28 +403,46 @@ public class StreamingJsonBuilder extends GroovyObjectSupport {
         if (args != null && Object[].class.isAssignableFrom(args.getClass())) {
             Object[] arr = (Object[]) args;
             try {
-                if (arr.length == 0) {
-                    call(name);
-                } else if (arr.length == 1) {
-                    if (arr[0] instanceof Closure) {
-                        final Closure callable = (Closure) arr[0];
-                        call(name, callable);
-                    } else if (arr[0] instanceof Map) {
-                        final Map<String, Map> map = Collections.singletonMap(name, (Map) arr[0]);
-                        call(map);
-                    } else {
+                switch(arr.length) {
+                    case 0:
+                        call(name);
+                    break;
+                    case 1:
+                        if (arr[0] instanceof Closure) {
+                            final Closure callable = (Closure) arr[0];
+                            call(name, callable);
+                        } else if (arr[0] instanceof Map) {
+                            final Map<String, Map> map = Collections.singletonMap(name, (Map) arr[0]);
+                            call(map);
+                        } else {
+                            notExpectedArgs = true;
+                        }
+                    break;
+                    case 2:
+                        final Object first = arr[0];
+                        final Object second = arr[1];
+                        final boolean isClosure = second instanceof Closure;
+
+                        if(isClosure && first instanceof Map ) {
+                            final Closure callable = (Closure) second;
+                            call(name, (Map)first, callable);
+                        }
+                        else if(isClosure && first instanceof Iterable) {
+                            final Iterable coll = (Iterable) first;
+                            final Closure callable = (Closure) second;
+                            call(name, coll, callable);
+                        }
+                        else if(isClosure && first.getClass().isArray()) {
+                            final Iterable coll = Arrays.asList((Object[])first);
+                            final Closure callable = (Closure) second;
+                            call(name, coll, callable);
+                        }
+                        else {
+                            notExpectedArgs = true;
+                        }
+                    break;
+                    default:
                         notExpectedArgs = true;
-                    }
-                } else if (arr.length == 2 && arr[0] instanceof Map && arr[1] instanceof Closure) {
-                    Map map = (Map) arr[0];
-                    final Closure callable = (Closure) arr[1];
-                    call(name, map, callable);
-                } else if (StreamingJsonDelegate.isCollectionWithClosure(arr)) {
-                    final Collection coll = (Collection) arr[0];
-                    final Closure callable = (Closure) arr[1];
-                    call(name, coll, callable);
-                } else {
-                    notExpectedArgs = true;
                 }
             } catch (IOException ioe) {
                 throw new JsonException(ioe);
@@ -447,9 +463,9 @@ public class StreamingJsonBuilder extends GroovyObjectSupport {
      */
     public static class StreamingJsonDelegate extends GroovyObjectSupport {
 
-        private Writer writer;
-        private boolean first;
-        private State state;
+        protected final Writer writer;
+        protected boolean first;
+        protected State state;
 
 
         public StreamingJsonDelegate(Writer w, boolean first) {
@@ -457,21 +473,42 @@ public class StreamingJsonBuilder extends GroovyObjectSupport {
             this.first = first;
         }
 
+        public Writer getWriter() {
+            return writer;
+        }
+
         public Object invokeMethod(String name, Object args) {
             if (args != null && Object[].class.isAssignableFrom(args.getClass())) {
                 try {
                     Object[] arr = (Object[]) args;
 
-                    if (arr.length == 1) {
-                        final Object value = arr[0];
-                        call(name, value);
-                    } else if (isCollectionWithClosure(arr)) {
-                        final Collection coll = (Collection) arr[0];
-                        final Closure callable = (Closure) arr[1];
-                        call(name, coll, callable);
-                    } else {
-                        final List<Object> list = Arrays.asList(arr);
-                        call(name, list);
+                    final int len = arr.length;
+                    switch (len) {
+                        case 1:
+                            final Object value = arr[0];
+                            call(name, value);
+                            return null;
+                        case 2:
+                            if(arr[len -1] instanceof Closure) {
+                                final Object obj = arr[0];
+                                final Closure callable = (Closure) arr[1];
+                                if(obj instanceof Iterable) {
+                                    call(name, (Iterable)obj, callable);
+                                    return null;
+                                }
+                                else if(obj.getClass().isArray()) {
+                                    call(name, Arrays.asList( (Object[])obj), callable);
+                                    return null;
+                                }
+                                else {
+                                    call(name, obj, callable);
+                                    return null;
+                                }
+                            }
+                        default:
+                            final List<Object> list = Arrays.asList(arr);
+                            call(name, list);
+
                     }
                 } catch (IOException ioe) {
                     throw new JsonException(ioe);
@@ -528,7 +565,7 @@ public class StreamingJsonBuilder extends GroovyObjectSupport {
          * @param coll a collection
          * @param c a closure used to convert the objects of coll
          */
-        public void call(String name, Collection coll, Closure c) throws IOException {
+        public void call(String name, Iterable coll, Closure c) throws IOException {
             writeName(name);
             writeObjects(coll, c);
         }
@@ -546,6 +583,33 @@ public class StreamingJsonBuilder extends GroovyObjectSupport {
         }
 
         /**
+         * Writes the name and value of a JSON attribute
+         *
+         * @param name The attribute name
+         * @param value The value
+         * @throws IOException
+         */
+        public void call(String name, Object value, @DelegatesTo(StreamingJsonDelegate.class) Closure callable) throws IOException {
+            writeName(name);
+            verifyValue();
+            writeObject(writer, value, callable);
+        }
+        /**
+         * Writes the name and another JSON boject
+         *
+         * @param name The attribute name
+         * @param value The value
+         * @throws IOException
+         */
+        public void call(String name,@DelegatesTo(StreamingJsonDelegate.class) Closure value) throws IOException {
+            writeName(name);
+            verifyValue();
+            writer.write(JsonOutput.OPEN_BRACE);
+            StreamingJsonDelegate.cloneDelegateAndGetContent(writer, value);
+            writer.write(JsonOutput.CLOSE_BRACE);
+
+        }
+        /**
          * Writes an unescaped value. Note: can cause invalid JSON if passed JSON is invalid
          *
          * @param name The attribute name
@@ -558,12 +622,12 @@ public class StreamingJsonBuilder extends GroovyObjectSupport {
         }
 
 
-        private void writeObjects(Collection coll, @DelegatesTo(StreamingJsonDelegate.class) Closure c) throws IOException {
+        private void writeObjects(Iterable coll, @DelegatesTo(StreamingJsonDelegate.class) Closure c) throws IOException {
             verifyValue();
             writeCollectionWithClosure(writer, coll, c);
         }
 
-        private void verifyValue() {
+        protected void verifyValue() {
             if(state == State.VALUE) {
                 throw new IllegalStateException("Cannot write value when value has just been written. Write a name first!");
             }
@@ -573,7 +637,7 @@ public class StreamingJsonBuilder extends GroovyObjectSupport {
         }
 
 
-        private void writeName(String name) throws IOException {
+        protected void writeName(String name) throws IOException {
             if(state == State.NAME) {
                 throw new IllegalStateException("Cannot write a name when a name has just been written. Write a value first!");
             }
@@ -589,21 +653,21 @@ public class StreamingJsonBuilder extends GroovyObjectSupport {
             writer.write(JsonOutput.COLON);
         }
 
-        private void writeValue(Object value) throws IOException {
+        protected void writeValue(Object value) throws IOException {
             verifyValue();
             writer.write(JsonOutput.toJson(value));
         }
 
-        private void writeArray(List<Object> list) throws IOException {
+        protected void writeArray(List<Object> list) throws IOException {
             verifyValue();
             writer.write(JsonOutput.toJson(list));
         }
 
         public static boolean isCollectionWithClosure(Object[] args) {
-            return args.length == 2 && args[0] instanceof Collection && args[1] instanceof Closure;
+            return args.length == 2 && args[0] instanceof Iterable && args[1] instanceof Closure;
         }
 
-        public static Object writeCollectionWithClosure(Writer writer, Collection coll, Closure closure) throws IOException {
+        public static Object writeCollectionWithClosure(Writer writer, Iterable coll, Closure closure) throws IOException {
             writer.write(JsonOutput.OPEN_BRACKET);
             boolean first = true;
             for (Object it : coll) {
@@ -613,16 +677,21 @@ public class StreamingJsonBuilder extends GroovyObjectSupport {
                     first = false;
                 }
 
-                writer.write(JsonOutput.OPEN_BRACE);
-                curryDelegateAndGetContent(writer, closure, it);
-                writer.write(JsonOutput.CLOSE_BRACE);
+                writeObject(writer, it, closure);
             }
             writer.write(JsonOutput.CLOSE_BRACKET);
 
             return writer;
         }
 
-        public static void cloneDelegateAndGetContent(Writer w, Closure c) {
+        private static void writeObject(Writer writer, Object object, Closure closure) throws IOException {
+            writer.write(JsonOutput.OPEN_BRACE);
+            curryDelegateAndGetContent(writer, closure, object);
+            writer.write(JsonOutput.CLOSE_BRACE);
+        }
+
+        public static void cloneDelegateAndGetContent(Writer w, Closure c)
+        {
             cloneDelegateAndGetContent(w, c, true);
         }
 

http://git-wip-us.apache.org/repos/asf/groovy/blob/61651590/subprojects/groovy-json/src/test/groovy/groovy/json/StreamingJsonBuilderTest.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-json/src/test/groovy/groovy/json/StreamingJsonBuilderTest.groovy b/subprojects/groovy-json/src/test/groovy/groovy/json/StreamingJsonBuilderTest.groovy
index 19f4477..9bae655 100644
--- a/subprojects/groovy-json/src/test/groovy/groovy/json/StreamingJsonBuilderTest.groovy
+++ b/subprojects/groovy-json/src/test/groovy/groovy/json/StreamingJsonBuilderTest.groovy
@@ -231,6 +231,51 @@ class StreamingJsonBuilderTest extends GroovyTestCase {
         }
     }
 
+    void testIterableAndClosure() {
+        def authors = [new Author(name: "Guillaume"), new Author(name: "Jochen"), new Author(name: "Paul")]
+        Iterable it = [iterator:{->
+            authors.iterator()
+        }] as Iterable
+        new StringWriter().with { w ->
+            def json = new StreamingJsonBuilder(w)
+            json it, { Author author ->
+                name author.name
+            }
+
+            assert w.toString() == '[{"name":"Guillaume"},{"name":"Jochen"},{"name":"Paul"}]'
+        }
+    }
+
+    void testMethodWithIterableAndClosure() {
+        def authors = [new Author(name: "Guillaume"), new Author(name: "Jochen"), new Author(name: "Paul")]
+        Iterable it = [iterator:{->
+            authors.iterator()
+        }] as Iterable
+
+        new StringWriter().with { w ->
+            def json = new StreamingJsonBuilder(w)
+            json.authors it, { Author author ->
+                name author.name
+            }
+
+            assert w.toString() == '{"authors":[{"name":"Guillaume"},{"name":"Jochen"},{"name":"Paul"}]}'
+        }
+    }
+
+    void testMethodWithArrayAndClosure() {
+        def authors = [new Author(name: "Guillaume"), new Author(name: "Jochen"), new Author(name: "Paul")]
+
+
+        new StringWriter().with { w ->
+            def json = new StreamingJsonBuilder(w)
+            json.authors authors as Author[], { Author author ->
+                name author.name
+            }
+
+            assert w.toString() == '{"authors":[{"name":"Guillaume"},{"name":"Jochen"},{"name":"Paul"}]}'
+        }
+    }
+
     void testMethodWithCollectionAndClosure() {
         def authors = [new Author(name: "Guillaume"), new Author(name: "Jochen"), new Author(name: "Paul")]