Skip to content

Commit

Permalink
[#112]Corrected skip methods behavior of JsonParserImpl; (#113)
Browse files Browse the repository at this point in the history
Signed-off-by: Anton Pinsky <anton.pinsky@ionos.com>
  • Loading branch information
api-from-the-ion committed Feb 26, 2024
1 parent c64269c commit dfbe33a
Show file tree
Hide file tree
Showing 5 changed files with 309 additions and 179 deletions.
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -26,3 +26,4 @@ nbproject/
*err_pid*.log
/tck-impl/.gradle/
/tck-impl/build/
/.sdkmanrc
266 changes: 131 additions & 135 deletions impl/src/main/java/org/eclipse/parsson/JsonParserImpl.java
Expand Up @@ -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;
Expand Down Expand Up @@ -190,25 +191,26 @@ public Stream<JsonValue> getArrayStream() {
}
Spliterator<JsonValue> spliterator =
new Spliterators.AbstractSpliterator<JsonValue>(Long.MAX_VALUE, Spliterator.ORDERED) {
@Override
public Spliterator<JsonValue> trySplit() {
return null;
}
@Override
public boolean tryAdvance(Consumer<? super JsonValue> action) {
if (action == null) {
throw new NullPointerException();
}
if (! hasNext()) {
return false;
}
if (next() == JsonParser.Event.END_ARRAY) {
return false;
}
action.accept(getValue());
return true;
}
};
@Override
public Spliterator<JsonValue> trySplit() {
return null;
}

@Override
public boolean tryAdvance(Consumer<? super JsonValue> 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);
}

Expand All @@ -220,35 +222,36 @@ public Stream<Map.Entry<String, JsonValue>> getObjectStream() {
}
Spliterator<Map.Entry<String, JsonValue>> spliterator =
new Spliterators.AbstractSpliterator<Map.Entry<String, JsonValue>>(Long.MAX_VALUE, Spliterator.ORDERED) {
@Override
public Spliterator<Map.Entry<String,JsonValue>> trySplit() {
return null;
}
@Override
public boolean tryAdvance(Consumer<? super Map.Entry<String, JsonValue>> 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;
}
};
@Override
public Spliterator<Map.Entry<String, JsonValue>> trySplit() {
return null;
}

@Override
public boolean tryAdvance(Consumer<? super Map.Entry<String, JsonValue>> 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);
}

Expand All @@ -260,29 +263,30 @@ public Stream<JsonValue> getValueStream() {
}
Spliterator<JsonValue> spliterator =
new Spliterators.AbstractSpliterator<JsonValue>(Long.MAX_VALUE, Spliterator.ORDERED) {
@Override
public Spliterator<JsonValue> trySplit() {
return null;
}
@Override
public boolean tryAdvance(Consumer<? super JsonValue> action) {
if (action == null) {
throw new NullPointerException();
}
if (! hasNext()) {
return false;
}
next();
action.accept(getValue());
return true;
}
};
@Override
public Spliterator<JsonValue> trySplit() {
return null;
}

@Override
public boolean tryAdvance(Consumer<? super JsonValue> 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;
Expand All @@ -291,7 +295,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;
Expand Down Expand Up @@ -418,27 +422,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 == 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;
} 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]");
}
Expand All @@ -455,9 +467,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(JsonToken.CURLYOPEN, JsonToken.CURLYCLOSE);
}

/*
* Some more things could be optimized. For example, instead
* tokenizer.nextToken(), one could use tokenizer.matchColonToken() to
Expand All @@ -484,16 +525,9 @@ public Event getNextEvent() {
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 {
Expand All @@ -516,29 +550,15 @@ public Event getNextEvent() {
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(JsonToken.SQUAREOPEN, JsonToken.SQUARECLOSE);
}

// Handle 1. ] 2. value 3. ,value
@Override
public Event getNextEvent() {
Expand All @@ -563,36 +583,12 @@ public Event getNextEvent() {
}
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));
}
}

}

0 comments on commit dfbe33a

Please sign in to comment.