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 <[email protected]>
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 -> {});
+ }
+ }
+
}