From c1a42cbf1eaa8eccf0635afb401e648b1563e452 Mon Sep 17 00:00:00 2001 From: Anton Pinsky Date: Mon, 13 Nov 2023 23:43:44 +0100 Subject: [PATCH 1/4] [#112]Corrected skip methods behavior of JsonParserImpl; created test for these methods Signed-off-by: Anton Pinsky --- .gitignore | 1 + .../org/eclipse/parsson/JsonParserImpl.java | 143 +++++++++--------- .../eclipse/parsson/JsonParserFixture.java | 73 +++++++++ .../parsson/tests/JsonParserSkipTest.java | 134 +++++++++++----- 4 files changed, 244 insertions(+), 107 deletions(-) create mode 100644 impl/src/test/java/org/eclipse/parsson/JsonParserFixture.java diff --git a/.gitignore b/.gitignore index c8dfb82e..fdf8d269 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,4 @@ nbproject/ *err_pid*.log /tck-impl/.gradle/ /tck-impl/build/ +/.sdkmanrc diff --git a/impl/src/main/java/org/eclipse/parsson/JsonParserImpl.java b/impl/src/main/java/org/eclipse/parsson/JsonParserImpl.java index 217af798..aa43eb43 100644 --- a/impl/src/main/java/org/eclipse/parsson/JsonParserImpl.java +++ b/impl/src/main/java/org/eclipse/parsson/JsonParserImpl.java @@ -189,26 +189,27 @@ public Stream getArrayStream() { 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; - } - }; + 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); } @@ -219,36 +220,37 @@ public Stream> getObjectStream() { 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; - } - }; + 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); } @@ -259,30 +261,31 @@ public Stream getValueStream() { 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; - } - }; + 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 public void skipArray() { - if (currentEvent == Event.START_ARRAY) { + if (currentContext instanceof ArrayContext) { currentContext.skip(); currentContext = stack.pop(); currentEvent = Event.END_ARRAY; @@ -291,7 +294,7 @@ public void skipArray() { @Override public void skipObject() { - if (currentEvent == Event.START_OBJECT) { + if (currentContext instanceof ObjectContext) { currentContext.skip(); currentContext = stack.pop(); currentEvent = Event.END_OBJECT; diff --git a/impl/src/test/java/org/eclipse/parsson/JsonParserFixture.java b/impl/src/test/java/org/eclipse/parsson/JsonParserFixture.java new file mode 100644 index 00000000..3642ec38 --- /dev/null +++ b/impl/src/test/java/org/eclipse/parsson/JsonParserFixture.java @@ -0,0 +1,73 @@ +/* + * 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.io.StringReader; +import java.util.function.Consumer; +import java.util.function.Supplier; + +import jakarta.json.Json; +import jakarta.json.JsonArray; +import jakarta.json.JsonObject; +import jakarta.json.stream.JsonParser; + +/** + * Class with methods that creates JsonParser with different configuration from different sources and runs the test code with this parser + */ +public class JsonParserFixture { + /** + * Runs the test code with JsonParser created from the given JsonObject + * + * @param object JsonObject to create JsonParser from + * @param parserConsumer test code to run with the created JsonParser + */ + public static void testWithCreateParserFromObject(JsonObject object, Consumer parserConsumer) { + testWithParser(() -> Json.createParserFactory(null).createParser(object), parserConsumer); + } + + /** + * Runs the test code with JsonParser created from the given JsonArray + * + * @param array JsonArray to create JsonParser from + * @param parserConsumer test code to run with the created JsonParser + */ + public static void testWithCreateParserFromArray(JsonArray array, Consumer parserConsumer) { + testWithParser(() -> Json.createParserFactory(null).createParser(array), parserConsumer); + } + + /** + * Runs the test code with JsonParser created from the given String + * + * @param string String with JSON to create JsonParser from + * @param parserConsumer test code to run with the created JsonParser + */ + public static void testWithCreateParserFromString(String string, Consumer parserConsumer) { + testWithParser(() -> Json.createParser(new StringReader(string)), parserConsumer); + } + + /** + * Runs the test code with JsonParser created from the given String + * + * @param parserSupplier Supplier of JsonParser to create JsonParser from + * @param parserConsumer test code to run with the created JsonParser + */ + private static void testWithParser(Supplier parserSupplier, Consumer parserConsumer) { + try (JsonParser parser = parserSupplier.get()) { + parserConsumer.accept(parser); + } + } +} diff --git a/impl/src/test/java/org/eclipse/parsson/tests/JsonParserSkipTest.java b/impl/src/test/java/org/eclipse/parsson/tests/JsonParserSkipTest.java index 56ea6af0..f138cb13 100644 --- a/impl/src/test/java/org/eclipse/parsson/tests/JsonParserSkipTest.java +++ b/impl/src/test/java/org/eclipse/parsson/tests/JsonParserSkipTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 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 @@ -16,13 +16,13 @@ package org.eclipse.parsson.tests; -import java.io.StringReader; import jakarta.json.Json; import jakarta.json.stream.JsonParser; import junit.framework.TestCase; -import static junit.framework.TestCase.assertEquals; -import static junit.framework.TestCase.assertFalse; -import static junit.framework.TestCase.assertTrue; + +import static org.eclipse.parsson.JsonParserFixture.testWithCreateParserFromArray; +import static org.eclipse.parsson.JsonParserFixture.testWithCreateParserFromObject; +import static org.eclipse.parsson.JsonParserFixture.testWithCreateParserFromString; /** * @@ -31,44 +31,70 @@ public class JsonParserSkipTest extends TestCase { public void testSkipArrayReader() { - try (JsonParser parser = Json.createParser(new StringReader("[[],[[]]]"))) { - testSkipArray(parser); - } + testWithCreateParserFromString("[[],[[]]]", JsonParserSkipTest::testSkipArray); } public void testSkipArrayStructure() { - try (JsonParser parser = Json.createParserFactory(null).createParser( - Json.createArrayBuilder() - .add(Json.createArrayBuilder()) - .add(Json.createArrayBuilder() - .add(Json.createArrayBuilder())) - .build())) { - testSkipArray(parser); - } + testWithCreateParserFromArray(Json.createArrayBuilder() + .add(Json.createArrayBuilder()) + .add(Json.createArrayBuilder() + .add(Json.createArrayBuilder())) + .build(), JsonParserSkipTest::testSkipArray); } private static void testSkipArray(JsonParser parser) { assertEquals(JsonParser.Event.START_ARRAY, parser.next()); parser.skipArray(); - assertEquals(false, parser.hasNext()); + assertFalse(parser.hasNext()); + } + + public void testSkipInsideArrayReader() { + testWithCreateParserFromString("[\"test\"]", JsonParserSkipTest::testSkipInsideArray); + } + + public void testSkipInsideArrayStructure() { + testWithCreateParserFromArray(Json.createArrayBuilder() + .add("test") + .build(), JsonParserSkipTest::testSkipInsideArray); + } + + private static void testSkipInsideArray(JsonParser parser) { + assertEquals(JsonParser.Event.START_ARRAY, parser.next()); + assertEquals(JsonParser.Event.VALUE_STRING, parser.next()); + parser.skipArray(); + assertFalse(parser.hasNext()); + } + + public void testNoSkipArrayReader() { + testWithCreateParserFromString("{\"key\":\"value\"}", JsonParserSkipTest::testNoSkipArray); + } + + public void testNoSkipArrayStructure() { + testWithCreateParserFromObject(Json.createObjectBuilder() + .add("key","value") + .build(), JsonParserSkipTest::testNoSkipArray); + } + + private static void testNoSkipArray(JsonParser parser) { + assertEquals(JsonParser.Event.START_OBJECT, parser.next()); + assertEquals(JsonParser.Event.KEY_NAME, parser.next()); + parser.skipArray(); + assertEquals(JsonParser.Event.VALUE_STRING, parser.next()); + assertEquals(JsonParser.Event.END_OBJECT, parser.next()); + assertFalse(parser.hasNext()); } public void testSkipArrayInObjectReader() { - try (JsonParser parser = Json.createParser(new StringReader("{\"array\":[[],[[]]],\"object\":\"value2\"}"))) { - testSkipArrayInObject(parser); - } + testWithCreateParserFromString("{\"array\":[[],[[]]],\"object\":\"value2\"}", JsonParserSkipTest::testSkipArrayInObject); } public void testSkipArrayInObjectStructure() { - try (JsonParser parser = Json.createParserFactory(null).createParser( - Json.createObjectBuilder().add("array", Json.createArrayBuilder() + testWithCreateParserFromObject(Json.createObjectBuilder().add("array", Json.createArrayBuilder() .add(Json.createArrayBuilder()) .add(Json.createArrayBuilder() .add(Json.createArrayBuilder())) ).add("object", "value2") - .build())) { - testSkipArrayInObject(parser); - } + .build(), JsonParserSkipTest::testSkipArrayInObject); } private static void testSkipArrayInObject(JsonParser parser) { @@ -84,20 +110,15 @@ private static void testSkipArrayInObject(JsonParser parser) { } public void testSkipObjectReader() { - try (JsonParser parser = Json.createParser(new StringReader("{\"array\":[],\"objectToSkip\":{\"huge key\":\"huge value\"},\"simple\":2}"))) { - testSkipObject(parser); - } + testWithCreateParserFromString("{\"array\":[],\"objectToSkip\":{\"huge key\":\"huge value\"},\"simple\":2}", JsonParserSkipTest::testSkipObject); } public void testSkipObjectStructure() { - try (JsonParser parser = Json.createParserFactory(null).createParser( - Json.createObjectBuilder() - .add("array", Json.createArrayBuilder().build()) - .add("objectToSkip", Json.createObjectBuilder().add("huge key", "huge value")) - .add("simple", 2) - .build())) { - testSkipObject(parser); - } + testWithCreateParserFromObject(Json.createObjectBuilder() + .add("array", Json.createArrayBuilder().build()) + .add("objectToSkip", Json.createObjectBuilder().add("huge key", "huge value")) + .add("simple", 2) + .build(), JsonParserSkipTest::testSkipObject); } private static void testSkipObject(JsonParser parser) { @@ -111,6 +132,45 @@ private static void testSkipObject(JsonParser parser) { assertEquals(JsonParser.Event.KEY_NAME, parser.next()); assertEquals(JsonParser.Event.VALUE_NUMBER, parser.next()); assertEquals(JsonParser.Event.END_OBJECT, parser.next()); - assertEquals(false, parser.hasNext()); + assertFalse(parser.hasNext()); + } + + public void testSkipInsideObjectReader() { + testWithCreateParserFromString("{\"objectToSkip\":{\"huge key\":\"huge value\"},\"simple\":2}", JsonParserSkipTest::testSkipInsideObject); + } + + public void testSkipInsideObjectStructure() { + testWithCreateParserFromObject(Json.createObjectBuilder() + .add("objectToSkip", Json.createObjectBuilder().add("huge key", "huge value")) + .add("simple", 2) + .build(), JsonParserSkipTest::testSkipInsideObject); + } + + private static void testSkipInsideObject(JsonParser parser) { + assertEquals(JsonParser.Event.START_OBJECT, parser.next()); + assertEquals(JsonParser.Event.KEY_NAME, parser.next()); + assertEquals(JsonParser.Event.START_OBJECT, parser.next()); + parser.skipObject(); + assertEquals(JsonParser.Event.KEY_NAME, parser.next()); + assertEquals(JsonParser.Event.VALUE_NUMBER, parser.next()); + assertEquals(JsonParser.Event.END_OBJECT, parser.next()); + assertFalse(parser.hasNext()); + } + + public void testNoSkipObjectReader() { + testWithCreateParserFromString("{\"key\":\"value\"}", JsonParserSkipTest::testNoSkipObject); + } + + public void testNoSkipObjectStructure() { + testWithCreateParserFromObject(Json.createObjectBuilder() + .add("Key", "value") + .build(), JsonParserSkipTest::testNoSkipObject); + } + + private static void testNoSkipObject(JsonParser parser) { + assertEquals(JsonParser.Event.START_OBJECT, parser.next()); + assertEquals(JsonParser.Event.KEY_NAME, parser.next()); + parser.skipObject(); + assertFalse(parser.hasNext()); } } From 5c41302a9dc56ceff81399d51d2202673887efae Mon Sep 17 00:00:00 2001 From: Anton Pinsky Date: Tue, 14 Nov 2023 02:06:26 +0100 Subject: [PATCH 2/4] [#112]Deduplicate the Context code in the JsonParserImpl Signed-off-by: Anton Pinsky --- .../org/eclipse/parsson/JsonParserImpl.java | 168 +++++++++--------- 1 file changed, 85 insertions(+), 83 deletions(-) diff --git a/impl/src/main/java/org/eclipse/parsson/JsonParserImpl.java b/impl/src/main/java/org/eclipse/parsson/JsonParserImpl.java index aa43eb43..a7beb5cf 100644 --- a/impl/src/main/java/org/eclipse/parsson/JsonParserImpl.java +++ b/impl/src/main/java/org/eclipse/parsson/JsonParserImpl.java @@ -25,6 +25,7 @@ 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; @@ -43,6 +44,15 @@ import org.eclipse.parsson.JsonTokenizer.JsonToken; +import static org.eclipse.parsson.JsonTokenizer.JsonToken.COLON; +import static org.eclipse.parsson.JsonTokenizer.JsonToken.COMMA; +import static org.eclipse.parsson.JsonTokenizer.JsonToken.CURLYCLOSE; +import static org.eclipse.parsson.JsonTokenizer.JsonToken.CURLYOPEN; +import static org.eclipse.parsson.JsonTokenizer.JsonToken.EOF; +import static org.eclipse.parsson.JsonTokenizer.JsonToken.SQUARECLOSE; +import static org.eclipse.parsson.JsonTokenizer.JsonToken.SQUAREOPEN; +import static org.eclipse.parsson.JsonTokenizer.JsonToken.STRING; + /** * JSON parser implementation. NoneContext, ArrayContext, ObjectContext is used * to go to next parser state. @@ -189,7 +199,7 @@ public Stream getArrayStream() { JsonMessages.PARSER_GETARRAY_ERR(currentEvent)); } Spliterator spliterator = - new Spliterators.AbstractSpliterator<>(Long.MAX_VALUE, Spliterator.ORDERED) { + new Spliterators.AbstractSpliterator(Long.MAX_VALUE, Spliterator.ORDERED) { @Override public Spliterator trySplit() { return null; @@ -220,7 +230,7 @@ public Stream> getObjectStream() { JsonMessages.PARSER_GETOBJECT_ERR(currentEvent)); } Spliterator> spliterator = - new Spliterators.AbstractSpliterator<>(Long.MAX_VALUE, Spliterator.ORDERED) { + new Spliterators.AbstractSpliterator>(Long.MAX_VALUE, Spliterator.ORDERED) { @Override public Spliterator> trySplit() { return null; @@ -261,7 +271,7 @@ public Stream getValueStream() { JsonMessages.PARSER_GETVALUESTREAM_ERR()); } Spliterator spliterator = - new Spliterators.AbstractSpliterator<>(Long.MAX_VALUE, Spliterator.ORDERED) { + new Spliterators.AbstractSpliterator(Long.MAX_VALUE, Spliterator.ORDERED) { @Override public Spliterator trySplit() { return null; @@ -309,7 +319,7 @@ private JsonArray getArray(JsonArrayBuilder builder) { } builder.add(getValue()); } - throw parsingException(JsonToken.EOF, "[CURLYOPEN, SQUAREOPEN, STRING, NUMBER, TRUE, FALSE, NULL, SQUARECLOSE]"); + throw parsingException(EOF, "[CURLYOPEN, SQUAREOPEN, STRING, NUMBER, TRUE, FALSE, NULL, SQUARECLOSE]"); } private CharSequence getCharSequence() { @@ -330,7 +340,7 @@ private JsonObject getObject(JsonObjectBuilder builder) { next(); builder.add(key, getValue()); } - throw parsingException(JsonToken.EOF, "[STRING, CURLYCLOSE]"); + throw parsingException(EOF, "[STRING, CURLYCLOSE]"); } @Override @@ -346,7 +356,7 @@ public JsonLocation getLastCharLocation() { public boolean hasNext() { if (stack.isEmpty() && (currentEvent != null && currentEvent.compareTo(Event.KEY_NAME) > 0)) { JsonToken token = tokenizer.nextToken(); - if (token != JsonToken.EOF) { + if (token != EOF) { throw new JsonParsingException(JsonMessages.PARSER_EXPECTED_EOF(token), getLastCharLocation()); } @@ -421,27 +431,35 @@ private boolean isEmpty() { } } - private abstract static class Context { + private abstract class Context { Context next; abstract Event getNextEvent(); abstract void skip(); - } - private final class NoneContext extends Context { - @Override - public Event getNextEvent() { - // Handle 1. { 2. [ 3. value - JsonToken token = tokenizer.nextToken(); - if (token == JsonToken.CURLYOPEN) { + protected Event nextEventIfValueOrObjectOrArrayStart(JsonToken token) { + if (token.isValue()) { + return token.getEvent(); + } else if (token == CURLYOPEN) { stack.push(currentContext); currentContext = new ObjectContext(); return Event.START_OBJECT; - } else if (token == JsonToken.SQUAREOPEN) { + } else if (token == SQUAREOPEN) { stack.push(currentContext); currentContext = new ArrayContext(); return Event.START_ARRAY; - } else if (token.isValue()) { - return token.getEvent(); + } + return null; + } + } + + private final class NoneContext extends Context { + @Override + public Event getNextEvent() { + // Handle 1. { 2. [ 3. value + JsonToken token = tokenizer.nextToken(); + Event event = nextEventIfValueOrObjectOrArrayStart(token); + if (event != null) { + return event; } throw parsingException(token, "[CURLYOPEN, SQUAREOPEN, STRING, NUMBER, TRUE, FALSE, NULL]"); } @@ -458,9 +476,38 @@ private JsonParsingException parsingException(JsonToken token, String expectedTo JsonMessages.PARSER_INVALID_TOKEN(token, location, expectedTokens), location); } - private final class ObjectContext extends Context { + private abstract class SkippingContext extends Context { + private final JsonToken openToken; + private final JsonToken closeToken; + + private SkippingContext(JsonToken openToken, JsonToken closeToken) { + this.openToken = Objects.requireNonNull(openToken); + this.closeToken = Objects.requireNonNull(closeToken); + } + + @Override + void skip() { + JsonToken token; + int depth = 1; + do { + token = tokenizer.nextToken(); + if (token == closeToken) { + depth--; + } + if (token == openToken) { + depth++; + } + } while (!(token == closeToken && depth == 0)); + } + } + + private final class ObjectContext extends SkippingContext { private boolean firstValue = true; + private ObjectContext() { + super(CURLYOPEN, CURLYCLOSE); + } + /* * Some more things could be optimized. For example, instead * tokenizer.nextToken(), one could use tokenizer.matchColonToken() to @@ -472,7 +519,7 @@ private final class ObjectContext extends Context { public Event getNextEvent() { // Handle 1. } 2. name:value 3. ,name:value JsonToken token = tokenizer.nextToken(); - if (token == JsonToken.EOF) { + if (token == EOF) { switch (currentEvent) { case START_OBJECT: throw parsingException(token, "[STRING, CURLYCLOSE]"); @@ -483,70 +530,49 @@ public Event getNextEvent() { } } else if (currentEvent == Event.KEY_NAME) { // Handle 1. :value - if (token != JsonToken.COLON) { + if (token != COLON) { throw parsingException(token, "[COLON]"); } token = tokenizer.nextToken(); - if (token.isValue()) { - return token.getEvent(); - } else if (token == JsonToken.CURLYOPEN) { - stack.push(currentContext); - currentContext = new ObjectContext(); - return Event.START_OBJECT; - } else if (token == JsonToken.SQUAREOPEN) { - stack.push(currentContext); - currentContext = new ArrayContext(); - return Event.START_ARRAY; + Event event = nextEventIfValueOrObjectOrArrayStart(token); + if (event != null) { + return event; } throw parsingException(token, "[CURLYOPEN, SQUAREOPEN, STRING, NUMBER, TRUE, FALSE, NULL]"); } else { // Handle 1. } 2. name 3. ,name - if (token == JsonToken.CURLYCLOSE) { + if (token == CURLYCLOSE) { currentContext = stack.pop(); return Event.END_OBJECT; } if (firstValue) { firstValue = false; } else { - if (token != JsonToken.COMMA) { + if (token != COMMA) { throw parsingException(token, "[COMMA]"); } token = tokenizer.nextToken(); } - if (token == JsonToken.STRING) { + if (token == STRING) { return Event.KEY_NAME; } throw parsingException(token, "[STRING]"); } } - - @Override - void skip() { - JsonToken token; - int depth = 1; - do { - token = tokenizer.nextToken(); - switch (token) { - case CURLYCLOSE: - depth--; - break; - case CURLYOPEN: - depth++; - break; - } - } while (!(token == JsonToken.CURLYCLOSE && depth == 0)); - } - } - private final class ArrayContext extends Context { + private final class ArrayContext extends SkippingContext { private boolean firstValue = true; + private ArrayContext() { + super(SQUAREOPEN, SQUARECLOSE); + } + // Handle 1. ] 2. value 3. ,value @Override public Event getNextEvent() { JsonToken token = tokenizer.nextToken(); - if (token == JsonToken.EOF) { + if (token == EOF) { switch (currentEvent) { case START_ARRAY: throw parsingException(token, "[CURLYOPEN, SQUAREOPEN, STRING, NUMBER, TRUE, FALSE, NULL]"); @@ -554,48 +580,24 @@ public Event getNextEvent() { throw parsingException(token, "[COMMA, CURLYCLOSE]"); } } - if (token == JsonToken.SQUARECLOSE) { + if (token == SQUARECLOSE) { currentContext = stack.pop(); return Event.END_ARRAY; } if (firstValue) { firstValue = false; } else { - if (token != JsonToken.COMMA) { + if (token != COMMA) { throw parsingException(token, "[COMMA]"); } token = tokenizer.nextToken(); } - if (token.isValue()) { - return token.getEvent(); - } else if (token == JsonToken.CURLYOPEN) { - stack.push(currentContext); - currentContext = new ObjectContext(); - return Event.START_OBJECT; - } else if (token == JsonToken.SQUAREOPEN) { - stack.push(currentContext); - currentContext = new ArrayContext(); - return Event.START_ARRAY; + + Event event = nextEventIfValueOrObjectOrArrayStart(token); + if (event != null) { + return event; } throw parsingException(token, "[CURLYOPEN, SQUAREOPEN, STRING, NUMBER, TRUE, FALSE, NULL]"); } - - @Override - void skip() { - JsonToken token; - int depth = 1; - do { - token = tokenizer.nextToken(); - switch (token) { - case SQUARECLOSE: - depth--; - break; - case SQUAREOPEN: - depth++; - break; - } - } while (!(token == JsonToken.SQUARECLOSE && depth == 0)); - } } - } From 872f0e1d94bf7eae017c8614ffb2ef74dc7b176a Mon Sep 17 00:00:00 2001 From: Anton Pinsky Date: Tue, 14 Nov 2023 02:20:52 +0100 Subject: [PATCH 3/4] [#112]Small POM plugin updates Signed-off-by: Anton Pinsky --- pom.xml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/pom.xml b/pom.xml index 64168c70..cac37a4e 100644 --- a/pom.xml +++ b/pom.xml @@ -94,7 +94,7 @@ ${config.dir}/exclude.xml false Low - 4.7.3.6 + 4.8.1.0 2.1.3 @@ -323,7 +323,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 3.6.0 + 3.6.2 org.apache.maven.plugins @@ -343,7 +343,7 @@ org.apache.maven.plugins maven-dependency-plugin - 3.6.0 + 3.6.1 org.apache.maven.plugins @@ -353,7 +353,7 @@ org.apache.maven.plugins maven-clean-plugin - 3.3.1 + 3.3.2 org.apache.maven.plugins @@ -368,7 +368,7 @@ org.apache.maven.plugins maven-surefire-plugin - 3.1.2 + 3.2.2 org.apache.maven.plugins @@ -429,7 +429,7 @@ org.hamcrest hamcrest-core - 1.3 + 2.2 test @@ -458,7 +458,7 @@ com.sun.xml.bind jaxb-impl - 3.0.1 + 4.0.4 From b8b874b1060e35a336cf2d4318d4a971f4db0052 Mon Sep 17 00:00:00 2001 From: Anton Pinsky Date: Tue, 14 Nov 2023 21:35:32 +0100 Subject: [PATCH 4/4] [#112]Removed static imports; replaced tabs with spaces Signed-off-by: Anton Pinsky --- .../org/eclipse/parsson/JsonParserImpl.java | 181 +++++++++--------- 1 file changed, 86 insertions(+), 95 deletions(-) diff --git a/impl/src/main/java/org/eclipse/parsson/JsonParserImpl.java b/impl/src/main/java/org/eclipse/parsson/JsonParserImpl.java index a7beb5cf..459d1fb3 100644 --- a/impl/src/main/java/org/eclipse/parsson/JsonParserImpl.java +++ b/impl/src/main/java/org/eclipse/parsson/JsonParserImpl.java @@ -44,15 +44,6 @@ import org.eclipse.parsson.JsonTokenizer.JsonToken; -import static org.eclipse.parsson.JsonTokenizer.JsonToken.COLON; -import static org.eclipse.parsson.JsonTokenizer.JsonToken.COMMA; -import static org.eclipse.parsson.JsonTokenizer.JsonToken.CURLYCLOSE; -import static org.eclipse.parsson.JsonTokenizer.JsonToken.CURLYOPEN; -import static org.eclipse.parsson.JsonTokenizer.JsonToken.EOF; -import static org.eclipse.parsson.JsonTokenizer.JsonToken.SQUARECLOSE; -import static org.eclipse.parsson.JsonTokenizer.JsonToken.SQUAREOPEN; -import static org.eclipse.parsson.JsonTokenizer.JsonToken.STRING; - /** * JSON parser implementation. NoneContext, ArrayContext, ObjectContext is used * to go to next parser state. @@ -199,27 +190,27 @@ public Stream getArrayStream() { 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; - } - }; + 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); } @@ -230,37 +221,37 @@ public Stream> getObjectStream() { 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; - } - }; + 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); } @@ -271,25 +262,25 @@ public Stream getValueStream() { 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; - } - }; + 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); } @@ -319,7 +310,7 @@ private JsonArray getArray(JsonArrayBuilder builder) { } builder.add(getValue()); } - throw parsingException(EOF, "[CURLYOPEN, SQUAREOPEN, STRING, NUMBER, TRUE, FALSE, NULL, SQUARECLOSE]"); + throw parsingException(JsonToken.EOF, "[CURLYOPEN, SQUAREOPEN, STRING, NUMBER, TRUE, FALSE, NULL, SQUARECLOSE]"); } private CharSequence getCharSequence() { @@ -340,7 +331,7 @@ private JsonObject getObject(JsonObjectBuilder builder) { next(); builder.add(key, getValue()); } - throw parsingException(EOF, "[STRING, CURLYCLOSE]"); + throw parsingException(JsonToken.EOF, "[STRING, CURLYCLOSE]"); } @Override @@ -356,7 +347,7 @@ public JsonLocation getLastCharLocation() { public boolean hasNext() { if (stack.isEmpty() && (currentEvent != null && currentEvent.compareTo(Event.KEY_NAME) > 0)) { JsonToken token = tokenizer.nextToken(); - if (token != EOF) { + if (token != JsonToken.EOF) { throw new JsonParsingException(JsonMessages.PARSER_EXPECTED_EOF(token), getLastCharLocation()); } @@ -439,11 +430,11 @@ private abstract class Context { protected Event nextEventIfValueOrObjectOrArrayStart(JsonToken token) { if (token.isValue()) { return token.getEvent(); - } else if (token == CURLYOPEN) { + } else if (token == JsonToken.CURLYOPEN) { stack.push(currentContext); currentContext = new ObjectContext(); return Event.START_OBJECT; - } else if (token == SQUAREOPEN) { + } else if (token == JsonToken.SQUAREOPEN) { stack.push(currentContext); currentContext = new ArrayContext(); return Event.START_ARRAY; @@ -505,7 +496,7 @@ private final class ObjectContext extends SkippingContext { private boolean firstValue = true; private ObjectContext() { - super(CURLYOPEN, CURLYCLOSE); + super(JsonToken.CURLYOPEN, JsonToken.CURLYCLOSE); } /* @@ -519,7 +510,7 @@ private ObjectContext() { public Event getNextEvent() { // Handle 1. } 2. name:value 3. ,name:value JsonToken token = tokenizer.nextToken(); - if (token == EOF) { + if (token == JsonToken.EOF) { switch (currentEvent) { case START_OBJECT: throw parsingException(token, "[STRING, CURLYCLOSE]"); @@ -530,7 +521,7 @@ public Event getNextEvent() { } } else if (currentEvent == Event.KEY_NAME) { // Handle 1. :value - if (token != COLON) { + if (token != JsonToken.COLON) { throw parsingException(token, "[COLON]"); } token = tokenizer.nextToken(); @@ -541,19 +532,19 @@ public Event getNextEvent() { throw parsingException(token, "[CURLYOPEN, SQUAREOPEN, STRING, NUMBER, TRUE, FALSE, NULL]"); } else { // Handle 1. } 2. name 3. ,name - if (token == CURLYCLOSE) { + if (token == JsonToken.CURLYCLOSE) { currentContext = stack.pop(); return Event.END_OBJECT; } if (firstValue) { firstValue = false; } else { - if (token != COMMA) { + if (token != JsonToken.COMMA) { throw parsingException(token, "[COMMA]"); } token = tokenizer.nextToken(); } - if (token == STRING) { + if (token == JsonToken.STRING) { return Event.KEY_NAME; } throw parsingException(token, "[STRING]"); @@ -565,14 +556,14 @@ private final class ArrayContext extends SkippingContext { private boolean firstValue = true; private ArrayContext() { - super(SQUAREOPEN, SQUARECLOSE); + super(JsonToken.SQUAREOPEN, JsonToken.SQUARECLOSE); } // Handle 1. ] 2. value 3. ,value @Override public Event getNextEvent() { JsonToken token = tokenizer.nextToken(); - if (token == EOF) { + if (token == JsonToken.EOF) { switch (currentEvent) { case START_ARRAY: throw parsingException(token, "[CURLYOPEN, SQUAREOPEN, STRING, NUMBER, TRUE, FALSE, NULL]"); @@ -580,14 +571,14 @@ public Event getNextEvent() { throw parsingException(token, "[COMMA, CURLYCLOSE]"); } } - if (token == SQUARECLOSE) { + if (token == JsonToken.SQUARECLOSE) { currentContext = stack.pop(); return Event.END_ARRAY; } if (firstValue) { firstValue = false; } else { - if (token != COMMA) { + if (token != JsonToken.COMMA) { throw parsingException(token, "[COMMA]"); } token = tokenizer.nextToken();