Skip to content

Commit

Permalink
Fix #194
Browse files Browse the repository at this point in the history
  • Loading branch information
cowtowncoder committed May 26, 2015
1 parent 1218c85 commit f93c9c8
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 55 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -420,38 +420,17 @@ public void writeString(String text) throws IOException
_writeNull();
return;
}
// First: can we make a local copy of chars that make up text?
// First: if we can't guarantee it all fits, quoted, within output, offline
final int len = text.length();
if (len > _charBufferLength) { // nope: off-line handling
if (len > _outputMaxContiguous) { // nope: off-line handling
_writeStringSegments(text, true);
return;
}
// Output: if we can't guarantee it fits in output buffer, off-line as well:
if (len > _outputMaxContiguous) {
_writeLongString(_charBuffer, 0, len);
return;
}
if ((_outputTail + len) >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = BYTE_QUOTE;
_writeStringSegment(text, 0, len); // we checked space already above
/* [JACKSON-462] But that method may have had to expand multi-byte Unicode
* chars, so we must check again
*/
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = BYTE_QUOTE;
}

private void _writeLongString(char[] text, int offset, int len) throws IOException
{
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = BYTE_QUOTE;
_writeStringSegments(text, 0, len);
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
Expand Down Expand Up @@ -1155,15 +1134,13 @@ private final void _writeStringSegments(String text, boolean addQuotes) throws I

int left = text.length();
int offset = 0;
final char[] cbuf = _charBuffer;

while (left > 0) {
int len = Math.min(_outputMaxContiguous, left);
text.getChars(offset, offset+len, cbuf, 0);
if ((_outputTail + len) > _outputEnd) { // caller must ensure enough space
_flushBuffer();
}
_writeStringSegment(cbuf, 0, len);
_writeStringSegment(text, offset, len);
offset += len;
left -= len;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.fasterxml.jackson.core.main;
package com.fasterxml.jackson.core.json;

import java.io.*;

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

private final JsonFactory FACTORY = new JsonFactory();

public void testBasicEscaping()
throws Exception
public void testBasicEscaping() throws Exception
{
doTestBasicEscaping(false);
doTestBasicEscaping(true);
}

public void testLongerRandomSingleChunk()
throws Exception
// for [core#194]
public void testMediumStringsBytes() throws Exception
{
_testMediumStrings(true, 1100);
_testMediumStrings(true, 2300);
_testMediumStrings(true, 3800);
_testMediumStrings(true, 7500);
_testMediumStrings(true, 19000);
}

// for [core#194]
public void testMediumStringsChars() throws Exception
{
_testMediumStrings(false, 1100);
_testMediumStrings(false, 2300);
_testMediumStrings(false, 3800);
_testMediumStrings(false, 7500);
_testMediumStrings(false, 19000);
}

public void testLongerRandomSingleChunk() throws Exception
{
/* Let's first generate 100k of pseudo-random characters, favoring
* 7-bit ascii range
Expand All @@ -43,8 +61,7 @@ public void testLongerRandomSingleChunk()
}
}

public void testLongerRandomMultiChunk()
throws Exception
public void testLongerRandomMultiChunk() throws Exception
{
/* Let's first generate 100k of pseudo-random characters, favoring
* 7-bit ascii range
Expand All @@ -62,6 +79,29 @@ public void testLongerRandomMultiChunk()
/**********************************************************
*/

private String _generareMediumText(int minLen)
{
StringBuilder sb = new StringBuilder(minLen + 1000);
Random rnd = new Random(minLen);
do {
switch (rnd.nextInt() % 4) {
case 0:
sb.append(" foo");
break;
case 1:
sb.append(" bar");
break;
case 2:
sb.append(String.valueOf(sb.length()));
break;
default:
sb.append(" \"stuff\"");
break;
}
} while (sb.length() < minLen);
return sb.toString();
}

private String generateRandom(int len)
{
StringBuilder sb = new StringBuilder(len+1000); // pad for surrogates
Expand All @@ -84,8 +124,36 @@ private String generateRandom(int len)
}
}
return sb.toString();
}
}

private void _testMediumStrings(boolean useBinary, int length) throws Exception
{
String text = _generareMediumText(length);
StringWriter sw = new StringWriter();
ByteArrayOutputStream bytes = new ByteArrayOutputStream();

JsonGenerator gen = useBinary ? FACTORY.createGenerator(bytes)
: FACTORY.createGenerator(sw);
gen.writeStartArray();
gen.writeString(text);
gen.writeEndArray();
gen.close();

String json;
if (useBinary) {
json = bytes.toString("UTF-8");
} else {
json = sw.toString();
}

JsonParser p = FACTORY.createParser(json);
assertToken(JsonToken.START_ARRAY, p.nextToken());
assertToken(JsonToken.VALUE_STRING, p.nextToken());
assertEquals(text, p.getText());
assertToken(JsonToken.END_ARRAY, p.nextToken());
p.close();
}

private void doTestBasicEscaping(boolean charArray)
throws Exception
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@
public class TestJsonGenerator
extends com.fasterxml.jackson.core.BaseTest
{
private final JsonFactory JSON_F = new JsonFactory();

// // // First, tests for primitive (non-structured) values

public void testStringWrite() throws Exception
{
JsonFactory jf = new JsonFactory();
String[] inputStrings = new String[] { "", "X", "1234567890" };
for (int useReader = 0; useReader < 2; ++useReader) {
for (int writeString = 0; writeString < 2; ++writeString) {
Expand All @@ -24,9 +25,9 @@ public void testStringWrite() throws Exception
JsonGenerator gen;
ByteArrayOutputStream bout = new ByteArrayOutputStream();
if (useReader != 0) {
gen = jf.createGenerator(new OutputStreamWriter(bout, "UTF-8"));
gen = JSON_F.createGenerator(new OutputStreamWriter(bout, "UTF-8"));
} else {
gen = jf.createGenerator(bout, JsonEncoding.UTF8);
gen = JSON_F.createGenerator(bout, JsonEncoding.UTF8);
}
if (writeString > 0) {
gen.writeString(input);
Expand All @@ -39,7 +40,7 @@ public void testStringWrite() throws Exception
}
gen.flush();
gen.close();
JsonParser jp = jf.createParser(new ByteArrayInputStream(bout.toByteArray()));
JsonParser jp = JSON_F.createParser(new ByteArrayInputStream(bout.toByteArray()));

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

public void testIntWrite() throws Exception
public void testIntValueWrite() throws Exception
{
doTestIntWrite(false);
doTestIntWrite(true);
doTestIntValueWrite(false);
doTestIntValueWrite(true);
}

public void testLongWrite() throws Exception
public void testLongValueWrite() throws Exception
{
doTestLongWrite(false);
doTestLongWrite(true);
doTestLongValueWrite(false);
doTestLongValueWrite(true);
}

public void testBooleanWrite() throws Exception
Expand All @@ -70,7 +71,7 @@ public void testBooleanWrite() throws Exception
boolean state = (i & 1) == 0;
boolean pad = (i & 2) == 0;
StringWriter sw = new StringWriter();
JsonGenerator gen = new JsonFactory().createGenerator(sw);
JsonGenerator gen = JSON_F.createGenerator(sw);
gen.writeBoolean(state);
if (pad) {
gen.writeRaw(" ");
Expand All @@ -95,7 +96,7 @@ public void testNullWrite()
for (int i = 0; i < 2; ++i) {
boolean pad = (i & 1) == 0;
StringWriter sw = new StringWriter();
JsonGenerator gen = new JsonFactory().createGenerator(sw);
JsonGenerator gen = JSON_F.createGenerator(sw);
gen.writeNull();
if (pad) {
gen.writeRaw(" ");
Expand All @@ -120,7 +121,7 @@ public void testRootIntsWrite()
throws Exception
{
StringWriter sw = new StringWriter();
JsonGenerator gen = new JsonFactory().createGenerator(sw);
JsonGenerator gen = JSON_F.createGenerator(sw);
gen.writeNumber(1);
gen.writeNumber(2);
gen.writeNumber(-13);
Expand All @@ -144,7 +145,7 @@ public void testFieldValueWrites()
throws Exception
{
StringWriter sw = new StringWriter();
JsonGenerator gen = new JsonFactory().createGenerator(sw);
JsonGenerator gen = JSON_F.createGenerator(sw);
gen.writeStartObject();
gen.writeNumberField("long", 3L);
gen.writeNumberField("double", 0.25);
Expand All @@ -161,7 +162,7 @@ public void testFieldValueWrites()
public void testOutputContext() throws Exception
{
StringWriter sw = new StringWriter();
JsonGenerator gen = new JsonFactory().createGenerator(sw);
JsonGenerator gen = JSON_F.createGenerator(sw);
JsonStreamContext ctxt = gen.getOutputContext();
assertTrue(ctxt.inRoot());

Expand Down Expand Up @@ -232,7 +233,7 @@ public void testOutputContext() throws Exception
/**********************************************************
*/

private void doTestIntWrite(boolean pad) throws Exception
private void doTestIntValueWrite(boolean pad) throws Exception
{
int[] VALUES = new int[] {
0, 1, -9, 32, -32, 57, 189, 2017, -9999, 13240, 123456,
Expand All @@ -241,7 +242,7 @@ private void doTestIntWrite(boolean pad) throws Exception
for (int i = 0; i < VALUES.length; ++i) {
int VALUE = VALUES[i];
StringWriter sw = new StringWriter();
JsonGenerator gen = new JsonFactory().createGenerator(sw);
JsonGenerator gen = JSON_F.createGenerator(sw);
gen.writeNumber(VALUE);
if (pad) {
gen.writeRaw(" ");
Expand All @@ -263,16 +264,15 @@ private void doTestIntWrite(boolean pad) throws Exception
}
}

private void doTestLongWrite(boolean pad)
throws Exception
private void doTestLongValueWrite(boolean pad) throws Exception
{
long[] VALUES = new long[] {
0L, 1L, -1L, -12005002294L, Long.MIN_VALUE, Long.MAX_VALUE
};
for (int i = 0; i < VALUES.length; ++i) {
long VALUE = VALUES[i];
StringWriter sw = new StringWriter();
JsonGenerator gen = new JsonFactory().createGenerator(sw);
JsonGenerator gen = JSON_F.createGenerator(sw);
gen.writeNumber(VALUE);
if (pad) {
gen.writeRaw(" ");
Expand All @@ -293,3 +293,4 @@ private void doTestLongWrite(boolean pad)
}
}
}

0 comments on commit f93c9c8

Please sign in to comment.