diff --git a/release-notes/CREDITS b/release-notes/CREDITS
index b82698b5b3..63f21d43bc 100644
--- a/release-notes/CREDITS
+++ b/release-notes/CREDITS
@@ -93,3 +93,7 @@ Tanguy Leroux (tlrx@github)
Mikael Staldal (mikaelstaldal@github)
* Contributed fix for #265: `JsonStringEncoder` should allow passing `CharSequence`
(2.8.0)
+
+Kevin Gallardo (newkek@github)
+ * Reported #296: JsonParserSequence skips a token on a switched Parser
+ (2.8.0)
diff --git a/release-notes/VERSION b/release-notes/VERSION
index c26ded7da6..45162a264e 100644
--- a/release-notes/VERSION
+++ b/release-notes/VERSION
@@ -39,6 +39,8 @@ JSON library.
#290: Add `JsonGenerator.canWriteFormattedNumbers()` for introspection
#294: Add `JsonGenerator.writeFieldId(long)` method to support binary formats
with non-String keys
+#296: JsonParserSequence skips a token on a switched Parser
+ (reported by Kevin G)
- Add `JsonParser.currentToken()` and `JsonParser.currentTokenId()` as replacements
for `getCurrentToken()` and `getCurrentTokenId()`, respectively. Existing methods
will likely be deprecated in 2.9.
diff --git a/src/main/java/com/fasterxml/jackson/core/JsonGenerator.java b/src/main/java/com/fasterxml/jackson/core/JsonGenerator.java
index 0048bda7c3..5917f5d9c6 100644
--- a/src/main/java/com/fasterxml/jackson/core/JsonGenerator.java
+++ b/src/main/java/com/fasterxml/jackson/core/JsonGenerator.java
@@ -1681,7 +1681,7 @@ public void writeOmittedField(String fieldName) throws IOException { }
*/
public void copyCurrentEvent(JsonParser p) throws IOException
{
- JsonToken t = p.getCurrentToken();
+ JsonToken t = p.currentToken();
// sanity check; what to do?
if (t == null) {
_reportError("No current event to copy");
@@ -1784,7 +1784,7 @@ public void copyCurrentEvent(JsonParser p) throws IOException
*/
public void copyCurrentStructure(JsonParser p) throws IOException
{
- JsonToken t = p.getCurrentToken();
+ JsonToken t = p.currentToken();
if (t == null) {
_reportError("No current event to copy");
}
diff --git a/src/main/java/com/fasterxml/jackson/core/JsonParser.java b/src/main/java/com/fasterxml/jackson/core/JsonParser.java
index bd30ae513c..90aed56f84 100644
--- a/src/main/java/com/fasterxml/jackson/core/JsonParser.java
+++ b/src/main/java/com/fasterxml/jackson/core/JsonParser.java
@@ -884,7 +884,7 @@ public int currentTokenId() {
/**
* Method that is functionally equivalent to:
*
- * return getCurrentTokenId() == id
+ * return currentTokenId() == id
*
* but may be more efficiently implemented.
*
@@ -899,7 +899,7 @@ public int currentTokenId() {
/**
* Method that is functionally equivalent to:
*
- * return getCurrentTokenId() == id
+ * return currentToken() == t
*
* but may be more efficiently implemented.
*
@@ -956,7 +956,7 @@ public int currentTokenId() { *
* Default implementation is equivalent to: *
- * getCurrentToken() == JsonToken.START_ARRAY + * currentToken() == JsonToken.START_ARRAY ** but may be overridden by custom parser implementations. * @@ -964,15 +964,15 @@ public int currentTokenId() { * start-array marker (such {@link JsonToken#START_ARRAY}); * false if not. */ - public boolean isExpectedStartArrayToken() { return getCurrentToken() == JsonToken.START_ARRAY; } + public boolean isExpectedStartArrayToken() { return currentToken() == JsonToken.START_ARRAY; } /** * Similar to {@link #isExpectedStartArrayToken()}, but checks whether stream * currently points to {@link JsonToken#START_OBJECT}. - * + * * @since 2.5 */ - public boolean isExpectedStartObjectToken() { return getCurrentToken() == JsonToken.START_OBJECT; } + public boolean isExpectedStartObjectToken() { return currentToken() == JsonToken.START_OBJECT; } /* /********************************************************** @@ -1285,12 +1285,12 @@ public short getShortValue() throws IOException * may be thrown to indicate numeric overflow/underflow. */ public boolean getBooleanValue() throws IOException { - JsonToken t = getCurrentToken(); + JsonToken t = currentToken(); if (t == JsonToken.VALUE_TRUE) return true; if (t == JsonToken.VALUE_FALSE) return false; throw new JsonParseException(this, - String.format("Current token (%s) not of boolean type", t)) - .withRequestPayload(_requestPayload); + String.format("Current token (%s) not of boolean type", t)) + .withRequestPayload(_requestPayload); } /** diff --git a/src/main/java/com/fasterxml/jackson/core/filter/FilteringParserDelegate.java b/src/main/java/com/fasterxml/jackson/core/filter/FilteringParserDelegate.java index bf68cd773b..2bb0165ce8 100644 --- a/src/main/java/com/fasterxml/jackson/core/filter/FilteringParserDelegate.java +++ b/src/main/java/com/fasterxml/jackson/core/filter/FilteringParserDelegate.java @@ -146,11 +146,16 @@ public int getMatchCount() { */ @Override public JsonToken getCurrentToken() { return _currToken; } + @Override public JsonToken currentToken() { return _currToken; } @Override public final int getCurrentTokenId() { final JsonToken t = _currToken; return (t == null) ? JsonTokenId.ID_NO_TOKEN : t.id(); } + @Override public final int currentTokenId() { + final JsonToken t = _currToken; + return (t == null) ? JsonTokenId.ID_NO_TOKEN : t.id(); + } @Override public boolean hasCurrentToken() { return _currToken != null; } @Override public boolean hasTokenId(int id) { diff --git a/src/main/java/com/fasterxml/jackson/core/util/JsonParserSequence.java b/src/main/java/com/fasterxml/jackson/core/util/JsonParserSequence.java index 1100d616b5..0c9c4eb960 100644 --- a/src/main/java/com/fasterxml/jackson/core/util/JsonParserSequence.java +++ b/src/main/java/com/fasterxml/jackson/core/util/JsonParserSequence.java @@ -25,6 +25,14 @@ public class JsonParserSequence extends JsonParserDelegate * Index of the next parser in {@link #_parsers}. */ protected int _nextParser; + + /** + * Flag used to indicate that `JsonParser.nextToken()` should not be called, + * due to parser already pointing to a token. + * + * @since 2.8 + */ + protected boolean _suppressNextToken; /* ******************************************************* @@ -35,6 +43,7 @@ public class JsonParserSequence extends JsonParserDelegate protected JsonParserSequence(JsonParser[] parsers) { super(parsers[0]); + _suppressNextToken = delegate.hasCurrentToken(); _parsers = parsers; _nextParser = 1; } @@ -94,15 +103,21 @@ public void close() throws IOException { } @Override - public JsonToken nextToken() throws IOException, JsonParseException + public JsonToken nextToken() throws IOException { + if (delegate == null) { + return null; + } + if (_suppressNextToken) { + _suppressNextToken = false; + return delegate.currentToken(); + } JsonToken t = delegate.nextToken(); - if (t != null) return t; - while (switchToNext()) { - t = delegate.nextToken(); - if (t != null) return t; + while ((t == null) && switchToNext()) { + t = delegate.hasCurrentToken() + ? delegate.currentToken() : delegate.nextToken(); } - return null; + return t; } /* diff --git a/src/test/java/com/fasterxml/jackson/core/json/ParserSequenceTest.java b/src/test/java/com/fasterxml/jackson/core/json/ParserSequenceTest.java index 738fa25d86..f555186f99 100644 --- a/src/test/java/com/fasterxml/jackson/core/json/ParserSequenceTest.java +++ b/src/test/java/com/fasterxml/jackson/core/json/ParserSequenceTest.java @@ -3,6 +3,7 @@ import com.fasterxml.jackson.core.*; import com.fasterxml.jackson.core.util.JsonParserSequence; +@SuppressWarnings("resource") public class ParserSequenceTest extends com.fasterxml.jackson.core.BaseTest { @@ -43,8 +44,22 @@ public void testSimple() throws Exception assertTrue(seq.isClosed()); seq.close(); - // redundant, but call to remove IDE warnings - p1.close(); - p2.close(); + } + + // for [jackson-core#296] + public void testInitialized() throws Exception + { + JsonParser p1 = JSON_FACTORY.createParser("1 2"); + JsonParser p2 = JSON_FACTORY.createParser("3 false"); + // consume '1', move to '2' + assertToken(JsonToken.VALUE_NUMBER_INT, p1.nextToken()); + assertToken(JsonToken.VALUE_NUMBER_INT, p1.nextToken()); + + JsonParserSequence seq = JsonParserSequence.createFlattened(p1, p2); + assertToken(JsonToken.VALUE_NUMBER_INT, seq.nextToken()); + assertEquals(2, seq.getIntValue()); + assertToken(JsonToken.VALUE_NUMBER_INT, seq.nextToken()); + assertEquals(3, seq.getIntValue()); + seq.close(); } } diff --git a/src/test/java/com/fasterxml/jackson/core/json/StringGenerationTest.java b/src/test/java/com/fasterxml/jackson/core/json/StringGenerationTest.java index 86d991fad1..4fd67c1956 100644 --- a/src/test/java/com/fasterxml/jackson/core/json/StringGenerationTest.java +++ b/src/test/java/com/fasterxml/jackson/core/json/StringGenerationTest.java @@ -287,7 +287,7 @@ private void _testLongerRandomMulti(int readMode, String text, boolean charArray } offset += act.length(); } - assertEquals(JsonToken.END_ARRAY, p.getCurrentToken()); + assertEquals(JsonToken.END_ARRAY, p.currentToken()); p.close(); } } diff --git a/src/test/java/com/fasterxml/jackson/core/json/TestParserOverrides.java b/src/test/java/com/fasterxml/jackson/core/json/TestParserOverrides.java index d382428acf..244effd753 100644 --- a/src/test/java/com/fasterxml/jackson/core/json/TestParserOverrides.java +++ b/src/test/java/com/fasterxml/jackson/core/json/TestParserOverrides.java @@ -45,14 +45,14 @@ public void _testTokenAccess(JsonFactory jf, boolean useStream) throws Exception JsonParser jp = useStream ? jf.createParser(new ByteArrayInputStream(DOC.getBytes("UTF-8"))) : jf.createParser(DOC); - assertNull(jp.getCurrentToken()); + assertNull(jp.currentToken()); jp.clearCurrentToken(); - assertNull(jp.getCurrentToken()); + assertNull(jp.currentToken()); assertNull(jp.getEmbeddedObject()); assertToken(JsonToken.START_ARRAY, jp.nextToken()); - assertToken(JsonToken.START_ARRAY, jp.getCurrentToken()); + assertToken(JsonToken.START_ARRAY, jp.currentToken()); jp.clearCurrentToken(); - assertNull(jp.getCurrentToken()); + assertNull(jp.currentToken()); // Also: no codec defined by default try { jp.readValueAsTree(); @@ -69,7 +69,7 @@ private void _testCurrentName(JsonFactory jf, boolean useStream) throws Exceptio JsonParser jp = useStream ? jf.createParser(new ByteArrayInputStream(DOC.getBytes("UTF-8"))) : jf.createParser(new StringReader(DOC)); - assertNull(jp.getCurrentToken()); + assertNull(jp.currentToken()); assertToken(JsonToken.START_OBJECT, jp.nextToken()); assertToken(JsonToken.FIELD_NAME, jp.nextToken()); assertEquals("first", jp.getCurrentName()); @@ -94,9 +94,7 @@ private void _testCurrentName(JsonFactory jf, boolean useStream) throws Exceptio assertToken(JsonToken.END_OBJECT, jp.nextToken()); jp.clearCurrentToken(); - assertNull(jp.getCurrentToken()); + assertNull(jp.currentToken()); jp.close(); } - - } diff --git a/src/test/java/com/fasterxml/jackson/core/json/TestRootValues.java b/src/test/java/com/fasterxml/jackson/core/json/TestRootValues.java index 585dbbee48..625d2845ad 100644 --- a/src/test/java/com/fasterxml/jackson/core/json/TestRootValues.java +++ b/src/test/java/com/fasterxml/jackson/core/json/TestRootValues.java @@ -45,7 +45,7 @@ private void _testBrokeanNumber(boolean useStream) throws Exception // Should fail, right away try { p.nextToken(); - fail("Ought to fail! Instead, got token: "+p.getCurrentToken()); + fail("Ought to fail! Instead, got token: "+p.currentToken()); } catch (JsonParseException e) { verifyException(e, "unexpected character"); } diff --git a/src/test/java/com/fasterxml/jackson/core/main/TestGeneratorCopy.java b/src/test/java/com/fasterxml/jackson/core/main/TestGeneratorCopy.java index 853ecb756d..e9e26f2587 100644 --- a/src/test/java/com/fasterxml/jackson/core/main/TestGeneratorCopy.java +++ b/src/test/java/com/fasterxml/jackson/core/main/TestGeneratorCopy.java @@ -26,7 +26,7 @@ public void testCopyRootTokens() while ((t = jp.nextToken()) != null) { gen.copyCurrentEvent(jp); // should not change parser state: - assertToken(t, jp.getCurrentToken()); + assertToken(t, jp.currentToken()); } jp.close(); gen.close(); @@ -46,14 +46,14 @@ public void testCopyArrayTokens() assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken()); gen.copyCurrentEvent(jp); // should not change parser state: - assertToken(JsonToken.VALUE_NUMBER_INT, jp.getCurrentToken()); + assertToken(JsonToken.VALUE_NUMBER_INT, jp.currentToken()); assertEquals(123, jp.getIntValue()); // And then let's copy the array assertToken(JsonToken.START_ARRAY, jp.nextToken()); gen.copyCurrentStructure(jp); // which will advance parser to matching close Array - assertToken(JsonToken.END_ARRAY, jp.getCurrentToken()); + assertToken(JsonToken.END_ARRAY, jp.currentToken()); jp.close(); gen.close(); @@ -72,7 +72,7 @@ public void testCopyObjectTokens() assertToken(JsonToken.START_OBJECT, jp.nextToken()); gen.copyCurrentStructure(jp); // which will advance parser to matching end Object - assertToken(JsonToken.END_OBJECT, jp.getCurrentToken()); + assertToken(JsonToken.END_OBJECT, jp.currentToken()); jp.close(); gen.close(); diff --git a/src/test/java/com/fasterxml/jackson/core/read/JsonParserTest.java b/src/test/java/com/fasterxml/jackson/core/read/JsonParserTest.java index 498bb9fa7d..55442e1015 100644 --- a/src/test/java/com/fasterxml/jackson/core/read/JsonParserTest.java +++ b/src/test/java/com/fasterxml/jackson/core/read/JsonParserTest.java @@ -226,7 +226,7 @@ private void _testSkipping(int mode) throws Exception // First, skipping of the whole thing assertToken(JsonToken.START_ARRAY, p.nextToken()); p.skipChildren(); - assertEquals(JsonToken.END_ARRAY, p.getCurrentToken()); + assertEquals(JsonToken.END_ARRAY, p.currentToken()); if (!isInputData) { JsonToken t = p.nextToken(); if (t != null) { @@ -242,27 +242,27 @@ private void _testSkipping(int mode) throws Exception assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken()); p.skipChildren(); // shouldn't move - assertToken(JsonToken.VALUE_NUMBER_INT, p.getCurrentToken()); + assertToken(JsonToken.VALUE_NUMBER_INT, p.currentToken()); assertEquals(1, p.getIntValue()); assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken()); // then skip array assertToken(JsonToken.START_ARRAY, p.nextToken()); p.skipChildren(); - assertToken(JsonToken.END_ARRAY, p.getCurrentToken()); + assertToken(JsonToken.END_ARRAY, p.currentToken()); assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken()); assertToken(JsonToken.START_OBJECT, p.nextToken()); p.skipChildren(); - assertToken(JsonToken.END_OBJECT, p.getCurrentToken()); + assertToken(JsonToken.END_OBJECT, p.currentToken()); assertToken(JsonToken.START_ARRAY, p.nextToken()); p.skipChildren(); - assertToken(JsonToken.END_ARRAY, p.getCurrentToken()); + assertToken(JsonToken.END_ARRAY, p.currentToken()); assertToken(JsonToken.START_OBJECT, p.nextToken()); p.skipChildren(); - assertToken(JsonToken.END_OBJECT, p.getCurrentToken()); + assertToken(JsonToken.END_OBJECT, p.currentToken()); assertToken(JsonToken.END_ARRAY, p.nextToken()); diff --git a/src/test/java/com/fasterxml/jackson/core/util/TestDelegates.java b/src/test/java/com/fasterxml/jackson/core/util/TestDelegates.java index 9cce04ac48..8fe7db3304 100644 --- a/src/test/java/com/fasterxml/jackson/core/util/TestDelegates.java +++ b/src/test/java/com/fasterxml/jackson/core/util/TestDelegates.java @@ -18,7 +18,7 @@ public void testParserDelegate() throws IOException JsonParser parser = JSON_F.createParser("[ 1, true, null, { } ]"); JsonParserDelegate del = new JsonParserDelegate(parser); - assertNull(del.getCurrentToken()); + assertNull(del.currentToken()); assertToken(JsonToken.START_ARRAY, del.nextToken()); assertEquals("[", del.getText()); assertToken(JsonToken.VALUE_NUMBER_INT, del.nextToken());