Skip to content

Commit 6f6a30a

Browse files
authored
add NonBlockingByteBufferJsonParser (and refactor some NonBlockingJsonParser code to make it more extensible) (#795)
1 parent 1320d99 commit 6f6a30a

12 files changed

+3326
-2975
lines changed

src/main/java/com/fasterxml/jackson/core/JsonFactory.java

+28
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import com.fasterxml.jackson.core.format.MatchStrength;
1313
import com.fasterxml.jackson.core.io.*;
1414
import com.fasterxml.jackson.core.json.*;
15+
import com.fasterxml.jackson.core.json.async.NonBlockingByteBufferJsonParser;
1516
import com.fasterxml.jackson.core.json.async.NonBlockingJsonParser;
1617
import com.fasterxml.jackson.core.sym.ByteQuadsCanonicalizer;
1718
import com.fasterxml.jackson.core.sym.CharsToNameCanonicalizer;
@@ -1241,6 +1242,33 @@ public JsonParser createNonBlockingByteArrayParser() throws IOException
12411242
return new NonBlockingJsonParser(ctxt, _parserFeatures, can);
12421243
}
12431244

1245+
/**
1246+
* Optional method for constructing parser for non-blocking parsing
1247+
* via {@link com.fasterxml.jackson.core.async.ByteBufferFeeder}
1248+
* interface (accessed using {@link JsonParser#getNonBlockingInputFeeder()}
1249+
* from constructed instance).
1250+
*<p>
1251+
* If this factory does not support non-blocking parsing (either at all,
1252+
* or from byte array),
1253+
* will throw {@link UnsupportedOperationException}.
1254+
*<p>
1255+
* Note that JSON-backed factory only supports parsing of UTF-8 encoded JSON content
1256+
* (and US-ASCII since it is proper subset); other encodings are not supported
1257+
* at this point.
1258+
*
1259+
* @since 2.14
1260+
*/
1261+
@Override
1262+
public JsonParser createNonBlockingByteBufferParser() throws IOException
1263+
{
1264+
// 17-May-2017, tatu: Need to take care not to accidentally create JSON parser
1265+
// for non-JSON input:
1266+
_requireJSONFactory("Non-blocking source not (yet?) supported for this format (%s)");
1267+
IOContext ctxt = _createNonBlockingContext(null);
1268+
ByteQuadsCanonicalizer can = _byteSymbolCanonicalizer.makeChild(_factoryFeatures);
1269+
return new NonBlockingByteBufferJsonParser(ctxt, _parserFeatures, can);
1270+
}
1271+
12441272
/*
12451273
/**********************************************************
12461274
/* Generator factories

src/main/java/com/fasterxml/jackson/core/TokenStreamFactory.java

+34
Original file line numberDiff line numberDiff line change
@@ -154,8 +154,42 @@ public abstract class TokenStreamFactory
154154
public abstract JsonParser createParser(String content) throws IOException;
155155
public abstract JsonParser createParser(URL url) throws IOException;
156156

157+
/**
158+
* Optional method for constructing parser for non-blocking parsing
159+
* via {@link com.fasterxml.jackson.core.async.ByteArrayFeeder}
160+
* interface (accessed using {@link JsonParser#getNonBlockingInputFeeder()}
161+
* from constructed instance).
162+
*<p>
163+
* If this factory does not support non-blocking parsing (either at all,
164+
* or from byte array),
165+
* will throw {@link UnsupportedOperationException}.
166+
*<p>
167+
* Note that JSON-backed factory only supports parsing of UTF-8 encoded JSON content
168+
* (and US-ASCII since it is proper subset); other encodings are not supported
169+
* at this point.
170+
*
171+
* @since 2.9
172+
*/
157173
public abstract JsonParser createNonBlockingByteArrayParser() throws IOException;
158174

175+
/**
176+
* Optional method for constructing parser for non-blocking parsing
177+
* via {@link com.fasterxml.jackson.core.async.ByteBufferFeeder}
178+
* interface (accessed using {@link JsonParser#getNonBlockingInputFeeder()}
179+
* from constructed instance).
180+
*<p>
181+
* If this factory does not support non-blocking parsing (either at all,
182+
* or from byte array),
183+
* will throw {@link UnsupportedOperationException}.
184+
*<p>
185+
* Note that JSON-backed factory only supports parsing of UTF-8 encoded JSON content
186+
* (and US-ASCII since it is proper subset); other encodings are not supported
187+
* at this point.
188+
*
189+
* @since 2.14
190+
*/
191+
public abstract JsonParser createNonBlockingByteBufferParser() throws IOException;
192+
159193
/*
160194
/**********************************************************************
161195
/* Factory methods, generators
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
package com.fasterxml.jackson.core.json.async;
2+
3+
import com.fasterxml.jackson.core.async.ByteBufferFeeder;
4+
import com.fasterxml.jackson.core.async.NonBlockingInputFeeder;
5+
import com.fasterxml.jackson.core.io.IOContext;
6+
import com.fasterxml.jackson.core.sym.ByteQuadsCanonicalizer;
7+
8+
import java.io.IOException;
9+
import java.io.OutputStream;
10+
import java.nio.ByteBuffer;
11+
import java.nio.channels.Channels;
12+
import java.nio.channels.WritableByteChannel;
13+
14+
/**
15+
* Non-blocking parser implementation for JSON content.
16+
*<p>
17+
* NOTE: only supports parsing of UTF-8 encoded content (and 7-bit US-ASCII since
18+
* it is strict subset of UTF-8): other encodings are not supported.
19+
*/
20+
public class NonBlockingByteBufferJsonParser
21+
extends NonBlockingUtf8JsonParserBase
22+
implements ByteBufferFeeder {
23+
24+
private ByteBuffer _inputBuffer = ByteBuffer.wrap(NO_BYTES);
25+
26+
public NonBlockingByteBufferJsonParser(IOContext ctxt, int parserFeatures,
27+
ByteQuadsCanonicalizer sym) {
28+
super(ctxt, parserFeatures, sym);
29+
}
30+
31+
@Override
32+
public NonBlockingInputFeeder getNonBlockingInputFeeder() {
33+
return this;
34+
}
35+
36+
@Override
37+
public void feedInput(final ByteBuffer byteBuffer) throws IOException {
38+
// Must not have remaining input
39+
if (_inputPtr < _inputEnd) {
40+
_reportError("Still have %d undecoded bytes, should not call 'feedInput'", _inputEnd - _inputPtr);
41+
}
42+
43+
final int start = byteBuffer.position();
44+
final int end = byteBuffer.limit();
45+
46+
if (end < start) {
47+
_reportError("Input end (%d) may not be before start (%d)", end, start);
48+
}
49+
// and shouldn't have been marked as end-of-input
50+
if (_endOfInput) {
51+
_reportError("Already closed, can not feed more input");
52+
}
53+
// Time to update pointers first
54+
_currInputProcessed += _origBufferLen;
55+
56+
// Also need to adjust row start, to work as if it extended into the past wrt new buffer
57+
_currInputRowStart = start - (_inputEnd - _currInputRowStart);
58+
59+
// And then update buffer settings
60+
_currBufferStart = start;
61+
_inputBuffer = byteBuffer;
62+
_inputPtr = start;
63+
_inputEnd = end;
64+
_origBufferLen = end - start;
65+
}
66+
67+
@Override
68+
public int releaseBuffered(final OutputStream out) throws IOException {
69+
final int avail = _inputEnd - _inputPtr;
70+
if (avail > 0) {
71+
final WritableByteChannel channel = Channels.newChannel(out);
72+
channel.write(_inputBuffer);
73+
}
74+
return avail;
75+
}
76+
77+
@Override
78+
protected byte getNextSignedByteFromBuffer() {
79+
return _inputBuffer.get(_inputPtr++);
80+
}
81+
82+
@Override
83+
protected int getNextUnsignedByteFromBuffer() {
84+
return _inputBuffer.get(_inputPtr++) & 0xFF;
85+
}
86+
87+
@Override
88+
protected byte getByteFromBuffer(final int ptr) {
89+
return _inputBuffer.get(ptr);
90+
}
91+
}

0 commit comments

Comments
 (0)