Skip to content

Commit f93c9c8

Browse files
committed
Fix #194
1 parent 1218c85 commit f93c9c8

File tree

3 files changed

+101
-55
lines changed

3 files changed

+101
-55
lines changed

src/main/java/com/fasterxml/jackson/core/json/UTF8JsonGenerator.java

+3-26
Original file line numberDiff line numberDiff line change
@@ -420,38 +420,17 @@ public void writeString(String text) throws IOException
420420
_writeNull();
421421
return;
422422
}
423-
// First: can we make a local copy of chars that make up text?
423+
// First: if we can't guarantee it all fits, quoted, within output, offline
424424
final int len = text.length();
425-
if (len > _charBufferLength) { // nope: off-line handling
425+
if (len > _outputMaxContiguous) { // nope: off-line handling
426426
_writeStringSegments(text, true);
427427
return;
428428
}
429-
// Output: if we can't guarantee it fits in output buffer, off-line as well:
430-
if (len > _outputMaxContiguous) {
431-
_writeLongString(_charBuffer, 0, len);
432-
return;
433-
}
434429
if ((_outputTail + len) >= _outputEnd) {
435430
_flushBuffer();
436431
}
437432
_outputBuffer[_outputTail++] = BYTE_QUOTE;
438433
_writeStringSegment(text, 0, len); // we checked space already above
439-
/* [JACKSON-462] But that method may have had to expand multi-byte Unicode
440-
* chars, so we must check again
441-
*/
442-
if (_outputTail >= _outputEnd) {
443-
_flushBuffer();
444-
}
445-
_outputBuffer[_outputTail++] = BYTE_QUOTE;
446-
}
447-
448-
private void _writeLongString(char[] text, int offset, int len) throws IOException
449-
{
450-
if (_outputTail >= _outputEnd) {
451-
_flushBuffer();
452-
}
453-
_outputBuffer[_outputTail++] = BYTE_QUOTE;
454-
_writeStringSegments(text, 0, len);
455434
if (_outputTail >= _outputEnd) {
456435
_flushBuffer();
457436
}
@@ -1155,15 +1134,13 @@ private final void _writeStringSegments(String text, boolean addQuotes) throws I
11551134

11561135
int left = text.length();
11571136
int offset = 0;
1158-
final char[] cbuf = _charBuffer;
11591137

11601138
while (left > 0) {
11611139
int len = Math.min(_outputMaxContiguous, left);
1162-
text.getChars(offset, offset+len, cbuf, 0);
11631140
if ((_outputTail + len) > _outputEnd) { // caller must ensure enough space
11641141
_flushBuffer();
11651142
}
1166-
_writeStringSegment(cbuf, 0, len);
1143+
_writeStringSegment(text, offset, len);
11671144
offset += len;
11681145
left -= len;
11691146
}

src/test/java/com/fasterxml/jackson/core/main/TestStringGeneration.java renamed to src/test/java/com/fasterxml/jackson/core/json/StringGenerationTest.java

+77-9
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package com.fasterxml.jackson.core.main;
1+
package com.fasterxml.jackson.core.json;
22

33
import java.io.*;
44

@@ -10,7 +10,7 @@
1010
* Set of basic unit tests for verifying that the string
1111
* generation, including character escaping, works as expected.
1212
*/
13-
public class TestStringGeneration
13+
public class StringGenerationTest
1414
extends BaseTest
1515
{
1616
final static String[] SAMPLES = new String[] {
@@ -23,15 +23,33 @@ public class TestStringGeneration
2323

2424
private final JsonFactory FACTORY = new JsonFactory();
2525

26-
public void testBasicEscaping()
27-
throws Exception
26+
public void testBasicEscaping() throws Exception
2827
{
2928
doTestBasicEscaping(false);
3029
doTestBasicEscaping(true);
3130
}
3231

33-
public void testLongerRandomSingleChunk()
34-
throws Exception
32+
// for [core#194]
33+
public void testMediumStringsBytes() throws Exception
34+
{
35+
_testMediumStrings(true, 1100);
36+
_testMediumStrings(true, 2300);
37+
_testMediumStrings(true, 3800);
38+
_testMediumStrings(true, 7500);
39+
_testMediumStrings(true, 19000);
40+
}
41+
42+
// for [core#194]
43+
public void testMediumStringsChars() throws Exception
44+
{
45+
_testMediumStrings(false, 1100);
46+
_testMediumStrings(false, 2300);
47+
_testMediumStrings(false, 3800);
48+
_testMediumStrings(false, 7500);
49+
_testMediumStrings(false, 19000);
50+
}
51+
52+
public void testLongerRandomSingleChunk() throws Exception
3553
{
3654
/* Let's first generate 100k of pseudo-random characters, favoring
3755
* 7-bit ascii range
@@ -43,8 +61,7 @@ public void testLongerRandomSingleChunk()
4361
}
4462
}
4563

46-
public void testLongerRandomMultiChunk()
47-
throws Exception
64+
public void testLongerRandomMultiChunk() throws Exception
4865
{
4966
/* Let's first generate 100k of pseudo-random characters, favoring
5067
* 7-bit ascii range
@@ -62,6 +79,29 @@ public void testLongerRandomMultiChunk()
6279
/**********************************************************
6380
*/
6481

82+
private String _generareMediumText(int minLen)
83+
{
84+
StringBuilder sb = new StringBuilder(minLen + 1000);
85+
Random rnd = new Random(minLen);
86+
do {
87+
switch (rnd.nextInt() % 4) {
88+
case 0:
89+
sb.append(" foo");
90+
break;
91+
case 1:
92+
sb.append(" bar");
93+
break;
94+
case 2:
95+
sb.append(String.valueOf(sb.length()));
96+
break;
97+
default:
98+
sb.append(" \"stuff\"");
99+
break;
100+
}
101+
} while (sb.length() < minLen);
102+
return sb.toString();
103+
}
104+
65105
private String generateRandom(int len)
66106
{
67107
StringBuilder sb = new StringBuilder(len+1000); // pad for surrogates
@@ -84,8 +124,36 @@ private String generateRandom(int len)
84124
}
85125
}
86126
return sb.toString();
87-
}
127+
}
128+
129+
private void _testMediumStrings(boolean useBinary, int length) throws Exception
130+
{
131+
String text = _generareMediumText(length);
132+
StringWriter sw = new StringWriter();
133+
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
88134

135+
JsonGenerator gen = useBinary ? FACTORY.createGenerator(bytes)
136+
: FACTORY.createGenerator(sw);
137+
gen.writeStartArray();
138+
gen.writeString(text);
139+
gen.writeEndArray();
140+
gen.close();
141+
142+
String json;
143+
if (useBinary) {
144+
json = bytes.toString("UTF-8");
145+
} else {
146+
json = sw.toString();
147+
}
148+
149+
JsonParser p = FACTORY.createParser(json);
150+
assertToken(JsonToken.START_ARRAY, p.nextToken());
151+
assertToken(JsonToken.VALUE_STRING, p.nextToken());
152+
assertEquals(text, p.getText());
153+
assertToken(JsonToken.END_ARRAY, p.nextToken());
154+
p.close();
155+
}
156+
89157
private void doTestBasicEscaping(boolean charArray)
90158
throws Exception
91159
{

src/test/java/com/fasterxml/jackson/core/json/TestJsonGenerator.java

+21-20
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,12 @@
1111
public class TestJsonGenerator
1212
extends com.fasterxml.jackson.core.BaseTest
1313
{
14+
private final JsonFactory JSON_F = new JsonFactory();
15+
1416
// // // First, tests for primitive (non-structured) values
1517

1618
public void testStringWrite() throws Exception
1719
{
18-
JsonFactory jf = new JsonFactory();
1920
String[] inputStrings = new String[] { "", "X", "1234567890" };
2021
for (int useReader = 0; useReader < 2; ++useReader) {
2122
for (int writeString = 0; writeString < 2; ++writeString) {
@@ -24,9 +25,9 @@ public void testStringWrite() throws Exception
2425
JsonGenerator gen;
2526
ByteArrayOutputStream bout = new ByteArrayOutputStream();
2627
if (useReader != 0) {
27-
gen = jf.createGenerator(new OutputStreamWriter(bout, "UTF-8"));
28+
gen = JSON_F.createGenerator(new OutputStreamWriter(bout, "UTF-8"));
2829
} else {
29-
gen = jf.createGenerator(bout, JsonEncoding.UTF8);
30+
gen = JSON_F.createGenerator(bout, JsonEncoding.UTF8);
3031
}
3132
if (writeString > 0) {
3233
gen.writeString(input);
@@ -39,7 +40,7 @@ public void testStringWrite() throws Exception
3940
}
4041
gen.flush();
4142
gen.close();
42-
JsonParser jp = jf.createParser(new ByteArrayInputStream(bout.toByteArray()));
43+
JsonParser jp = JSON_F.createParser(new ByteArrayInputStream(bout.toByteArray()));
4344

4445
JsonToken t = jp.nextToken();
4546
assertNotNull("Document \""+bout.toString("UTF-8")+"\" yielded no tokens", t);
@@ -52,16 +53,16 @@ public void testStringWrite() throws Exception
5253
}
5354
}
5455

55-
public void testIntWrite() throws Exception
56+
public void testIntValueWrite() throws Exception
5657
{
57-
doTestIntWrite(false);
58-
doTestIntWrite(true);
58+
doTestIntValueWrite(false);
59+
doTestIntValueWrite(true);
5960
}
6061

61-
public void testLongWrite() throws Exception
62+
public void testLongValueWrite() throws Exception
6263
{
63-
doTestLongWrite(false);
64-
doTestLongWrite(true);
64+
doTestLongValueWrite(false);
65+
doTestLongValueWrite(true);
6566
}
6667

6768
public void testBooleanWrite() throws Exception
@@ -70,7 +71,7 @@ public void testBooleanWrite() throws Exception
7071
boolean state = (i & 1) == 0;
7172
boolean pad = (i & 2) == 0;
7273
StringWriter sw = new StringWriter();
73-
JsonGenerator gen = new JsonFactory().createGenerator(sw);
74+
JsonGenerator gen = JSON_F.createGenerator(sw);
7475
gen.writeBoolean(state);
7576
if (pad) {
7677
gen.writeRaw(" ");
@@ -95,7 +96,7 @@ public void testNullWrite()
9596
for (int i = 0; i < 2; ++i) {
9697
boolean pad = (i & 1) == 0;
9798
StringWriter sw = new StringWriter();
98-
JsonGenerator gen = new JsonFactory().createGenerator(sw);
99+
JsonGenerator gen = JSON_F.createGenerator(sw);
99100
gen.writeNull();
100101
if (pad) {
101102
gen.writeRaw(" ");
@@ -120,7 +121,7 @@ public void testRootIntsWrite()
120121
throws Exception
121122
{
122123
StringWriter sw = new StringWriter();
123-
JsonGenerator gen = new JsonFactory().createGenerator(sw);
124+
JsonGenerator gen = JSON_F.createGenerator(sw);
124125
gen.writeNumber(1);
125126
gen.writeNumber(2);
126127
gen.writeNumber(-13);
@@ -144,7 +145,7 @@ public void testFieldValueWrites()
144145
throws Exception
145146
{
146147
StringWriter sw = new StringWriter();
147-
JsonGenerator gen = new JsonFactory().createGenerator(sw);
148+
JsonGenerator gen = JSON_F.createGenerator(sw);
148149
gen.writeStartObject();
149150
gen.writeNumberField("long", 3L);
150151
gen.writeNumberField("double", 0.25);
@@ -161,7 +162,7 @@ public void testFieldValueWrites()
161162
public void testOutputContext() throws Exception
162163
{
163164
StringWriter sw = new StringWriter();
164-
JsonGenerator gen = new JsonFactory().createGenerator(sw);
165+
JsonGenerator gen = JSON_F.createGenerator(sw);
165166
JsonStreamContext ctxt = gen.getOutputContext();
166167
assertTrue(ctxt.inRoot());
167168

@@ -232,7 +233,7 @@ public void testOutputContext() throws Exception
232233
/**********************************************************
233234
*/
234235

235-
private void doTestIntWrite(boolean pad) throws Exception
236+
private void doTestIntValueWrite(boolean pad) throws Exception
236237
{
237238
int[] VALUES = new int[] {
238239
0, 1, -9, 32, -32, 57, 189, 2017, -9999, 13240, 123456,
@@ -241,7 +242,7 @@ private void doTestIntWrite(boolean pad) throws Exception
241242
for (int i = 0; i < VALUES.length; ++i) {
242243
int VALUE = VALUES[i];
243244
StringWriter sw = new StringWriter();
244-
JsonGenerator gen = new JsonFactory().createGenerator(sw);
245+
JsonGenerator gen = JSON_F.createGenerator(sw);
245246
gen.writeNumber(VALUE);
246247
if (pad) {
247248
gen.writeRaw(" ");
@@ -263,16 +264,15 @@ private void doTestIntWrite(boolean pad) throws Exception
263264
}
264265
}
265266

266-
private void doTestLongWrite(boolean pad)
267-
throws Exception
267+
private void doTestLongValueWrite(boolean pad) throws Exception
268268
{
269269
long[] VALUES = new long[] {
270270
0L, 1L, -1L, -12005002294L, Long.MIN_VALUE, Long.MAX_VALUE
271271
};
272272
for (int i = 0; i < VALUES.length; ++i) {
273273
long VALUE = VALUES[i];
274274
StringWriter sw = new StringWriter();
275-
JsonGenerator gen = new JsonFactory().createGenerator(sw);
275+
JsonGenerator gen = JSON_F.createGenerator(sw);
276276
gen.writeNumber(VALUE);
277277
if (pad) {
278278
gen.writeRaw(" ");
@@ -293,3 +293,4 @@ private void doTestLongWrite(boolean pad)
293293
}
294294
}
295295
}
296+

0 commit comments

Comments
 (0)