diff --git a/impl/src/main/java/org/eclipse/parsson/JsonParserImpl.java b/impl/src/main/java/org/eclipse/parsson/JsonParserImpl.java index 454f7b3..6313e65 100644 --- a/impl/src/main/java/org/eclipse/parsson/JsonParserImpl.java +++ b/impl/src/main/java/org/eclipse/parsson/JsonParserImpl.java @@ -22,11 +22,16 @@ import java.io.Reader; import java.math.BigDecimal; import java.nio.charset.Charset; +import java.util.AbstractMap; import java.util.Map; import java.util.NoSuchElementException; import java.util.Objects; +import java.util.Spliterator; +import java.util.Spliterators; +import java.util.function.Consumer; import java.util.function.Function; import java.util.stream.Stream; +import java.util.stream.StreamSupport; import jakarta.json.JsonArray; import jakarta.json.JsonArrayBuilder; @@ -58,24 +63,20 @@ public class JsonParserImpl implements JsonParser { private final JsonContext jsonContext; - private final JsonParserStreamCreator streamCreator = new JsonParserStreamCreator(this, true, () -> currentEvent, - () -> currentContext instanceof NoneContext); - - - JsonParserImpl(Reader reader, JsonContext jsonContext) { + public JsonParserImpl(Reader reader, JsonContext jsonContext) { this.jsonContext = jsonContext; stack = new Stack(jsonContext.depthLimit()); this.tokenizer = new JsonTokenizer(reader, jsonContext); } - JsonParserImpl(InputStream in, JsonContext jsonContext) { + public JsonParserImpl(InputStream in, JsonContext jsonContext) { this.jsonContext = jsonContext; stack = new Stack(jsonContext.depthLimit()); UnicodeDetectingInputStream uin = new UnicodeDetectingInputStream(in); this.tokenizer = new JsonTokenizer(new InputStreamReader(uin, uin.getCharset()), jsonContext); } - JsonParserImpl(InputStream in, Charset encoding, JsonContext jsonContext) { + public JsonParserImpl(InputStream in, Charset encoding, JsonContext jsonContext) { this.jsonContext = jsonContext; stack = new Stack(jsonContext.depthLimit()); this.tokenizer = new JsonTokenizer(new InputStreamReader(in, encoding), jsonContext); @@ -177,17 +178,103 @@ public JsonValue getValue() { @Override public Stream getArrayStream() { - return streamCreator.getArrayStream(); + if (currentEvent != Event.START_ARRAY) { + throw new IllegalStateException( + JsonMessages.PARSER_GETARRAY_ERR(currentEvent)); + } + Spliterator spliterator = + new Spliterators.AbstractSpliterator(Long.MAX_VALUE, Spliterator.ORDERED) { + @Override + public Spliterator trySplit() { + return null; + } + + @Override + public boolean tryAdvance(Consumer action) { + if (action == null) { + throw new NullPointerException(); + } + if (!hasNext()) { + return false; + } + if (next() == JsonParser.Event.END_ARRAY) { + return false; + } + action.accept(getValue()); + return true; + } + }; + return StreamSupport.stream(spliterator, false); } @Override public Stream> getObjectStream() { - return streamCreator.getObjectStream(); + if (currentEvent != Event.START_OBJECT) { + throw new IllegalStateException( + JsonMessages.PARSER_GETOBJECT_ERR(currentEvent)); + } + Spliterator> spliterator = + new Spliterators.AbstractSpliterator>(Long.MAX_VALUE, Spliterator.ORDERED) { + @Override + public Spliterator> trySplit() { + return null; + } + + @Override + public boolean tryAdvance(Consumer> action) { + if (action == null) { + throw new NullPointerException(); + } + if (!hasNext()) { + return false; + } + JsonParser.Event e = next(); + if (e == JsonParser.Event.END_OBJECT) { + return false; + } + if (e != JsonParser.Event.KEY_NAME) { + throw new JsonException(JsonMessages.INTERNAL_ERROR()); + } + String key = getString(); + if (!hasNext()) { + throw new JsonException(JsonMessages.INTERNAL_ERROR()); + } + next(); + JsonValue value = getValue(); + action.accept(new AbstractMap.SimpleImmutableEntry<>(key, value)); + return true; + } + }; + return StreamSupport.stream(spliterator, false); } @Override public Stream getValueStream() { - return streamCreator.getValueStream(); + if (! (currentContext instanceof NoneContext)) { + throw new IllegalStateException( + JsonMessages.PARSER_GETVALUESTREAM_ERR()); + } + Spliterator spliterator = + new Spliterators.AbstractSpliterator(Long.MAX_VALUE, Spliterator.ORDERED) { + @Override + public Spliterator trySplit() { + return null; + } + + @Override + public boolean tryAdvance(Consumer action) { + if (action == null) { + throw new NullPointerException(); + } + if (!hasNext()) { + return false; + } + next(); + action.accept(getValue()); + return true; + } + }; + return StreamSupport.stream(spliterator, false); } @Override diff --git a/impl/src/main/java/org/eclipse/parsson/JsonParserStreamCreator.java b/impl/src/main/java/org/eclipse/parsson/JsonParserStreamCreator.java deleted file mode 100644 index d38e4dc..0000000 --- a/impl/src/main/java/org/eclipse/parsson/JsonParserStreamCreator.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0, which is available at - * http://www.eclipse.org/legal/epl-2.0. - * - * This Source Code may also be made available under the following Secondary - * Licenses when the conditions for such availability set forth in the - * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, - * version 2 with the GNU Classpath Exception, which is available at - * https://www.gnu.org/software/classpath/license.html. - * - * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 - */ - -package org.eclipse.parsson; - -import java.util.AbstractMap; -import java.util.Map; -import java.util.Objects; -import java.util.function.Supplier; -import java.util.stream.Stream; - -import jakarta.json.JsonException; -import jakarta.json.JsonValue; -import jakarta.json.stream.JsonParser; -import jakarta.json.stream.JsonParser.Event; - -class JsonParserStreamCreator { - - private final JsonParser parser; - private final boolean nextBeforeCreationOfValueStream; - private final Supplier currenEventSupplier; - private final Supplier canProduceValueStream; - - JsonParserStreamCreator(JsonParser parser, boolean nextBeforeCreationOfValueStream, Supplier currenEventSupplier, - Supplier canProduceValueStream) { - - this.parser = Objects.requireNonNull(parser); - this.nextBeforeCreationOfValueStream = nextBeforeCreationOfValueStream; - this.currenEventSupplier = Objects.requireNonNull(currenEventSupplier); - this.canProduceValueStream = Objects.requireNonNull(canProduceValueStream); - } - - /** - * Creates new {@link Stream} from values from {@link Supplier}. The stream delivers the values as long as supplier delivers non-null values - * - * @param supplier supplier of the values - * @param type of the values which are delivered by the supplier and the stream - * @return stream of values from given supplier - */ - private static Stream streamFromSupplier(Supplier supplier) { - return StreamCreator.iterate(Objects.requireNonNull(supplier).get(), Objects::nonNull, value -> supplier.get()); - } - - public Stream getArrayStream() { - if (currenEventSupplier.get() == Event.START_ARRAY) { - return streamFromSupplier(() -> (parser.hasNext() && parser.next() != Event.END_ARRAY) ? parser.getValue() : null); - } else { - throw new IllegalStateException(JsonMessages.PARSER_GETARRAY_ERR(parser.currentEvent())); - } - } - - public Stream> getObjectStream() { - if (currenEventSupplier.get() == Event.START_OBJECT) { - return streamFromSupplier(() -> { - if (!parser.hasNext()) { - return null; - } - Event e = parser.next(); - if (e == Event.END_OBJECT) { - return null; - } else if (e != Event.KEY_NAME) { - throw new JsonException(JsonMessages.INTERNAL_ERROR()); - } else { - String key = parser.getString(); - if (!parser.hasNext()) { - throw new JsonException(JsonMessages.INTERNAL_ERROR()); - } else { - parser.next(); - return new AbstractMap.SimpleImmutableEntry<>(key, parser.getValue()); - } - } - }); - } else { - throw new IllegalStateException(JsonMessages.PARSER_GETOBJECT_ERR(parser.currentEvent())); - } - } - - public Stream getValueStream() { - if (canProduceValueStream.get()) { - if (nextBeforeCreationOfValueStream) { - parser.next(); - } - - return streamFromSupplier(() -> { - if (parser.hasNext()) { - return parser.getValue(); - } else { - return null; - } - }); - } else { - throw new IllegalStateException(JsonMessages.PARSER_GETVALUESTREAM_ERR()); - } - } -} diff --git a/impl/src/main/java/org/eclipse/parsson/JsonStructureParser.java b/impl/src/main/java/org/eclipse/parsson/JsonStructureParser.java index d59d982..c311698 100644 --- a/impl/src/main/java/org/eclipse/parsson/JsonStructureParser.java +++ b/impl/src/main/java/org/eclipse/parsson/JsonStructureParser.java @@ -26,7 +26,6 @@ import java.util.Map; import java.util.NoSuchElementException; import java.util.function.Function; -import java.util.stream.Stream; /** * {@link JsonParser} implementation on top of JsonArray/JsonObject @@ -35,13 +34,9 @@ */ class JsonStructureParser implements JsonParser { - private Scope current; + private Scope current; private Event state; - private final Deque> scopeStack = new ArrayDeque<>(); - - //JsonParserImpl delivers the whole object - so we have to call next() before creation of the stream - private final JsonParserStreamCreator streamCreator = new JsonParserStreamCreator(this, true, () -> state, scopeStack::isEmpty); - + private final Deque scopeStack = new ArrayDeque<>(); JsonStructureParser(JsonArray array) { current = new ArrayScope(array); @@ -97,55 +92,6 @@ public JsonLocation getLocation() { return JsonLocationImpl.UNKNOWN; } - @Override - public JsonObject getObject() { - if (state != Event.START_OBJECT) { - throw new IllegalStateException( - JsonMessages.PARSER_GETOBJECT_ERR(state)); - } - if (current == null) { - throw new NoSuchElementException(JsonMessages.INTERNAL_ERROR()); - } - state = Event.END_OBJECT; - return current.getJsonValue().asJsonObject(); - - } - - @Override - public JsonValue getValue() { - if (current == null) { - throw new IllegalStateException(JsonMessages.INTERNAL_ERROR()); - } - - switch (state) { - case START_OBJECT: - return getObject(); - case START_ARRAY: - return getArray(); - case KEY_NAME: - return Json.createValue(((ObjectScope)current).key); - case END_OBJECT: - case END_ARRAY: - throw new IllegalStateException(JsonMessages.INTERNAL_ERROR()); - default: - return current.getJsonValue(); - } - } - - @Override - public JsonArray getArray() { - if (state != Event.START_ARRAY) { - throw new IllegalStateException( - JsonMessages.PARSER_GETARRAY_ERR(state)); - } - Scope topOfTheStack = scopeStack.isEmpty() ? current : scopeStack.pop(); - if (topOfTheStack == null) { - throw new NoSuchElementException(JsonMessages.INTERNAL_ERROR()); - } - state = Event.END_ARRAY; - return topOfTheStack.getJsonValue().asJsonArray(); - } - @Override public boolean hasNext() { return !((state == Event.END_OBJECT || state == Event.END_ARRAY) && scopeStack.isEmpty()); @@ -203,37 +149,59 @@ public void close() { // no-op } - @Override - public Event currentEvent() { - return state; - } - - @Override - public Stream getArrayStream() { - return streamCreator.getArrayStream(); - } - - @Override - public Stream> getObjectStream() { - return streamCreator.getObjectStream(); - } - - @Override - public Stream getValueStream() { - return streamCreator.getValueStream(); - } - @Override public void skipObject() { if (current instanceof ObjectScope) { - state = Event.END_OBJECT; + int depth = 1; + do { + if (state == Event.KEY_NAME) { + state = getState(current.getJsonValue()); + switch (state) { + case START_OBJECT: + depth++; + break; + case END_OBJECT: + depth--; + break; + default: + //no-op + } + } else { + if (current.hasNext()) { + current.next(); + state = Event.KEY_NAME; + } else { + state = Event.END_OBJECT; + depth--; + } + } + } while (state != Event.END_OBJECT && depth > 0); } } @Override public void skipArray() { if (current instanceof ArrayScope) { - state = Event.END_ARRAY; + int depth = 1; + do { + if (current.hasNext()) { + current.next(); + state = getState(current.getJsonValue()); + switch (state) { + case START_ARRAY: + depth++; + break; + case END_ARRAY: + depth--; + break; + default: + //no-op + } + } else { + state = Event.END_ARRAY; + depth--; + } + } while (!(state == Event.END_ARRAY && depth == 0)); } } @@ -258,13 +226,10 @@ private static Event getState(JsonValue value) { } } - private static abstract class Scope implements Iterator { - @Override - public final void remove() {throw new UnsupportedOperationException(); } - + private static abstract class Scope implements Iterator { abstract JsonValue getJsonValue(); - static Scope createScope(JsonValue value) { + static Scope createScope(JsonValue value) { if (value instanceof JsonArray) { return new ArrayScope((JsonArray)value); } else if (value instanceof JsonObject) { @@ -274,7 +239,7 @@ static Scope createScope(JsonValue value) { } } - private static class ArrayScope extends Scope { + private static class ArrayScope extends Scope { private final Iterator it; private JsonValue value; @@ -293,6 +258,11 @@ public JsonValue next() { return value; } + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + @Override JsonValue getJsonValue() { return value; @@ -300,14 +270,12 @@ JsonValue getJsonValue() { } - private static class ObjectScope extends Scope> { - private final JsonObject object; + private static class ObjectScope extends Scope { private final Iterator> it; private JsonValue value; private String key; ObjectScope(JsonObject object) { - this.object = object; this.it = object.entrySet().iterator(); } @@ -324,9 +292,14 @@ public Map.Entry next() { return next; } + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + @Override JsonValue getJsonValue() { - return value == null ? object : value; + return value; } } diff --git a/impl/src/main/java/org/eclipse/parsson/StreamCreator.java b/impl/src/main/java/org/eclipse/parsson/StreamCreator.java deleted file mode 100644 index cf391d1..0000000 --- a/impl/src/main/java/org/eclipse/parsson/StreamCreator.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (c) 2023 Oracle and/or its affiliates. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0, which is available at - * http://www.eclipse.org/legal/epl-2.0. - * - * This Source Code may also be made available under the following Secondary - * Licenses when the conditions for such availability set forth in the - * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, - * version 2 with the GNU Classpath Exception, which is available at - * https://www.gnu.org/software/classpath/license.html. - * - * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 - */ - -package org.eclipse.parsson; - -import java.util.Objects; -import java.util.Spliterator; -import java.util.Spliterators; -import java.util.function.Consumer; -import java.util.function.Predicate; -import java.util.function.UnaryOperator; -import java.util.stream.Stream; -import java.util.stream.StreamSupport; - -/** - * Copy of public static Stream Stream#iterate(T seed, Predicate hasNext, UnaryOperator next) - * because the last is since Java 9 - */ -class StreamCreator { - /** - * Returns a sequential ordered {@code Stream} produced by iterative - * application of the given {@code next} function to an initial element, - * conditioned on satisfying the given {@code hasNext} predicate. The - * stream terminates as soon as the {@code hasNext} predicate returns false. - * - *

{@code Stream.iterate} should produce the same sequence of elements as - * produced by the corresponding for-loop: - *

{@code
-     *     for (T index=seed; hasNext.test(index); index = next.apply(index)) {
-     *         ...
-     *     }
-     * }
- * - *

The resulting sequence may be empty if the {@code hasNext} predicate - * does not hold on the seed value. Otherwise the first element will be the - * supplied {@code seed} value, the next element (if present) will be the - * result of applying the {@code next} function to the {@code seed} value, - * and so on iteratively until the {@code hasNext} predicate indicates that - * the stream should terminate. - * - *

The action of applying the {@code hasNext} predicate to an element - * happens-before - * the action of applying the {@code next} function to that element. The - * action of applying the {@code next} function for one element - * happens-before the action of applying the {@code hasNext} - * predicate for subsequent elements. For any given element an action may - * be performed in whatever thread the library chooses. - * - * @param the type of stream elements - * @param seed the initial element - * @param hasNext a predicate to apply to elements to determine when the - * stream must terminate. - * @param next a function to be applied to the previous element to produce - * a new element - * @return a new sequential {@code Stream} - * @since 9 - */ - public static Stream iterate(T seed, Predicate hasNext, UnaryOperator next) { - Objects.requireNonNull(next); - Objects.requireNonNull(hasNext); - Spliterator spliterator = new Spliterators.AbstractSpliterator(Long.MAX_VALUE, - Spliterator.ORDERED | Spliterator.IMMUTABLE) { - T prev; - boolean started, finished; - - @Override - public boolean tryAdvance(Consumer action) { - Objects.requireNonNull(action); - if (finished) - return false; - T t; - if (started) - t = next.apply(prev); - else { - t = seed; - started = true; - } - if (!hasNext.test(t)) { - prev = null; - finished = true; - return false; - } - action.accept(prev = t); - return true; - } - - @Override - public void forEachRemaining(Consumer action) { - Objects.requireNonNull(action); - if (finished) - return; - finished = true; - T t = started ? next.apply(prev) : seed; - prev = null; - while (hasNext.test(t)) { - action.accept(t); - t = next.apply(t); - } - } - }; - return StreamSupport.stream(spliterator, false); - } -} diff --git a/impl/src/test/java/org/eclipse/parsson/tests/JsonParserTest.java b/impl/src/test/java/org/eclipse/parsson/tests/JsonParserTest.java index 6ac8c21..556512a 100644 --- a/impl/src/test/java/org/eclipse/parsson/tests/JsonParserTest.java +++ b/impl/src/test/java/org/eclipse/parsson/tests/JsonParserTest.java @@ -16,6 +16,10 @@ package org.eclipse.parsson.tests; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + import java.io.ByteArrayInputStream; import java.io.InputStream; import java.io.InputStreamReader; @@ -27,35 +31,21 @@ import jakarta.json.stream.JsonParser; import jakarta.json.stream.JsonParser.Event; import jakarta.json.stream.JsonParserFactory; - import java.math.BigDecimal; -import java.math.BigInteger; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.EnumSet; import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.NoSuchElementException; -import java.util.Objects; import java.util.Random; import java.util.Scanner; -import java.util.stream.Collector; -import java.util.stream.Collectors; - import jakarta.json.stream.JsonParsingException; import org.eclipse.parsson.JsonParserFixture; import org.eclipse.parsson.api.BufferPool; -import org.hamcrest.Matcher; -import org.hamcrest.MatcherAssert; -import org.hamcrest.Matchers; import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.function.Executable; /** * JsonParser Tests @@ -66,22 +56,6 @@ public class JsonParserTest { static final Charset UTF_32LE = Charset.forName("UTF-32LE"); static final Charset UTF_32BE = Charset.forName("UTF-32BE"); - private static final EnumSet GET_STRING_EVENT_ENUM_SET = - EnumSet.of(JsonParser.Event.KEY_NAME, JsonParser.Event.VALUE_STRING, JsonParser.Event.VALUE_NUMBER); - - private static final EnumSet NOT_GET_VALUE_EVENT_ENUM_SET = EnumSet.of(JsonParser.Event.END_OBJECT, JsonParser.Event.END_ARRAY); - - private static final Collector, ?, ArrayList> MAP_TO_LIST_COLLECTOR = Collector.of(ArrayList::new, - (list, entry) -> { - list.add(entry.getKey()); - list.add(entry.getValue().toString()); - }, - (left, right) -> { - left.addAll(right); - return left; - }, - Collector.Characteristics.IDENTITY_FINISH); - @Test void testReader() { JsonParser reader = Json.createParser( @@ -898,631 +872,4 @@ private void checkExceptionFromNext(String input) { } Assertions.fail(); } - - @Nested - public class DirectParserTests { - @Test - void testNumbersStructure() { - JsonParserFixture.testWithCreateParserFromObject(Json.createObjectBuilder() - .add("int", 1) - .add("long", 1L) - .add("double", 1d) - .add("BigInteger", BigInteger.TEN) - .add("BigDecimal", BigDecimal.TEN) - .build(), this::testNumbers); - } - - @Test - void testNumbersString() { - JsonParserFixture.testWithCreateParserFromString("{\"int\":1,\"long\":1,\"double\":1.0,\"BigInteger\":10,\"BigDecimal\":10}", this::testNumbers); - } - - private void testNumbers(JsonParser parser) { - parser.next(); - parser.next(); - parser.getString(); - parser.next(); - Assertions.assertTrue(parser.isIntegralNumber()); - Assertions.assertEquals(1, parser.getInt()); - - parser.next(); - parser.getString(); - parser.next(); - Assertions.assertTrue(parser.isIntegralNumber()); - Assertions.assertEquals(1L, parser.getLong()); - - parser.next(); - parser.getString(); - parser.next(); - Assertions.assertFalse(parser.isIntegralNumber()); - Assertions.assertEquals(BigDecimal.valueOf(1d), parser.getBigDecimal()); - - parser.next(); - parser.getString(); - parser.next(); - Assertions.assertTrue(parser.isIntegralNumber()); - Assertions.assertEquals(BigDecimal.TEN, parser.getBigDecimal()); - - parser.next(); - parser.getString(); - parser.next(); - Assertions.assertTrue(parser.isIntegralNumber()); - Assertions.assertEquals(BigDecimal.TEN, parser.getBigDecimal()); - } - - @Test - void testParser_getStringStructure(){ - JsonParserFixture.testWithCreateParserFromObject(TestData.createFamilyPerson(), this::testParser_getString); - } - - @Test - void testParser_getStringString(){ - JsonParserFixture.testWithCreateParserFromString(TestData.JSON_FAMILY_STRING, this::testParser_getString); - } - - private void testParser_getString(JsonParser parser) { - List values = new ArrayList<>(); - parser.next(); - while (parser.hasNext()) { - Event event = parser.next(); - if (GET_STRING_EVENT_ENUM_SET.contains(event)) { - String strValue = Objects.toString(parser.getString(), "null"); - values.add(strValue); - } - } - - MatcherAssert.assertThat(values,TestData.FAMILY_MATCHER_WITH_NO_QUOTATION); - } - - @Test - void testParser_getValueStructure(){ - JsonParserFixture.testWithCreateParserFromObject(TestData.createFamilyPerson(), this::testParser_getValue); - } - - @Test - void testParser_getValueString(){ - JsonParserFixture.testWithCreateParserFromString(TestData.JSON_FAMILY_STRING, this::testParser_getValue); - } - - private void testParser_getValue(JsonParser parser) { - List values = new ArrayList<>(); - parser.next(); - while (parser.hasNext()) { - Event event = parser.next(); - if (!NOT_GET_VALUE_EVENT_ENUM_SET.contains(event)) { - String strValue = Objects.toString(parser.getValue(), "null"); - values.add(strValue); - } - } - - MatcherAssert.assertThat(values, TestData.FAMILY_MATCHER_KEYS_WITH_QUOTATION); - } - - @Test - void testSkipArrayStructure() { - JsonParserFixture.testWithCreateParserFromObject(TestData.createObjectWithArrays(), this::testSkipArray); - } - - @Test - void testSkipArrayString() { - JsonParserFixture.testWithCreateParserFromString(TestData.JSON_OBJECT_WITH_ARRAYS, this::testSkipArray); - } - - private void testSkipArray(JsonParser parser) { - parser.next(); - parser.next(); - parser.getString(); - parser.next(); - parser.skipArray(); - parser.next(); - String key = parser.getString(); - - Assertions.assertEquals("secondElement", key); - } - - @Test - void testSkipObjectStructure() { - JsonParserFixture.testWithCreateParserFromObject(TestData.createJsonObject(), this::testSkipObject); - } - - @Test - void testSkipObjectString() { - JsonParserFixture.testWithCreateParserFromString(TestData.JSON_OBJECT_WITH_OBJECTS, this::testSkipObject); - } - - private void testSkipObject(JsonParser parser) { - parser.next(); - parser.next(); - parser.getString(); - parser.next(); - parser.skipObject(); - parser.next(); - String key = parser.getString(); - - Assertions.assertEquals("secondPerson", key); - } - - private void assertThrowsIllegalStateException(Executable executable) { - Assertions.assertThrows(IllegalStateException.class, executable); - } - - @Test - void testErrorGetObjectStructure() { - assertThrowsIllegalStateException(() -> JsonParserFixture.testWithCreateParserFromObject(TestData.createJsonObject(), JsonParser::getObject)); - } - - @Test - void testErrorGetObjectString() { - assertThrowsIllegalStateException(() -> JsonParserFixture.testWithCreateParserFromString(TestData.JSON_OBJECT_WITH_OBJECTS, JsonParser::getObject)); - } - - @Test - void testErrorGetArrayStructure() { - assertThrowsIllegalStateException(() -> JsonParserFixture.testWithCreateParserFromObject(TestData.createJsonObject(), this::testErrorGetArray)); - } - - @Test - void testErrorGetArrayString() { - assertThrowsIllegalStateException(() -> JsonParserFixture.testWithCreateParserFromString(TestData.JSON_OBJECT_WITH_OBJECTS, this::testErrorGetArray)); - } - - private void testErrorGetArray(JsonParser parser) { - parser.next(); - parser.getArray(); - } - - @Test - void testErrorGetValueEndOfObjectStructure() { - assertThrowsIllegalStateException(() -> JsonParserFixture.testWithCreateParserFromObject(TestData.createJsonObject(), this::testErrorGetValueEndOfObject)); - } - - @Test - void testErrorGetValueEndOfObjectString() { - assertThrowsIllegalStateException(() -> JsonParserFixture.testWithCreateParserFromString(TestData.JSON_OBJECT_WITH_OBJECTS, this::testErrorGetValueEndOfObject)); - } - - private void testErrorGetValueEndOfObject(JsonParser parser) { - parser.next(); - parser.skipObject(); - parser.getValue(); - } - - @Test - void testErrorGetValueEndOfArrayStructure() { - assertThrowsIllegalStateException(() -> JsonParserFixture.testWithCreateParserFromObject(TestData.createObjectWithArrays(), this::testErrorGetValueEndOfArray)); - } - - @Test - void testErrorGetValueEndOfArrayString() { - assertThrowsIllegalStateException(() -> JsonParserFixture.testWithCreateParserFromString(TestData.JSON_OBJECT_WITH_ARRAYS, this::testErrorGetValueEndOfArray)); - } - - private void testErrorGetValueEndOfArray(JsonParser parser) { - parser.next(); - parser.next(); - parser.getString(); - parser.next(); - parser.skipArray(); - parser.getValue(); - } - - @Test - void testBooleanNullandCurrentEventStructure() { - JsonParserFixture.testWithCreateParserFromObject(Json.createObjectBuilder() - .add("true", true) - .add("false", false) - .addNull("null") - .build(), this::testBooleanNullandCurrentEvent); - } - - @Test - void testBooleanNullandCurrentEventString() { - JsonParserFixture.testWithCreateParserFromString("{\"true\":true,\"false\":false,\"null\":null}", this::testBooleanNullandCurrentEvent); - } - - private void testBooleanNullandCurrentEvent(JsonParser parser) { - parser.next(); - parser.next(); - parser.getValue(); - parser.next(); - Assertions.assertEquals(JsonValue.ValueType.TRUE, parser.getValue().getValueType()); - parser.next(); - parser.getValue(); - parser.next(); - Assertions.assertEquals(JsonValue.ValueType.FALSE, parser.getValue().getValueType()); - parser.next(); - parser.getValue(); - parser.next(); - Assertions.assertEquals(JsonValue.ValueType.NULL, parser.getValue().getValueType()); - Assertions.assertEquals(Event.VALUE_NULL, parser.currentEvent()); - } - - @Test - void testBigLongAndDecimalsStructure() { - JsonParserFixture.testWithCreateParserFromObject(Json.createObjectBuilder() - .add("long", 12345678901234567L) - .add("longer", 1234567890123456789L) - .build(), this::testBigLongAndDecimals); - } - - @Test - void testBigLongAndDecimalsString() { - JsonParserFixture.testWithCreateParserFromString("{\"long\":12345678901234567,\"longer\":1234567890123456789}", this::testBigLongAndDecimals); - } - - private void testBigLongAndDecimals(JsonParser parser) { - parser.next(); - parser.next(); - parser.getString(); - parser.next(); - Assertions.assertEquals("12345678901234567", parser.getValue().toString()); - parser.next(); - parser.getString(); - parser.next(); - Assertions.assertEquals("1234567890123456789", parser.getValue().toString()); - } - - private void assertThrowsJsonParsingException(Executable executable) { - Assertions.assertThrows(JsonParsingException.class, executable); - } - - @Test - void testWrongValueAndEndOfObjectInArray() {//509 ArrayContext.getNextEvent, no coma - assertThrowsJsonParsingException(() -> JsonParserFixture.testWithCreateParserFromString("{\"a\":[5 }]}", parser -> { - parser.next(); - parser.next(); - parser.getString(); - parser.next(); - parser.getValue(); - })); - } - - @Test - void testWrongEndOfObjectInArray() {//518 ArrayContext.getNextEvent, at the end - assertThrowsJsonParsingException(() -> JsonParserFixture.testWithCreateParserFromString("{\"a\":[}, 3]}", parser -> { - parser.next(); - parser.next(); - parser.getString(); - parser.next(); - parser.getValue(); - })); - } - - @Test - void testWrongKey() {//477 ObjectContext.getNextEvent, at the end - assertThrowsJsonParsingException(() -> JsonParserFixture.testWithCreateParserFromString("{\"a\":1, 5}", parser -> { - parser.next(); - parser.next(); - parser.getString(); - parser.next(); - parser.getValue(); - parser.next(); - })); - } - - @Test - void testErrorInTheValue() {//470 ObjectContext.getNextEvent, no coma - assertThrowsJsonParsingException(() -> JsonParserFixture.testWithCreateParserFromString("{\"a\":1:}", parser -> { - parser.next(); - parser.next(); - parser.getString(); - parser.next(); - parser.getValue(); - parser.next(); - })); - } - - @Test - void testNoValueAfterKey() {//452 ObjectContext.getNextEvent, no colon - assertThrowsJsonParsingException(() -> JsonParserFixture.testWithCreateParserFromString("{\"a\"}", parser -> { - parser.next(); - parser.next(); - parser.getString(); - parser.next(); - })); - } - - @Test - void testNoJSONAtAll() {//382 NoneContext.getNextEvent, at the end - assertThrowsJsonParsingException(() -> JsonParserFixture.testWithCreateParserFromString("", JsonParser::next)); - } - - @Test - void testWrongArrayEndWithComa() {//518 ArrayContext.getNextEvent, at the end - assertThrowsJsonParsingException(() -> JsonParserFixture.testWithCreateParserFromString("[,", parser -> { - parser.next(); - parser.getArray(); - })); - } - } - - @Nested - class StreamTests { - @Test - void testGetValueStream_GetOneElement_Structure() { - JsonParserFixture.testWithCreateParserFromObject(TestData.createFamilyPerson(), this::testGetValueStream_GetOneElement); - } - - @Test - void testGetValueStream_GetOneElement_String() { - JsonParserFixture.testWithCreateParserFromString(TestData.JSON_FAMILY_STRING, this::testGetValueStream_GetOneElement); - } - - private void testGetValueStream_GetOneElement(JsonParser parser) { - JsonString name = (JsonString) parser.getValueStream() - .map(JsonValue::asJsonObject) - .map(JsonObject::values) - .findFirst() - .orElseThrow(() -> new NoSuchElementException("No value present")) - .stream() - .filter(e -> e.getValueType() == JsonValue.ValueType.STRING) - .findFirst() - .orElseThrow(() -> new RuntimeException("Name not found")); - - Assertions.assertEquals("John", name.getString()); - } - - @Test - void testGetValueStream_GetListStructure() { - JsonParserFixture.testWithCreateParserFromObject(TestData.createFamilyPerson(), this::testGetValueStream_GetList); - } - - @Test - void testGetValueStream_GetListString() { - JsonParserFixture.testWithCreateParserFromString(TestData.JSON_FAMILY_STRING, this::testGetValueStream_GetList); - } - - private void testGetValueStream_GetList(JsonParser parser) { - List values = parser.getValueStream().map(value -> Objects.toString(value, "null")).collect(Collectors.toList()); - - MatcherAssert.assertThat(values, Matchers.contains(TestData.JSON_FAMILY_STRING)); - } - - @Test - void testGetArrayStream_GetOneElementStructure() { - JsonParserFixture.testWithCreateParserFromObject(TestData.createObjectWithArrays(), this::testGetArrayStream_GetOneElement); - } - - @Test - void testGetArrayStream_GetOneElementString() { - JsonParserFixture.testWithCreateParserFromString(TestData.JSON_OBJECT_WITH_ARRAYS, this::testGetArrayStream_GetOneElement); - } - - private void testGetArrayStream_GetOneElement(JsonParser parser) { - parser.next(); - parser.next(); - String key = parser.getString(); - parser.next(); - JsonString element = (JsonString) parser.getArrayStream().filter(e -> e.getValueType() == JsonValue.ValueType.STRING) - .findFirst() - .orElseThrow(() -> new RuntimeException("Element not found")); - - Assertions.assertEquals("first", element.getString()); - Assertions.assertEquals("firstElement", key); - } - - @Test - void testGetArrayStream_GetListStructure() { - JsonParserFixture.testWithCreateParserFromObject(TestData.createObjectWithArrays(), this::testGetArrayStream_GetList); - } - - @Test - void testGetArrayStream_GetListString() { - JsonParserFixture.testWithCreateParserFromString(TestData.JSON_OBJECT_WITH_ARRAYS, this::testGetArrayStream_GetList); - } - - private void testGetArrayStream_GetList(JsonParser parser) { - parser.next(); - parser.next(); - String key = parser.getString(); - parser.next(); - List values = parser.getArrayStream().map(value -> Objects.toString(value, "null")).collect(Collectors.toList()); - - MatcherAssert.assertThat(values, TestData.ARRAY_STREAM_MATCHER); - Assertions.assertEquals("firstElement", key); - } - - @Test - void testGetObjectStream_GetOneElementStructure() { - JsonParserFixture.testWithCreateParserFromObject(TestData.createJsonObject(), this::testGetObjectStream_GetOneElement); - } - - @Test - void testGetObjectStream_GetOneElementString() { - JsonParserFixture.testWithCreateParserFromString(TestData.JSON_OBJECT_WITH_OBJECTS, this::testGetObjectStream_GetOneElement); - } - - private void testGetObjectStream_GetOneElement(JsonParser parser) { - parser.next(); - String surname = parser.getObjectStream().filter(e -> e.getKey().equals("firstPerson")) - .map(Map.Entry::getValue) - .map(JsonValue::asJsonObject) - .map(obj -> obj.getString("surname")) - .findFirst() - .orElseThrow(() -> new RuntimeException("Surname not found")); - - Assertions.assertEquals("Smith", surname); - } - - @Test - void testGetObjectStream_GetListStructure() { - JsonParserFixture.testWithCreateParserFromObject(TestData.createFamilyPerson(), this::testGetObjectStream_GetList); - } - - @Test - void testGetObjectStream_GetListString() { - JsonParserFixture.testWithCreateParserFromString(TestData.JSON_FAMILY_STRING, this::testGetObjectStream_GetList); - } - - private void testGetObjectStream_GetList(JsonParser parser) { - parser.next(); - List values = parser.getObjectStream().collect(MAP_TO_LIST_COLLECTOR); - - MatcherAssert.assertThat(values, TestData.FAMILY_MATCHER_KEYS_WITHOUT_QUOTATION); - } - } - - @Nested - public class JSONPStandardParserTests { - @Test - void testStandardStructureParser_getValueStream() { - JsonParserFixture.testWithCreateParserFromObject(TestData.createFamilyPerson(), this::test_getValueStream); - } - - @Test - void testStandardStringParser_getValueStream() { - JsonParserFixture.testWithCreateParserFromString(TestData.JSON_FAMILY_STRING, this::test_getValueStream); - } - - private void test_getValueStream(JsonParser parser) { - List values = parser.getValueStream().map(value -> Objects.toString(value, "null")).collect(Collectors.toList()); - - MatcherAssert.assertThat(values, Matchers.contains(TestData.JSON_FAMILY_STRING)); - } - - @Test - void testStandardStructureParser_getArrayStream() { - JsonParserFixture.testWithCreateParserFromObject(TestData.createObjectWithArrays(), this::test_getArrayStream); - } - - @Test - void testStandardStringParser_getArrayStream() { - JsonParserFixture.testWithCreateParserFromString(TestData.JSON_OBJECT_WITH_ARRAYS, this::test_getArrayStream); - } - - private void test_getArrayStream(JsonParser parser) { - parser.next(); - parser.next(); - String key = parser.getString(); - parser.next(); - List values = parser.getArrayStream().map(value -> Objects.toString(value, "null")).collect(Collectors.toList()); - - MatcherAssert.assertThat(values, TestData.ARRAY_STREAM_MATCHER); - Assertions.assertEquals("firstElement", key); - } - - @Test - void testStandardStructureParser_getObjectStream() { - JsonParserFixture.testWithCreateParserFromObject(TestData.createFamilyPerson(), this::test_getObjectStream); - } - - @Test - void testStandardStringParser_getObjectStream() { - JsonParserFixture.testWithCreateParserFromString(TestData.JSON_FAMILY_STRING, this::test_getObjectStream); - } - - private void test_getObjectStream(JsonParser parser) { - parser.next(); - List values = parser.getObjectStream().collect(MAP_TO_LIST_COLLECTOR); - - MatcherAssert.assertThat(values, TestData.FAMILY_MATCHER_KEYS_WITHOUT_QUOTATION); - } - - @Test - void testStandardStructureParser_getValue() { - JsonParserFixture.testWithCreateParserFromObject(TestData.createFamilyPerson(), this::test_getValue); - } - - @Test - void testStandardStringParser_getValue() { - JsonParserFixture.testWithCreateParserFromString(TestData.JSON_FAMILY_STRING, this::test_getValue); - } - - private void test_getValue(JsonParser parser) { - List values = new ArrayList<>(); - parser.next(); - while (parser.hasNext()) { - Event event = parser.next(); - if (!NOT_GET_VALUE_EVENT_ENUM_SET.contains(event)) { - String strValue = Objects.toString(parser.getValue(), "null"); - values.add(strValue); - } - } - - MatcherAssert.assertThat(values, TestData.FAMILY_MATCHER_KEYS_WITH_QUOTATION); - } - - @Test - void testStandardStructureParser_getString() { - JsonParserFixture.testWithCreateParserFromObject(TestData.createFamilyPerson(), this::test_getString); - } - - @Test - void testStandardStringParser_getString() { - JsonParserFixture.testWithCreateParserFromString(TestData.JSON_FAMILY_STRING, this::test_getString); - } - - private void test_getString(JsonParser parser) { - List values = new ArrayList<>(); - parser.next(); - while (parser.hasNext()) { - Event event = parser.next(); - if (GET_STRING_EVENT_ENUM_SET.contains(event)) { - String strValue = Objects.toString(parser.getString(), "null"); - values.add(strValue); - } - } - - MatcherAssert.assertThat(values, TestData.FAMILY_MATCHER_WITH_NO_QUOTATION); - } - } - - private static class TestData { - private static final String JSON_OBJECT_WITH_OBJECTS = "{\"firstPerson\":{\"name\":\"John\", \"surname\":\"Smith\"}," + - "\"secondPerson\":{\"name\":\"Deborah\", \"surname\":\"Harris\"}}"; - - private static final String JSON_OBJECT_WITH_ARRAYS = "{\"firstElement\":[\"first\", \"second\"],\"secondElement\":[\"third\", \"fourth\"]}"; - - private static final String JSON_FAMILY_STRING = "{\"name\":\"John\",\"surname\":\"Smith\",\"age\":30,\"married\":true," + - "\"wife\":{\"name\":\"Deborah\",\"surname\":\"Harris\"},\"children\":[\"Jack\",\"Mike\"]}"; - - private static final Matcher> FAMILY_MATCHER_KEYS_WITHOUT_QUOTATION = - Matchers.contains("name", "\"John\"", "surname", "\"Smith\"", "age", "30", "married", "true", "wife", - "{\"name\":\"Deborah\",\"surname\":\"Harris\"}", "children", "[\"Jack\",\"Mike\"]"); - - private static final Matcher> FAMILY_MATCHER_KEYS_WITH_QUOTATION = - Matchers.contains("\"name\"", "\"John\"", "\"surname\"", "\"Smith\"", "\"age\"", "30", "\"married\"", "true", - "\"wife\"", "{\"name\":\"Deborah\",\"surname\":\"Harris\"}", "\"children\"", "[\"Jack\",\"Mike\"]"); - - private static final Matcher> FAMILY_MATCHER_WITH_NO_QUOTATION = - Matchers.contains("name", "John", "surname", "Smith", "age", "30", "married", - "wife", "name", "Deborah", "surname", "Harris", "children", "Jack", "Mike"); - - private static final Matcher> ARRAY_STREAM_MATCHER = Matchers.contains("\"first\"", "\"second\""); - - private static JsonObject createFamilyPerson() { - return Json.createObjectBuilder() - .add("name", "John") - .add("surname", "Smith") - .add("age", 30) - .add("married", true) - .add("wife", createPerson("Deborah", "Harris")) - .add("children", createArray("Jack", "Mike")) - .build(); - } - - private static JsonObject createObjectWithArrays() { - return Json.createObjectBuilder() - .add("firstElement", createArray("first", "second")) - .add("secondElement", createArray("third", "fourth")) - .build(); - } - - private static JsonArrayBuilder createArray(String firstElement, String secondElement) { - return Json.createArrayBuilder().add(firstElement).add(secondElement); - } - - private static JsonObject createJsonObject() { - return Json.createObjectBuilder() - .add("firstPerson", createPerson("John", "Smith")) - .add("secondPerson", createPerson("Deborah", "Harris")) - .build(); - } - - private static JsonObjectBuilder createPerson(String name, String surname) { - return Json.createObjectBuilder() - .add("name", name) - .add("surname", surname); - } - } }