diff --git a/release-notes/CREDITS-2.x b/release-notes/CREDITS-2.x index 1e895809d5..22f1acceed 100644 --- a/release-notes/CREDITS-2.x +++ b/release-notes/CREDITS-2.x @@ -257,3 +257,7 @@ Jendrik Johannes (jjohannes@github) Jonathan Haber (jhaber@github) * Contributed #573: More customizable TokenFilter inclusion (using `Tokenfilter.Inclusion`) (2.12.0) + +Jeffrey Ye (jeffreye@github) + * Reported #702: `ArrayOutOfBoundException` at `WriterBasedJsonGenerator.writeString(Reader, int)` + (2.12.4) diff --git a/release-notes/VERSION-2.x b/release-notes/VERSION-2.x index dbd2bef52a..3064fbd319 100644 --- a/release-notes/VERSION-2.x +++ b/release-notes/VERSION-2.x @@ -14,6 +14,11 @@ JSON library. === Releases === ------------------------------------------------------------------------ +2.12.4 (not yet released) + +#702: `ArrayOutOfBoundException` at `WriterBasedJsonGenerator.writeString(Reader, int)` + (reported by Jeffrey Y) + 2.12.3 (12-Apr-2021) 2.12.2 (03-Mar-2021) 2.12.1 (08-Jan-2021) diff --git a/src/main/java/com/fasterxml/jackson/core/json/WriterBasedJsonGenerator.java b/src/main/java/com/fasterxml/jackson/core/json/WriterBasedJsonGenerator.java index d5db1de742..70058a813f 100644 --- a/src/main/java/com/fasterxml/jackson/core/json/WriterBasedJsonGenerator.java +++ b/src/main/java/com/fasterxml/jackson/core/json/WriterBasedJsonGenerator.java @@ -430,37 +430,32 @@ public void writeString(String text) throws IOException } @Override - public void writeString(Reader reader, int len) throws IOException { + public void writeString(Reader reader, final int len) throws IOException + { _verifyValueWrite(WRITE_STRING); if (reader == null) { _reportError("null reader"); return; // just to block warnings by lgtm.com } int toRead = (len >= 0) ? len : Integer.MAX_VALUE; - //Add leading quote - if ((_outputTail + len) >= _outputEnd) { + // Add leading quote + if (_outputTail >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = _quoteChar; final char[] buf = _allocateCopyBuffer(); - //read while (toRead > 0) { int toReadNow = Math.min(toRead, buf.length); int numRead = reader.read(buf, 0, toReadNow); if (numRead <= 0) { break; } - if ((_outputTail + len) >= _outputEnd) { - _flushBuffer(); - } _writeString(buf, 0, numRead); - - //decrease tracker toRead -= numRead; } - //Add trailing quote - if ((_outputTail + len) >= _outputEnd) { + // Add trailing quote + if (_outputTail >= _outputEnd) { _flushBuffer(); } _outputBuffer[_outputTail++] = _quoteChar; diff --git a/src/test/java/com/fasterxml/jackson/core/json/StringGenerationFromReaderTest.java b/src/test/java/com/fasterxml/jackson/core/json/StringGenerationFromReaderTest.java index 5f8bc9c03d..f21bda04c6 100644 --- a/src/test/java/com/fasterxml/jackson/core/json/StringGenerationFromReaderTest.java +++ b/src/test/java/com/fasterxml/jackson/core/json/StringGenerationFromReaderTest.java @@ -30,9 +30,10 @@ public void testBasicEscaping() throws Exception // for [core#194] public void testMediumStringsBytes() throws Exception { + final JsonFactory jsonF = new JsonFactory(); for (int mode : ALL_BINARY_MODES) { - for (int size : new int[] { 1100, 2300, 3800, 7500, 19000 }) { - _testMediumStrings(mode, size); + for (int size : new int[] { 1100, 2300, 3800, 7500, 19000, 33333 }) { + _testMediumStrings(jsonF, mode, size); } } } @@ -40,18 +41,18 @@ public void testMediumStringsBytes() throws Exception // for [core#194] public void testMediumStringsChars() throws Exception { + final JsonFactory jsonF = new JsonFactory(); for (int mode : ALL_TEXT_MODES) { - for (int size : new int[] { 1100, 2300, 3800, 7500, 19000 }) { - _testMediumStrings(mode, size); + for (int size : new int[] { 1100, 2300, 3800, 7500, 19000, 33333 }) { + _testMediumStrings(jsonF, mode, size); } } } public void testLongerRandomSingleChunk() throws Exception { - /* Let's first generate 100k of pseudo-random characters, favoring - * 7-bit ascii range - */ + // Let's first generate 100k of pseudo-random characters, favoring + // 7-bit ascii range for (int mode : ALL_TEXT_MODES) { for (int round = 0; round < 80; ++round) { String content = generateRandom(75000+round); @@ -62,9 +63,8 @@ public void testLongerRandomSingleChunk() throws Exception public void testLongerRandomMultiChunk() throws Exception { - /* Let's first generate 100k of pseudo-random characters, favoring - * 7-bit ascii range - */ + // Let's first generate 100k of pseudo-random characters, favoring + // 7-bit ascii range for (int mode : ALL_TEXT_MODES) { for (int round = 0; round < 70; ++round) { String content = generateRandom(73000+round); @@ -126,14 +126,15 @@ private String generateRandom(int len) return sb.toString(); } - private void _testMediumStrings(int readMode, int length) throws Exception + private void _testMediumStrings(JsonFactory jsonF, + int readMode, int length) throws Exception { String text = _generareMediumText(length); StringWriter sw = new StringWriter(); ByteArrayOutputStream bytes = new ByteArrayOutputStream(); - JsonGenerator gen = (readMode != MODE_READER) ? FACTORY.createGenerator(bytes) - : FACTORY.createGenerator(sw); + JsonGenerator gen = (readMode != MODE_READER) ? jsonF.createGenerator(bytes) + : jsonF.createGenerator(sw); gen.writeStartArray(); StringReader reader = new StringReader(text); @@ -143,9 +144,9 @@ private void _testMediumStrings(int readMode, int length) throws Exception JsonParser p; if (readMode == MODE_READER) { - p = FACTORY.createParser(sw.toString()); + p = jsonF.createParser(sw.toString()); } else { - p = createParser(FACTORY, readMode, bytes.toByteArray()); + p = createParser(jsonF, readMode, bytes.toByteArray()); } assertToken(JsonToken.START_ARRAY, p.nextToken()); assertToken(JsonToken.VALUE_STRING, p.nextToken()); @@ -153,7 +154,7 @@ private void _testMediumStrings(int readMode, int length) throws Exception assertToken(JsonToken.END_ARRAY, p.nextToken()); p.close(); } - + private void doTestBasicEscaping() throws Exception { for (int i = 0; i < SAMPLES.length; ++i) {