Skip to content

Commit d02ac0f

Browse files
authored
Merge pull request #877 from rikkarth/feat/871-strictMode
StrictMode Implementation for JSONArray
2 parents cfd4761 + 3200275 commit d02ac0f

File tree

6 files changed

+764
-109
lines changed

6 files changed

+764
-109
lines changed

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

Lines changed: 85 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -75,19 +75,31 @@ public JSONArray() {
7575
}
7676

7777
/**
78-
* Construct a JSONArray from a JSONTokener.
78+
* Constructs a JSONArray from a JSONTokener.
79+
* <p>
80+
* This constructor reads the JSONTokener to parse a JSON array. It uses the default JSONParserConfiguration.
7981
*
80-
* @param x
81-
* A JSONTokener
82-
* @throws JSONException
83-
* If there is a syntax error.
82+
* @param x A JSONTokener
83+
* @throws JSONException If there is a syntax error.
8484
*/
8585
public JSONArray(JSONTokener x) throws JSONException {
86+
this(x, new JSONParserConfiguration());
87+
}
88+
89+
/**
90+
* Constructs a JSONArray from a JSONTokener and a JSONParserConfiguration.
91+
* JSONParserConfiguration contains strictMode turned off (false) by default.
92+
*
93+
* @param x A JSONTokener instance from which the JSONArray is constructed.
94+
* @param jsonParserConfiguration A JSONParserConfiguration instance that controls the behavior of the parser.
95+
* @throws JSONException If a syntax error occurs during the construction of the JSONArray.
96+
*/
97+
public JSONArray(JSONTokener x, JSONParserConfiguration jsonParserConfiguration) throws JSONException {
8698
this();
8799
if (x.nextClean() != '[') {
88100
throw x.syntaxError("A JSONArray text must start with '['");
89101
}
90-
102+
91103
char nextChar = x.nextClean();
92104
if (nextChar == 0) {
93105
// array is unclosed. No ']' found, instead EOF
@@ -101,27 +113,34 @@ public JSONArray(JSONTokener x) throws JSONException {
101113
this.myArrayList.add(JSONObject.NULL);
102114
} else {
103115
x.back();
104-
this.myArrayList.add(x.nextValue());
116+
this.myArrayList.add(x.nextValue(jsonParserConfiguration));
105117
}
106118
switch (x.nextClean()) {
107-
case 0:
108-
// array is unclosed. No ']' found, instead EOF
109-
throw x.syntaxError("Expected a ',' or ']'");
110-
case ',':
111-
nextChar = x.nextClean();
112-
if (nextChar == 0) {
119+
case 0:
113120
// array is unclosed. No ']' found, instead EOF
114121
throw x.syntaxError("Expected a ',' or ']'");
115-
}
116-
if (nextChar == ']') {
122+
case ',':
123+
nextChar = x.nextClean();
124+
if (nextChar == 0) {
125+
// array is unclosed. No ']' found, instead EOF
126+
throw x.syntaxError("Expected a ',' or ']'");
127+
}
128+
if (nextChar == ']') {
129+
return;
130+
}
131+
x.back();
132+
break;
133+
case ']':
134+
if (jsonParserConfiguration.isStrictMode()) {
135+
nextChar = x.nextClean();
136+
if (nextChar != 0) {
137+
throw x.syntaxError("invalid character found after end of array: " + nextChar);
138+
}
139+
}
140+
117141
return;
118-
}
119-
x.back();
120-
break;
121-
case ']':
122-
return;
123-
default:
124-
throw x.syntaxError("Expected a ',' or ']'");
142+
default:
143+
throw x.syntaxError("Expected a ',' or ']'");
125144
}
126145
}
127146
}
@@ -138,7 +157,19 @@ public JSONArray(JSONTokener x) throws JSONException {
138157
* If there is a syntax error.
139158
*/
140159
public JSONArray(String source) throws JSONException {
141-
this(new JSONTokener(source));
160+
this(new JSONTokener(source), new JSONParserConfiguration());
161+
}
162+
163+
/**
164+
* Constructs a JSONArray from a source JSON text and a JSONParserConfiguration.
165+
*
166+
* @param source A string that begins with <code>[</code>&nbsp;<small>(left bracket)</small> and
167+
* ends with <code>]</code> &nbsp;<small>(right bracket)</small>.
168+
* @param jsonParserConfiguration A JSONParserConfiguration instance that controls the behavior of the parser.
169+
* @throws JSONException If there is a syntax error.
170+
*/
171+
public JSONArray(String source, JSONParserConfiguration jsonParserConfiguration) throws JSONException {
172+
this(new JSONTokener(source), jsonParserConfiguration);
142173
}
143174

144175
/**
@@ -367,7 +398,7 @@ public Number getNumber(int index) throws JSONException {
367398

368399
/**
369400
* Get the enum value associated with an index.
370-
*
401+
*
371402
* @param <E>
372403
* Enum Type
373404
* @param clazz
@@ -555,7 +586,7 @@ public String join(String separator) throws JSONException {
555586
if (len == 0) {
556587
return "";
557588
}
558-
589+
559590
StringBuilder sb = new StringBuilder(
560591
JSONObject.valueToString(this.myArrayList.get(0)));
561592

@@ -869,7 +900,7 @@ public Integer optIntegerObject(int index, Integer defaultValue) {
869900

870901
/**
871902
* Get the enum value associated with a key.
872-
*
903+
*
873904
* @param <E>
874905
* Enum Type
875906
* @param clazz
@@ -884,7 +915,7 @@ public <E extends Enum<E>> E optEnum(Class<E> clazz, int index) {
884915

885916
/**
886917
* Get the enum value associated with a key.
887-
*
918+
*
888919
* @param <E>
889920
* Enum Type
890921
* @param clazz
@@ -917,8 +948,8 @@ public <E extends Enum<E>> E optEnum(Class<E> clazz, int index, E defaultValue)
917948
}
918949

919950
/**
920-
* Get the optional BigInteger value associated with an index. The
921-
* defaultValue is returned if there is no value for the index, or if the
951+
* Get the optional BigInteger value associated with an index. The
952+
* defaultValue is returned if there is no value for the index, or if the
922953
* value is not a number and cannot be converted to a number.
923954
*
924955
* @param index
@@ -933,8 +964,8 @@ public BigInteger optBigInteger(int index, BigInteger defaultValue) {
933964
}
934965

935966
/**
936-
* Get the optional BigDecimal value associated with an index. The
937-
* defaultValue is returned if there is no value for the index, or if the
967+
* Get the optional BigDecimal value associated with an index. The
968+
* defaultValue is returned if there is no value for the index, or if the
938969
* value is not a number and cannot be converted to a number. If the value
939970
* is float or double, the {@link BigDecimal#BigDecimal(double)}
940971
* constructor will be used. See notes on the constructor for conversion
@@ -1103,7 +1134,7 @@ public Number optNumber(int index, Number defaultValue) {
11031134
if (val instanceof Number){
11041135
return (Number) val;
11051136
}
1106-
1137+
11071138
if (val instanceof String) {
11081139
try {
11091140
return JSONObject.stringToNumber((String) val);
@@ -1180,7 +1211,7 @@ public JSONArray put(Collection<?> value) {
11801211
public JSONArray put(double value) throws JSONException {
11811212
return this.put(Double.valueOf(value));
11821213
}
1183-
1214+
11841215
/**
11851216
* Append a float value. This increases the array's length by one.
11861217
*
@@ -1435,19 +1466,19 @@ public JSONArray put(int index, Object value) throws JSONException {
14351466
*
14361467
* @param collection
14371468
* A Collection.
1438-
* @return this.
1469+
* @return this.
14391470
*/
14401471
public JSONArray putAll(Collection<?> collection) {
14411472
this.addAll(collection, false);
14421473
return this;
14431474
}
1444-
1475+
14451476
/**
14461477
* Put an Iterable's elements in to the JSONArray.
14471478
*
14481479
* @param iter
14491480
* An Iterable.
1450-
* @return this.
1481+
* @return this.
14511482
*/
14521483
public JSONArray putAll(Iterable<?> iter) {
14531484
this.addAll(iter, false);
@@ -1459,7 +1490,7 @@ public JSONArray putAll(Iterable<?> iter) {
14591490
*
14601491
* @param array
14611492
* A JSONArray.
1462-
* @return this.
1493+
* @return this.
14631494
*/
14641495
public JSONArray putAll(JSONArray array) {
14651496
// directly copy the elements from the source array to this one
@@ -1474,7 +1505,7 @@ public JSONArray putAll(JSONArray array) {
14741505
* @param array
14751506
* Array. If the parameter passed is null, or not an array or Iterable, an
14761507
* exception will be thrown.
1477-
* @return this.
1508+
* @return this.
14781509
*
14791510
* @throws JSONException
14801511
* If not an array, JSONArray, Iterable or if an value is non-finite number.
@@ -1485,17 +1516,17 @@ public JSONArray putAll(Object array) throws JSONException {
14851516
this.addAll(array, false);
14861517
return this;
14871518
}
1488-
1519+
14891520
/**
1490-
* Creates a JSONPointer using an initialization string and tries to
1521+
* Creates a JSONPointer using an initialization string and tries to
14911522
* match it to an item within this JSONArray. For example, given a
14921523
* JSONArray initialized with this document:
14931524
* <pre>
14941525
* [
14951526
* {"b":"c"}
14961527
* ]
14971528
* </pre>
1498-
* and this JSONPointer string:
1529+
* and this JSONPointer string:
14991530
* <pre>
15001531
* "/0/b"
15011532
* </pre>
@@ -1508,17 +1539,17 @@ public JSONArray putAll(Object array) throws JSONException {
15081539
public Object query(String jsonPointer) {
15091540
return query(new JSONPointer(jsonPointer));
15101541
}
1511-
1542+
15121543
/**
1513-
* Uses a user initialized JSONPointer and tries to
1544+
* Uses a user initialized JSONPointer and tries to
15141545
* match it to an item within this JSONArray. For example, given a
15151546
* JSONArray initialized with this document:
15161547
* <pre>
15171548
* [
15181549
* {"b":"c"}
15191550
* ]
15201551
* </pre>
1521-
* and this JSONPointer:
1552+
* and this JSONPointer:
15221553
* <pre>
15231554
* "/0/b"
15241555
* </pre>
@@ -1531,23 +1562,23 @@ public Object query(String jsonPointer) {
15311562
public Object query(JSONPointer jsonPointer) {
15321563
return jsonPointer.queryFrom(this);
15331564
}
1534-
1565+
15351566
/**
15361567
* Queries and returns a value from this object using {@code jsonPointer}, or
15371568
* returns null if the query fails due to a missing key.
1538-
*
1569+
*
15391570
* @param jsonPointer the string representation of the JSON pointer
15401571
* @return the queried value or {@code null}
15411572
* @throws IllegalArgumentException if {@code jsonPointer} has invalid syntax
15421573
*/
15431574
public Object optQuery(String jsonPointer) {
15441575
return optQuery(new JSONPointer(jsonPointer));
15451576
}
1546-
1577+
15471578
/**
15481579
* Queries and returns a value from this object using {@code jsonPointer}, or
15491580
* returns null if the query fails due to a missing key.
1550-
*
1581+
*
15511582
* @param jsonPointer The JSON pointer
15521583
* @return the queried value or {@code null}
15531584
* @throws IllegalArgumentException if {@code jsonPointer} has invalid syntax
@@ -1667,11 +1698,11 @@ public String toString() {
16671698

16681699
/**
16691700
* Make a pretty-printed JSON text of this JSONArray.
1670-
*
1701+
*
16711702
* <p>If <pre> {@code indentFactor > 0}</pre> and the {@link JSONArray} has only
16721703
* one element, then the array will be output on a single line:
16731704
* <pre>{@code [1]}</pre>
1674-
*
1705+
*
16751706
* <p>If an array has 2 or more elements, then it will be output across
16761707
* multiple lines: <pre>{@code
16771708
* [
@@ -1683,7 +1714,7 @@ public String toString() {
16831714
* <p><b>
16841715
* Warning: This method assumes that the data structure is acyclical.
16851716
* </b>
1686-
*
1717+
*
16871718
* @param indentFactor
16881719
* The number of spaces to add to each level of indentation.
16891720
* @return a printable, displayable, transmittable representation of the
@@ -1717,11 +1748,11 @@ public Writer write(Writer writer) throws JSONException {
17171748

17181749
/**
17191750
* Write the contents of the JSONArray as JSON text to a writer.
1720-
*
1751+
*
17211752
* <p>If <pre>{@code indentFactor > 0}</pre> and the {@link JSONArray} has only
17221753
* one element, then the array will be output on a single line:
17231754
* <pre>{@code [1]}</pre>
1724-
*
1755+
*
17251756
* <p>If an array has 2 or more elements, then it will be output across
17261757
* multiple lines: <pre>{@code
17271758
* [
@@ -1947,7 +1978,7 @@ private void addAll(Object array, boolean wrap, int recursionDepth, JSONParserCo
19471978
"JSONArray initial value should be a string or collection or array.");
19481979
}
19491980
}
1950-
1981+
19511982
/**
19521983
* Create a new JSONException in a common format for incorrect conversions.
19531984
* @param idx index of the item

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

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -220,12 +220,12 @@ public JSONObject(JSONTokener x, JSONParserConfiguration jsonParserConfiguration
220220
for (;;) {
221221
c = x.nextClean();
222222
switch (c) {
223-
case 0:
224-
throw x.syntaxError("A JSONObject text must end with '}'");
225-
case '}':
226-
return;
227-
default:
228-
key = x.nextSimpleValue(c).toString();
223+
case 0:
224+
throw x.syntaxError("A JSONObject text must end with '}'");
225+
case '}':
226+
return;
227+
default:
228+
key = x.nextSimpleValue(c, jsonParserConfiguration).toString();
229229
}
230230

231231
// The key is followed by ':'.
@@ -244,7 +244,7 @@ public JSONObject(JSONTokener x, JSONParserConfiguration jsonParserConfiguration
244244
throw x.syntaxError("Duplicate key \"" + key + "\"");
245245
}
246246

247-
Object value = x.nextValue();
247+
Object value = x.nextValue(jsonParserConfiguration);
248248
// Only add value if non-null
249249
if (value != null) {
250250
this.put(key, value);
@@ -1247,7 +1247,7 @@ public BigDecimal optBigDecimal(String key, BigDecimal defaultValue) {
12471247
static BigDecimal objectToBigDecimal(Object val, BigDecimal defaultValue) {
12481248
return objectToBigDecimal(val, defaultValue, true);
12491249
}
1250-
1250+
12511251
/**
12521252
* @param val value to convert
12531253
* @param defaultValue default value to return is the conversion doesn't work or is null.

0 commit comments

Comments
 (0)