Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
* wrt. current index, entry count (binary content won't have
* line/column number).
*
* @since 3.1
* @since 3.2
*/
public class ParserReadContextTest extends CBORTestBase
{
Expand Down
1 change: 1 addition & 0 deletions release-notes/VERSION
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ implementations)

#662: (avro) Remove `IOException` from `AvroMapper.schemaFrom()`
method signatures
#674: Smile parser does not update `StreamReadContext` index or entry count

3.1.1 (not yet released)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -378,8 +378,13 @@ public JsonToken nextToken() throws JacksonException
// also: clear any data retained so far
_binaryValue = null;
// Two main modes: values, and property names.
if ((_currToken != JsonToken.PROPERTY_NAME) && _streamReadContext.inObject()) {
return _updateToken(_handlePropertyName());
final boolean inObject = _streamReadContext.inObject();
if ((_currToken != JsonToken.PROPERTY_NAME) && inObject) {
JsonToken t = _handlePropertyName();
if (t == JsonToken.PROPERTY_NAME) {
_streamReadContext.valueRead();
}
return _updateToken(t);
}
if (_inputPtr >= _inputEnd) {
if (!_loadMore()) {
Expand All @@ -388,6 +393,12 @@ public JsonToken nextToken() throws JacksonException
}
final int ch = _inputBuffer[_inputPtr++] & 0xFF;
_typeAsInt = ch;
// 17-Feb-2026, tatu: [dataformats-binary#674] Need to update context index
// for non-Object contexts (Array, root)
// NOTE: should we worry about end markers etc?
if (!inObject) {
_streamReadContext.valueRead();
}
switch (ch >> 5) {
case 0: // short shared string value reference
if (ch != 0) { // 0x0 is invalid
Expand Down Expand Up @@ -621,6 +632,11 @@ public String nextName() throws JacksonException
int ch = _inputBuffer[_inputPtr++] & 0xFF;
// is this needed?
_typeAsInt = ch;
// [dataformats-binary#674] Update context index for property entries
// (but not for END_OBJECT marker 0xFB)
if (ch != 0xFB) {
_streamReadContext.valueRead();
}
switch (ch >> 6) {
case 0: // misc, including end marker
switch (ch) {
Expand Down Expand Up @@ -738,6 +754,7 @@ public boolean nextName(SerializableString str) throws JacksonException
_updateToken(JsonToken.PROPERTY_NAME);
_inputPtr = ptr;
_streamReadContext.setCurrentName("");
_streamReadContext.valueRead(); // [dataformats-binary#674]
return (byteLen == 0);
case 0x30: // long shared
case 0x31:
Expand All @@ -752,6 +769,7 @@ public boolean nextName(SerializableString str) throws JacksonException
_streamReadContext.setCurrentName(name);
_inputPtr = ptr;
_updateToken(JsonToken.PROPERTY_NAME);
_streamReadContext.valueRead(); // [dataformats-binary#674]
return name.equals(str.getValue());
}
//case 0x34: // long ASCII/Unicode name; let's not even try...
Expand All @@ -767,6 +785,7 @@ public boolean nextName(SerializableString str) throws JacksonException
_streamReadContext.setCurrentName(name);
_inputPtr = ptr;
_updateToken(JsonToken.PROPERTY_NAME);
_streamReadContext.valueRead(); // [dataformats-binary#674]
return name.equals(str.getValue());
}
case 2: // short ASCII
Expand All @@ -789,6 +808,7 @@ public boolean nextName(SerializableString str) throws JacksonException
}
_streamReadContext.setCurrentName(name);
_updateToken(JsonToken.PROPERTY_NAME);
_streamReadContext.valueRead(); // [dataformats-binary#674]
return true;
}
}
Expand Down Expand Up @@ -827,6 +847,7 @@ public boolean nextName(SerializableString str) throws JacksonException
}
_streamReadContext.setCurrentName(name);
_updateToken(JsonToken.PROPERTY_NAME);
_streamReadContext.valueRead(); // [dataformats-binary#674]
return true;
}
}
Expand Down Expand Up @@ -862,6 +883,11 @@ public int nextNameMatch(PropertyNameMatcher matcher) throws JacksonException
int ch = _inputBuffer[_inputPtr++] & 0xFF;
// is this needed?
_typeAsInt = ch;
// [dataformats-binary#674] Update context index for property entries
// (but not for END_OBJECT marker 0xFB)
if (ch != 0xFB) {
_streamReadContext.valueRead();
}
switch (ch >> 6) {
case 0: // misc, including end marker
switch (ch) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,11 +118,12 @@ public void endOfInput() {
* implementation
*/

// public boolean nextFieldName(SerializableString str) throws JacksonException
// public String nextTextValue() throws JacksonException
// public int nextIntValue(int defaultValue) throws JacksonException
// public long nextLongValue(long defaultValue) throws JacksonException
// public Boolean nextBooleanValue() throws JacksonException
// public String nextName()
// public boolean nextName(SerializableString str)
// public String nextTextValue()
// public int nextIntValue(int defaultValue)
// public long nextLongValue(long defaultValue)
// public Boolean nextBooleanValue()

@Override
public int releaseBuffered(OutputStream out) throws JacksonException {
Expand Down Expand Up @@ -418,6 +419,13 @@ protected JsonToken _finishHeader(int state) throws JacksonException
*/
private final JsonToken _startValue(int ch) throws JacksonException
{
// [dataformats-binary#674] Update context index for non-Object contexts
// (Array, root).
// Q? Structural markers (END_ARRAY 0xF9, EOF 0xFF)?
if (!_streamReadContext.inObject()) {
// && (ch & 0xFF) != 0xF9 && (ch & 0xFF) != 0xFF) {
_streamReadContext.valueRead();
}
main_switch:
switch ((ch >> 5) & 0x7) {
case 0: // short shared string value reference
Expand Down Expand Up @@ -531,6 +539,11 @@ private final JsonToken _startValue(int ch) throws JacksonException
*/
protected final JsonToken _startFieldName(int ch) throws JacksonException
{
// [dataformats-binary#674] Update context index for property entries
// (but not for END_OBJECT marker 0xFB)
if ((ch & 0xFF) != 0xFB) {
_streamReadContext.valueRead();
}
switch ((ch >> 6) & 3) {
case 0: // misc, including end marker
switch (ch) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
package tools.jackson.dataformat.smile.async;

import org.junit.jupiter.api.Test;

import tools.jackson.core.*;

import static org.junit.jupiter.api.Assertions.*;

public class AsyncParserReadContextTest extends AsyncTestBase
{
// Async version of ParserReadContextTest.keywords()
// [dataformats-binary#674]
@Test
void keywords() throws Exception
{
final String JSON = "{\n"
+"\"key1\" : null,\n"
+"\"key2\" : true,\n"
+"\"key3\" : false,\n"
+"\"key4\" : [ false, null, true ]\n"
+"}"
;

byte[] data = _smileDoc(JSON, true);

// Test with different read sizes to exercise async buffering
_testKeywords(data, 0, 100);
_testKeywords(data, 0, 3);
_testKeywords(data, 0, 1);

_testKeywords(data, 1, 100);
_testKeywords(data, 1, 3);
_testKeywords(data, 1, 1);
}

private void _testKeywords(byte[] data, int offset, int readSize)
{
AsyncReaderWrapper r = asyncForBytes(_smileReader(true), readSize, data, offset);
JsonParser p = r.parser();

TokenStreamContext ctxt = p.streamReadContext();
assertEquals("/", ctxt.toString());
assertTrue(ctxt.inRoot());
assertFalse(ctxt.inArray());
assertFalse(ctxt.inObject());
assertEquals(0, ctxt.getEntryCount());
assertEquals(0, ctxt.getCurrentIndex());

assertToken(JsonToken.START_OBJECT, r.nextToken());

ctxt = p.streamReadContext();
assertFalse(ctxt.inRoot());
assertFalse(ctxt.inArray());
assertTrue(ctxt.inObject());
assertEquals(0, ctxt.getEntryCount());
assertEquals(0, ctxt.getCurrentIndex());

assertToken(JsonToken.PROPERTY_NAME, r.nextToken());
assertEquals("key1", p.currentName());
assertEquals("{\"key1\"}", ctxt.toString());

ctxt = p.streamReadContext();
assertFalse(ctxt.inRoot());
assertFalse(ctxt.inArray());
assertTrue(ctxt.inObject());
assertEquals(0, ctxt.getCurrentIndex());
assertEquals(1, ctxt.getEntryCount());
assertEquals("key1", ctxt.currentName());

assertToken(JsonToken.VALUE_NULL, r.nextToken());
assertEquals("key1", ctxt.currentName());

ctxt = p.streamReadContext();
assertEquals(0, ctxt.getCurrentIndex());
assertEquals(1, ctxt.getEntryCount());

assertToken(JsonToken.PROPERTY_NAME, r.nextToken());
assertEquals("key2", p.currentName());
ctxt = p.streamReadContext();
assertEquals(1, ctxt.getCurrentIndex());
assertEquals(2, ctxt.getEntryCount());
assertEquals("key2", ctxt.currentName());

assertToken(JsonToken.VALUE_TRUE, r.nextToken());
assertEquals(1, ctxt.getCurrentIndex());
assertEquals(2, ctxt.getEntryCount());
assertEquals("key2", ctxt.currentName());

assertToken(JsonToken.PROPERTY_NAME, r.nextToken());
assertEquals("key3", p.currentName());
assertEquals(2, ctxt.getCurrentIndex());
assertEquals(3, ctxt.getEntryCount());
assertToken(JsonToken.VALUE_FALSE, r.nextToken());
assertEquals(2, ctxt.getCurrentIndex());
assertEquals(3, ctxt.getEntryCount());

assertToken(JsonToken.PROPERTY_NAME, r.nextToken());
assertEquals("key4", p.currentName());
assertEquals(3, ctxt.getCurrentIndex());
assertEquals(4, ctxt.getEntryCount());

assertToken(JsonToken.START_ARRAY, r.nextToken());
ctxt = p.streamReadContext();
assertTrue(ctxt.inArray());
assertNull(ctxt.currentName());
assertEquals(0, ctxt.getCurrentIndex());
assertEquals(0, ctxt.getEntryCount());
assertEquals("key4", ctxt.getParent().currentName());

assertToken(JsonToken.VALUE_FALSE, r.nextToken());
assertEquals(0, ctxt.getCurrentIndex());
assertEquals(1, ctxt.getEntryCount());
assertEquals("[0]", ctxt.toString());

assertToken(JsonToken.VALUE_NULL, r.nextToken());
assertEquals(1, ctxt.getCurrentIndex());
assertEquals(2, ctxt.getEntryCount());

assertToken(JsonToken.VALUE_TRUE, r.nextToken());
assertEquals(2, ctxt.getCurrentIndex());
assertEquals(3, ctxt.getEntryCount());

assertToken(JsonToken.END_ARRAY, r.nextToken());

ctxt = p.streamReadContext();
assertTrue(ctxt.inObject());

assertToken(JsonToken.END_OBJECT, r.nextToken());
ctxt = p.streamReadContext();
assertTrue(ctxt.inRoot());
assertNull(ctxt.currentName());

r.close();
}
}
Loading