Skip to content

Commit 8f66865

Browse files
author
rikkarth
committed
Merge branch 'master' into feat/871-strictMode
2 parents 3672b5e + 45dede4 commit 8f66865

5 files changed

Lines changed: 185 additions & 5 deletions

File tree

src/main/java/org/json/JSONArray.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
*/
66

77
import java.io.IOException;
8-
import java.io.StringWriter;
98
import java.io.Writer;
109
import java.lang.reflect.Array;
1110
import java.math.BigDecimal;
@@ -1730,7 +1729,10 @@ public String toString() {
17301729
*/
17311730
@SuppressWarnings("resource")
17321731
public String toString(int indentFactor) throws JSONException {
1733-
StringWriter sw = new StringWriter();
1732+
// each value requires a comma, so multiply the count by 2
1733+
// We don't want to oversize the initial capacity
1734+
int initialSize = myArrayList.size() * 2;
1735+
Writer sw = new StringBuilderWriter(Math.max(initialSize, 16));
17341736
return this.write(sw, indentFactor, 0).toString();
17351737
}
17361738

src/main/java/org/json/JSONObject.java

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66

77
import java.io.Closeable;
88
import java.io.IOException;
9-
import java.io.StringWriter;
109
import java.io.Writer;
1110
import java.lang.annotation.Annotation;
1211
import java.lang.reflect.Field;
@@ -2266,7 +2265,10 @@ public Object optQuery(JSONPointer jsonPointer) {
22662265
*/
22672266
@SuppressWarnings("resource")
22682267
public static String quote(String string) {
2269-
StringWriter sw = new StringWriter();
2268+
if (string == null || string.isEmpty()) {
2269+
return "\"\"";
2270+
}
2271+
Writer sw = new StringBuilderWriter(string.length() + 2);
22702272
try {
22712273
return quote(string, sw).toString();
22722274
} catch (IOException ignored) {
@@ -2665,7 +2667,10 @@ public String toString() {
26652667
*/
26662668
@SuppressWarnings("resource")
26672669
public String toString(int indentFactor) throws JSONException {
2668-
StringWriter w = new StringWriter();
2670+
// 6 characters are the minimum to serialise a key value pair e.g.: "k":1,
2671+
// and we don't want to oversize the initial capacity
2672+
int initialSize = map.size() * 6;
2673+
Writer w = new StringBuilderWriter(Math.max(initialSize, 16));
26692674
return this.write(w, indentFactor, 0).toString();
26702675
}
26712676

@@ -2808,13 +2813,18 @@ static final Writer writeValue(Writer writer, Object value,
28082813
if (value == null || value.equals(null)) {
28092814
writer.write("null");
28102815
} else if (value instanceof JSONString) {
2816+
// JSONString must be checked first, so it can overwrite behaviour of other types below
28112817
Object o;
28122818
try {
28132819
o = ((JSONString) value).toJSONString();
28142820
} catch (Exception e) {
28152821
throw new JSONException(e);
28162822
}
28172823
writer.write(o != null ? o.toString() : quote(value.toString()));
2824+
} else if (value instanceof String) {
2825+
// assuming most values are Strings, so testing it early
2826+
quote(value.toString(), writer);
2827+
return writer;
28182828
} else if (value instanceof Number) {
28192829
// not all Numbers may match actual JSON Numbers. i.e. fractions or Imaginary
28202830
final String numberAsString = numberToString((Number) value);
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
package org.json;
2+
3+
import java.io.IOException;
4+
import java.io.Writer;
5+
6+
/**
7+
* Performance optimised alternative for {@link java.io.StringWriter}
8+
* using internally a {@link StringBuilder} instead of a {@link StringBuffer}.
9+
*/
10+
public class StringBuilderWriter extends Writer {
11+
private final StringBuilder builder;
12+
13+
/**
14+
* Create a new string builder writer using the default initial string-builder buffer size.
15+
*/
16+
public StringBuilderWriter() {
17+
builder = new StringBuilder();
18+
lock = builder;
19+
}
20+
21+
/**
22+
* Create a new string builder writer using the specified initial string-builder buffer size.
23+
*
24+
* @param initialSize The number of {@code char} values that will fit into this buffer
25+
* before it is automatically expanded
26+
*
27+
* @throws IllegalArgumentException If {@code initialSize} is negative
28+
*/
29+
public StringBuilderWriter(int initialSize) {
30+
builder = new StringBuilder(initialSize);
31+
lock = builder;
32+
}
33+
34+
@Override
35+
public void write(int c) {
36+
builder.append((char) c);
37+
}
38+
39+
@Override
40+
public void write(char[] cbuf, int offset, int length) {
41+
if ((offset < 0) || (offset > cbuf.length) || (length < 0) ||
42+
((offset + length) > cbuf.length) || ((offset + length) < 0)) {
43+
throw new IndexOutOfBoundsException();
44+
} else if (length == 0) {
45+
return;
46+
}
47+
builder.append(cbuf, offset, length);
48+
}
49+
50+
@Override
51+
public void write(String str) {
52+
builder.append(str);
53+
}
54+
55+
@Override
56+
public void write(String str, int offset, int length) {
57+
builder.append(str, offset, offset + length);
58+
}
59+
60+
@Override
61+
public StringBuilderWriter append(CharSequence csq) {
62+
write(String.valueOf(csq));
63+
return this;
64+
}
65+
66+
@Override
67+
public StringBuilderWriter append(CharSequence csq, int start, int end) {
68+
if (csq == null) {
69+
csq = "null";
70+
}
71+
return append(csq.subSequence(start, end));
72+
}
73+
74+
@Override
75+
public StringBuilderWriter append(char c) {
76+
write(c);
77+
return this;
78+
}
79+
80+
@Override
81+
public String toString() {
82+
return builder.toString();
83+
}
84+
85+
@Override
86+
public void flush() {
87+
}
88+
89+
@Override
90+
public void close() throws IOException {
91+
}
92+
}

src/test/java/org/json/junit/JSONStringTest.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,22 @@ public void testNullStringValue() throws Exception {
319319
}
320320
}
321321

322+
@Test
323+
public void testEnumJSONString() {
324+
JSONObject jsonObject = new JSONObject();
325+
jsonObject.put("key", MyEnum.MY_ENUM);
326+
assertEquals("{\"key\":\"myJsonString\"}", jsonObject.toString());
327+
}
328+
329+
private enum MyEnum implements JSONString {
330+
MY_ENUM;
331+
332+
@Override
333+
public String toJSONString() {
334+
return "\"myJsonString\"";
335+
}
336+
}
337+
322338
/**
323339
* A JSONString that returns a valid JSON string value.
324340
*/
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package org.json.junit;
2+
3+
import static org.junit.Assert.assertEquals;
4+
5+
import org.json.StringBuilderWriter;
6+
import org.junit.Before;
7+
import org.junit.Test;
8+
9+
public class StringBuilderWriterTest {
10+
private StringBuilderWriter writer;
11+
12+
@Before
13+
public void setUp() {
14+
writer = new StringBuilderWriter();
15+
}
16+
17+
@Test
18+
public void testWriteChar() {
19+
writer.write('a');
20+
assertEquals("a", writer.toString());
21+
}
22+
23+
@Test
24+
public void testWriteCharArray() {
25+
char[] chars = {'a', 'b', 'c'};
26+
writer.write(chars, 0, 3);
27+
assertEquals("abc", writer.toString());
28+
}
29+
30+
@Test
31+
public void testWriteString() {
32+
writer.write("hello");
33+
assertEquals("hello", writer.toString());
34+
}
35+
36+
@Test
37+
public void testWriteStringWithOffsetAndLength() {
38+
writer.write("hello world", 6, 5);
39+
assertEquals("world", writer.toString());
40+
}
41+
42+
@Test
43+
public void testAppendCharSequence() {
44+
writer.append("hello");
45+
assertEquals("hello", writer.toString());
46+
}
47+
48+
@Test
49+
public void testAppendCharSequenceWithStartAndEnd() {
50+
CharSequence csq = "hello world";
51+
writer.append(csq, 6, 11);
52+
assertEquals("world", writer.toString());
53+
}
54+
55+
@Test
56+
public void testAppendChar() {
57+
writer.append('a');
58+
assertEquals("a", writer.toString());
59+
}
60+
}

0 commit comments

Comments
 (0)