This is an automated email from the ASF dual-hosted git repository.

rmannibucau pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/johnzon.git


The following commit(s) were added to refs/heads/master by this push:
     new 7751e96  True object and array streaming (#74)
7751e96 is described below

commit 7751e96c4731a16a620a99e1165efac98db30566
Author: Csaba Varga <csab...@gmail.com>
AuthorDate: Sun Jul 11 18:09:29 2021 +0200

    True object and array streaming (#74)
    
    * Add tests for getArrayStream() and getObjectStream()
    
    * Implement lazy parsing for getArrayStream() and getObjectStream()
    
    Now these methods should behave in the spirit of the specification, only
    keeping the latest element in memory and parsing more data only as
    necessary.
    
    * Remove redundant else's
    
    * Extract anonymous spliterator implementations into static classes
    
    * Verify the event type we get in getObjectStream()
    
    * Add unit tests for parse errors in getArrayStream and getObjectStream
    
    * Make sure to close all parsers
---
 .../apache/johnzon/core/JohnzonJsonParserImpl.java | 78 +++++++++++++++++--
 .../johnzon/core/JsonParserStreamingTest.java      | 91 +++++++++++++++++++---
 2 files changed, 149 insertions(+), 20 deletions(-)

diff --git 
a/johnzon-core/src/main/java/org/apache/johnzon/core/JohnzonJsonParserImpl.java 
b/johnzon-core/src/main/java/org/apache/johnzon/core/JohnzonJsonParserImpl.java
index 6edde73..61cb708 100644
--- 
a/johnzon-core/src/main/java/org/apache/johnzon/core/JohnzonJsonParserImpl.java
+++ 
b/johnzon-core/src/main/java/org/apache/johnzon/core/JohnzonJsonParserImpl.java
@@ -17,9 +17,15 @@
 package org.apache.johnzon.core;
 
 
+import java.util.AbstractMap;
 import java.util.Collections;
 import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.function.Consumer;
 import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
 
 import javax.json.JsonArray;
 import javax.json.JsonObject;
@@ -132,20 +138,76 @@ public abstract class JohnzonJsonParserImpl implements 
JohnzonJsonParser {
         }
     }
 
+    private static class ArrayStreamSpliterator extends 
Spliterators.AbstractSpliterator<JsonValue> {
+
+        private final JohnzonJsonParserImpl parser;
+
+        ArrayStreamSpliterator(JohnzonJsonParserImpl parser) {
+            super(Long.MAX_VALUE, Spliterator.IMMUTABLE | Spliterator.NONNULL 
| Spliterator.ORDERED);
+            this.parser = parser;
+        }
+
+        @Override
+        public boolean tryAdvance(Consumer<? super JsonValue> action) {
+            Event next = parser.next();
+
+            if (next == Event.END_ARRAY) {
+                return false;
+            }
+
+            action.accept(parser.getValue());
+            return true;
+        }
+    }
+
     @Override
     public Stream<JsonValue> getArrayStream() {
-        //X TODO this implementation is very simplistic
-        //X I find it unintuitive what the spec intends here
-        //X we probably need to improve this
-        return getArray().stream();
+        Event current = current();
+        if (current != Event.START_ARRAY) {
+            throw new IllegalStateException(current + " doesn't support 
getArrayStream()");
+        }
+
+        return StreamSupport.stream(new ArrayStreamSpliterator(this), false);
+    }
+
+    private static class ObjectStreamSpliterator extends 
Spliterators.AbstractSpliterator<Map.Entry<String,JsonValue>> {
+        
+        private final JohnzonJsonParserImpl parser;
+
+        ObjectStreamSpliterator(JohnzonJsonParserImpl parser) {
+            super(Long.MAX_VALUE, Spliterator.IMMUTABLE | Spliterator.NONNULL 
| Spliterator.ORDERED);
+            this.parser = parser;
+        }
+
+        @Override
+        public boolean tryAdvance(Consumer<? super Entry<String, JsonValue>> 
action) {
+            Event next = parser.next();
+
+            if (next == Event.END_OBJECT) {
+                return false;
+            }
+
+            if (next != Event.KEY_NAME) {
+                throw new IllegalStateException("Expected key name event but 
got " + next + " instead.");
+            }
+
+            String key = parser.getString();
+            parser.next();
+            JsonValue value = parser.getValue();
+            action.accept(new AbstractMap.SimpleImmutableEntry<>(key, value));
+            return true;
+        }
+
     }
 
     @Override
     public Stream<Map.Entry<String, JsonValue>> getObjectStream() {
-        //X TODO this implementation is very simplistic
-        //X I find it unintuitive what the spec intends here
-        //X we probably need to improve this
-        return getObject().entrySet().stream();
+        Event current = current();
+        if (current != Event.START_OBJECT) {
+            throw new IllegalStateException(current + " doesn't support 
getObjectStream()");
+        }
+
+        return StreamSupport.stream(new ObjectStreamSpliterator(this), false);
     }
 
     @Override
diff --git 
a/johnzon-core/src/test/java/org/apache/johnzon/core/JsonParserStreamingTest.java
 
b/johnzon-core/src/test/java/org/apache/johnzon/core/JsonParserStreamingTest.java
index dfdff4e..42fd659 100644
--- 
a/johnzon-core/src/test/java/org/apache/johnzon/core/JsonParserStreamingTest.java
+++ 
b/johnzon-core/src/test/java/org/apache/johnzon/core/JsonParserStreamingTest.java
@@ -18,20 +18,26 @@
  */
 package org.apache.johnzon.core;
 
-import org.junit.Test;
+import static java.util.stream.Collectors.joining;
+import static org.junit.Assert.assertEquals;
 
-import javax.json.Json;
-import javax.json.stream.JsonParser;
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.StringReader;
 import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
 import java.util.stream.Collectors;
 import java.util.stream.IntStream;
 
-import static java.util.stream.Collectors.joining;
-import static org.junit.Assert.assertEquals;
+import javax.json.Json;
+import javax.json.JsonNumber;
+import javax.json.JsonString;
+import javax.json.stream.JsonParser;
+import javax.json.stream.JsonParsingException;
+
+import org.junit.Test;
 
 public class JsonParserStreamingTest {
     @Test
@@ -42,8 +48,9 @@ public class JsonParserStreamingTest {
                 "\t\"}").getBytes(StandardCharsets.UTF_8);
 
         final BufferStrategy.BufferProvider<char[]> bs = 
BufferStrategyFactory.valueOf("QUEUE").newCharProvider(len);
-        try (final InputStream stream = new ByteArrayInputStream(bytes)) {
-            final JsonStreamParserImpl impl = new JsonStreamParserImpl(stream, 
len, bs, bs, false);
+        try (final InputStream stream = new ByteArrayInputStream(bytes);
+                final JsonStreamParserImpl impl = new 
JsonStreamParserImpl(stream, len, bs, bs, false)) {
+
             while (impl.hasNext()) {
                 impl.next();
             }
@@ -114,11 +121,71 @@ public class JsonParserStreamingTest {
 
     private String parserAndConcat(String json) {
         StringReader sr = new StringReader(json);
-        JsonParser jsonParser = Json.createParser(sr);
 
-        String sum = jsonParser.getValueStream()
-                .map(v -> v.toString())
-                .collect(Collectors.joining(","));
-        return sum;
+        try (JsonParser jsonParser = Json.createParser(sr)) {
+            String sum = jsonParser.getValueStream()
+                    .map(v -> v.toString())
+                    .collect(Collectors.joining(","));
+            return sum;
+        }
+    }
+
+    @Test
+    public void testGetArrayStream() {
+        StringReader sr = new StringReader("[1,2,3,4,5,6]");
+
+        try (JsonParser jsonParser = Json.createParser(sr)) {
+            JsonParser.Event firstEvent = jsonParser.next();
+            assertEquals(JsonParser.Event.START_ARRAY, firstEvent);
+
+            int sum = jsonParser.getArrayStream()
+                    .mapToInt(v -> ((JsonNumber)v).intValue())
+                    .sum();
+            assertEquals(21, sum);
+        }
     }
+
+    @Test(expected = JsonParsingException.class)
+    public void testParseErrorInGetArrayStream() {
+        StringReader sr = new StringReader("[\"this is\":\"not an object\"]");
+
+        try (JsonParser jsonParser = Json.createParser(sr)) {
+            JsonParser.Event firstEvent = jsonParser.next();
+            assertEquals(JsonParser.Event.START_ARRAY, firstEvent);
+
+            jsonParser.getArrayStream().forEach(dummy -> {});
+        }
+    }
+
+    @Test
+    public void testGetObjectStream() {
+        StringReader sr = new 
StringReader("{\"foo\":\"bar\",\"baz\":\"quux\",\"something\":\"else\"}");
+
+        try (JsonParser jsonParser = Json.createParser(sr)) {
+            JsonParser.Event firstEvent = jsonParser.next();
+            assertEquals(JsonParser.Event.START_OBJECT, firstEvent);
+
+            Map<String, String> mappings = jsonParser.getObjectStream()
+                    .collect(Collectors.toMap(Map.Entry::getKey, e -> 
((JsonString)e.getValue()).getString()));
+
+            Map<String, String> expectedMappings = new HashMap<>();
+            expectedMappings.put("foo", "bar");
+            expectedMappings.put("baz", "quux");
+            expectedMappings.put("something", "else");
+            assertEquals(expectedMappings, mappings);
+        }
+    }
+
+    @Test(expected = JsonParsingException.class)
+    public void testParseErrorInGetObjectStream() {
+        StringReader sr = new StringReader("{42}");
+
+        try (JsonParser jsonParser = Json.createParser(sr)) {
+            JsonParser.Event firstEvent = jsonParser.next();
+            assertEquals(JsonParser.Event.START_OBJECT, firstEvent);
+
+            jsonParser.getObjectStream().forEach(dummy -> {});
+        }
+    }
+
 }

Reply via email to