Skip to content

Commit d48215e

Browse files
committed
Merge branch '2.14'
2 parents 05dae02 + 8765e02 commit d48215e

File tree

11 files changed

+3248
-2986
lines changed

11 files changed

+3248
-2986
lines changed

release-notes/VERSION-2.x

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ JSON library.
1616

1717
2.14.0 (not yet released)
1818

19+
#478: Provide implementation of async JSON parser fed by `ByteBufferFeeder`
20+
(requested by Arjen P)
21+
(contributed by @pjfanning)
1922
#577: Improve performance of floating-point number parsing
2023
(contributed by @pjfanning)
2124
#684: Add "JsonPointer#appendProperty" and "JsonPointer#appendIndex"

src/main/java/tools/jackson/core/TokenStreamFactory.java

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1035,7 +1035,11 @@ public abstract JsonParser createParser(ObjectReadContext readCtxt,
10351035
*<p>
10361036
* If this factory does not support non-blocking parsing (either at all,
10371037
* or from byte array),
1038-
* will throw {@link UnsupportedOperationException}
1038+
* will throw {@link UnsupportedOperationException}.
1039+
*<p>
1040+
* Note that JSON-backed factory only supports parsing of UTF-8 encoded JSON content
1041+
* (and US-ASCII since it is proper subset); other encodings are not supported
1042+
* at this point.
10391043
*
10401044
* @param <P> Nominal type of parser constructed and returned
10411045
* @param readCtxt Object read context to use
@@ -1044,10 +1048,37 @@ public abstract JsonParser createParser(ObjectReadContext readCtxt,
10441048
*
10451049
* @throws JacksonException If parser construction or initialization fails
10461050
*/
1047-
public <P extends JsonParser & ByteArrayFeeder> P createNonBlockingByteArrayParser(ObjectReadContext readCtxt) throws JacksonException {
1051+
public <P extends JsonParser & ByteArrayFeeder> P createNonBlockingByteArrayParser(ObjectReadContext readCtxt)
1052+
throws JacksonException {
10481053
return _unsupported("Non-blocking source not (yet?) support for this format ("+getFormatName()+")");
10491054
}
10501055

1056+
/**
1057+
* Optional method for constructing parser for non-blocking parsing
1058+
* via {@link tools.jackson.core.async.ByteBufferFeeder}
1059+
* interface (accessed using {@link JsonParser#nonBlockingInputFeeder()}
1060+
* from constructed instance).
1061+
*<p>
1062+
* If this factory does not support non-blocking parsing (either at all,
1063+
* or from byte array),
1064+
* will throw {@link UnsupportedOperationException}.
1065+
*<p>
1066+
* Note that JSON-backed factory only supports parsing of UTF-8 encoded JSON content
1067+
* (and US-ASCII since it is proper subset); other encodings are not supported
1068+
* at this point.
1069+
*
1070+
* @param <P> Nominal type of parser constructed and returned
1071+
* @param readCtxt Object read context to use
1072+
*
1073+
* @return Non-blocking parser constructed
1074+
*
1075+
* @throws JacksonException If parser construction or initialization fails
1076+
*/
1077+
public <P extends JsonParser & ByteArrayFeeder> P createNonBlockingByteBufferParser(ObjectReadContext readCtxt)
1078+
throws JacksonException {
1079+
return _unsupported("Non-blocking source not (yet?) support for this format ("+getFormatName()+")");
1080+
}
1081+
10511082
/*
10521083
/**********************************************************************
10531084
/* Generator factories with databind context (3.0)

src/main/java/tools/jackson/core/json/JsonFactory.java

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import tools.jackson.core.base.TextualTSFactory;
1313
import tools.jackson.core.io.*;
1414
import tools.jackson.core.json.async.NonBlockingJsonParser;
15+
import tools.jackson.core.json.async.NonBlockingByteBufferJsonParser;
1516
import tools.jackson.core.sym.BinaryNameMatcher;
1617
import tools.jackson.core.sym.ByteQuadsCanonicalizer;
1718
import tools.jackson.core.sym.CharsToNameCanonicalizer;
@@ -328,7 +329,6 @@ public String getRootValueSeparator() {
328329

329330
@Override
330331
public JsonParser createNonBlockingByteArrayParser(ObjectReadContext readCtxt)
331-
throws JacksonException
332332
{
333333
IOContext ioCtxt = _createNonBlockingContext(null);
334334
ByteQuadsCanonicalizer can = _byteSymbolCanonicalizer.makeChild(_factoryFeatures);
@@ -338,10 +338,21 @@ public JsonParser createNonBlockingByteArrayParser(ObjectReadContext readCtxt)
338338
can);
339339
}
340340

341+
@Override
342+
public JsonParser createNonBlockingByteBufferParser(ObjectReadContext readCtxt)
343+
{
344+
IOContext ioCtxt = _createNonBlockingContext(null);
345+
ByteQuadsCanonicalizer can = _byteSymbolCanonicalizer.makeChild(_factoryFeatures);
346+
return new NonBlockingByteBufferJsonParser(readCtxt, ioCtxt,
347+
readCtxt.getStreamReadFeatures(_streamReadFeatures),
348+
readCtxt.getFormatReadFeatures(_formatReadFeatures),
349+
can);
350+
}
351+
341352
protected IOContext _createNonBlockingContext(Object srcRef) {
342353
return new IOContext(_getBufferRecycler(),
343354
ContentReference.rawReference(srcRef), false);
344-
}
355+
}
345356

346357
/*
347358
/**********************************************************************
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
package tools.jackson.core.json.async;
2+
3+
import java.io.IOException;
4+
import java.io.OutputStream;
5+
import java.nio.ByteBuffer;
6+
import java.nio.channels.Channels;
7+
import java.nio.channels.WritableByteChannel;
8+
9+
import tools.jackson.core.JacksonException;
10+
import tools.jackson.core.ObjectReadContext;
11+
import tools.jackson.core.async.ByteBufferFeeder;
12+
import tools.jackson.core.async.NonBlockingInputFeeder;
13+
import tools.jackson.core.io.IOContext;
14+
import tools.jackson.core.sym.ByteQuadsCanonicalizer;
15+
16+
/**
17+
* Non-blocking parser implementation for JSON content that takes its input
18+
* via {@link java.nio.ByteBuffer} instance(s) passed.
19+
*<p>
20+
* NOTE: only supports parsing of UTF-8 encoded content (and 7-bit US-ASCII since
21+
* it is strict subset of UTF-8): other encodings are not supported.
22+
*/
23+
public class NonBlockingByteBufferJsonParser
24+
extends NonBlockingUtf8JsonParserBase
25+
implements ByteBufferFeeder
26+
{
27+
private ByteBuffer _inputBuffer = ByteBuffer.wrap(NO_BYTES);
28+
29+
public NonBlockingByteBufferJsonParser(ObjectReadContext readCtxt, IOContext ctxt,
30+
int stdFeatures, int formatReadFeatures, ByteQuadsCanonicalizer sym) {
31+
super(readCtxt, ctxt, stdFeatures, formatReadFeatures, sym);
32+
}
33+
34+
@Override
35+
public NonBlockingInputFeeder nonBlockingInputFeeder() {
36+
return this;
37+
}
38+
39+
@Override
40+
public void feedInput(final ByteBuffer byteBuffer) throws JacksonException {
41+
// Must not have remaining input
42+
if (_inputPtr < _inputEnd) {
43+
_reportError("Still have %d undecoded bytes, should not call 'feedInput'", _inputEnd - _inputPtr);
44+
}
45+
46+
final int start = byteBuffer.position();
47+
final int end = byteBuffer.limit();
48+
49+
if (end < start) {
50+
_reportError("Input end (%d) may not be before start (%d)", end, start);
51+
}
52+
// and shouldn't have been marked as end-of-input
53+
if (_endOfInput) {
54+
_reportError("Already closed, can not feed more input");
55+
}
56+
// Time to update pointers first
57+
_currInputProcessed += _origBufferLen;
58+
59+
// Also need to adjust row start, to work as if it extended into the past wrt new buffer
60+
_currInputRowStart = start - (_inputEnd - _currInputRowStart);
61+
62+
// And then update buffer settings
63+
_currBufferStart = start;
64+
_inputBuffer = byteBuffer;
65+
_inputPtr = start;
66+
_inputEnd = end;
67+
_origBufferLen = end - start;
68+
}
69+
70+
@Override
71+
public int releaseBuffered(final OutputStream out) throws JacksonException {
72+
final int avail = _inputEnd - _inputPtr;
73+
if (avail > 0) {
74+
final WritableByteChannel channel = Channels.newChannel(out);
75+
try {
76+
channel.write(_inputBuffer);
77+
} catch (IOException e) {
78+
throw _wrapIOFailure(e);
79+
}
80+
}
81+
return avail;
82+
}
83+
84+
@Override
85+
protected byte getNextSignedByteFromBuffer() {
86+
return _inputBuffer.get(_inputPtr++);
87+
}
88+
89+
@Override
90+
protected int getNextUnsignedByteFromBuffer() {
91+
return _inputBuffer.get(_inputPtr++) & 0xFF;
92+
}
93+
94+
@Override
95+
protected byte getByteFromBuffer(final int ptr) {
96+
return _inputBuffer.get(ptr);
97+
}
98+
}

0 commit comments

Comments
 (0)