Skip to content

Commit abea194

Browse files
committed
Adding JSONParserConfiguration for configuring the depth of nested maps
1 parent dcac3bc commit abea194

File tree

5 files changed

+115
-34
lines changed

5 files changed

+115
-34
lines changed

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

Lines changed: 57 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -149,18 +149,22 @@ public JSONArray(String source) throws JSONException {
149149
* A Collection.
150150
*/
151151
public JSONArray(Collection<?> collection) {
152-
this(collection, 0);
152+
this(collection, 0, new JSONParserConfiguration());
153153
}
154154

155-
protected JSONArray(Collection<?> collection, int recursionDepth) {
156-
if (recursionDepth > JSONObject.RECURSION_DEPTH_LIMIT) {
157-
throw new JSONException("JSONArray has reached recursion depth limit of " + JSONObject.RECURSION_DEPTH_LIMIT);
155+
public JSONArray(Collection<?> collection, JSONParserConfiguration jsonParserConfiguration) {
156+
this(collection, 0, jsonParserConfiguration);
157+
}
158+
159+
protected JSONArray(Collection<?> collection, int recursionDepth, JSONParserConfiguration jsonParserConfiguration) {
160+
if (recursionDepth > jsonParserConfiguration.getMaxNestingDepth()) {
161+
throw new JSONException("JSONArray has reached recursion depth limit of " + jsonParserConfiguration.getMaxNestingDepth());
158162
}
159163
if (collection == null) {
160164
this.myArrayList = new ArrayList<Object>();
161165
} else {
162166
this.myArrayList = new ArrayList<Object>(collection.size());
163-
this.addAll(collection, true, recursionDepth);
167+
this.addAll(collection, true, recursionDepth, jsonParserConfiguration);
164168
}
165169
}
166170

@@ -1345,7 +1349,27 @@ public JSONArray put(int index, long value) throws JSONException {
13451349
* If a key in the map is <code>null</code>
13461350
*/
13471351
public JSONArray put(int index, Map<?, ?> value) throws JSONException {
1348-
this.put(index, new JSONObject(value));
1352+
this.put(index, new JSONObject(value, new JSONParserConfiguration()));
1353+
return this;
1354+
}
1355+
1356+
/**
1357+
* Put a value in the JSONArray, where the value will be a JSONObject that
1358+
* is produced from a Map.
1359+
*
1360+
* @param index
1361+
* The subscript
1362+
* @param value
1363+
* The Map value.
1364+
* @param jsonParserConfiguration
1365+
* Configuration for recursive depth
1366+
* @return
1367+
* @throws JSONException
1368+
* If the index is negative or if the value is an invalid
1369+
* number.
1370+
*/
1371+
public JSONArray put(int index, Map<?, ?> value, JSONParserConfiguration jsonParserConfiguration) throws JSONException {
1372+
this.put(index, new JSONObject(value, jsonParserConfiguration));
13491373
return this;
13501374
}
13511375

@@ -1790,11 +1814,11 @@ public boolean isEmpty() {
17901814
* variable to keep the count of how nested the object creation is happening.
17911815
*
17921816
*/
1793-
private void addAll(Collection<?> collection, boolean wrap, int recursionDepth) {
1817+
private void addAll(Collection<?> collection, boolean wrap, int recursionDepth, JSONParserConfiguration jsonParserConfiguration) {
17941818
this.myArrayList.ensureCapacity(this.myArrayList.size() + collection.size());
17951819
if (wrap) {
17961820
for (Object o: collection){
1797-
this.put(JSONObject.wrap(o, recursionDepth + 1));
1821+
this.put(JSONObject.wrap(o, recursionDepth + 1, jsonParserConfiguration));
17981822
}
17991823
} else {
18001824
for (Object o: collection){
@@ -1823,7 +1847,14 @@ private void addAll(Iterable<?> iter, boolean wrap) {
18231847
}
18241848
}
18251849
}
1826-
1850+
1851+
/**
1852+
* Add an array's elements to the JSONArray.
1853+
*
1854+
* @param array
1855+
* @param wrap
1856+
* @throws JSONException
1857+
*/
18271858
private void addAll(Object array, boolean wrap) throws JSONException {
18281859
this.addAll(array, wrap, 0);
18291860
}
@@ -1836,23 +1867,37 @@ private void addAll(Object array, boolean wrap) throws JSONException {
18361867
* JSONArray, Collection, or Iterable, an exception will be
18371868
* thrown.
18381869
* @param wrap
1870+
* @param recursionDepth
1871+
*/
1872+
private void addAll(Object array, boolean wrap, int recursionDepth) {
1873+
addAll(array, wrap, recursionDepth, new JSONParserConfiguration());
1874+
}
1875+
/**
1876+
* Add an array's elements to the JSONArray.
1877+
*`
1878+
* @param array
1879+
* Array. If the parameter passed is null, or not an array,
1880+
* JSONArray, Collection, or Iterable, an exception will be
1881+
* thrown.
1882+
* @param wrap
18391883
* {@code true} to call {@link JSONObject#wrap(Object)} for each item,
18401884
* {@code false} to add the items directly
18411885
* @param recursionDepth
18421886
* Variable to keep the count of how nested the object creation is happening.
1843-
*
1887+
* @param recursionDepth
1888+
* Variable to pass parser custom configuration for json parsing.
18441889
* @throws JSONException
18451890
* If not an array or if an array value is non-finite number.
18461891
* @throws NullPointerException
18471892
* Thrown if the array parameter is null.
18481893
*/
1849-
private void addAll(Object array, boolean wrap, int recursionDepth) throws JSONException {
1894+
private void addAll(Object array, boolean wrap, int recursionDepth, JSONParserConfiguration jsonParserConfiguration) throws JSONException {
18501895
if (array.getClass().isArray()) {
18511896
int length = Array.getLength(array);
18521897
this.myArrayList.ensureCapacity(this.myArrayList.size() + length);
18531898
if (wrap) {
18541899
for (int i = 0; i < length; i += 1) {
1855-
this.put(JSONObject.wrap(Array.get(array, i), recursionDepth + 1));
1900+
this.put(JSONObject.wrap(Array.get(array, i), recursionDepth + 1, jsonParserConfiguration));
18561901
}
18571902
} else {
18581903
for (int i = 0; i < length; i += 1) {

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

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,6 @@ public String toString() {
147147
* The map where the JSONObject's properties are kept.
148148
*/
149149
private final Map<String, Object> map;
150-
public static final int RECURSION_DEPTH_LIMIT = 1000;
151150

152151
public Class<? extends Map> getMapType() {
153152
return map.getClass();
@@ -277,16 +276,20 @@ public JSONObject(JSONTokener x) throws JSONException {
277276
* If a key in the map is <code>null</code>
278277
*/
279278
public JSONObject(Map<?, ?> m) {
280-
this(m, 0);
279+
this(m, 0, new JSONParserConfiguration());
280+
}
281+
282+
public JSONObject(Map<?, ?> m, JSONParserConfiguration jsonParserConfiguration) {
283+
this(m, 0, jsonParserConfiguration);
281284
}
282285

283286
/**
284287
* Construct a JSONObject from a map with recursion depth.
285288
*
286289
*/
287-
protected JSONObject(Map<?, ?> m, int recursionDepth) {
288-
if (recursionDepth > RECURSION_DEPTH_LIMIT) {
289-
throw new JSONException("JSONObject has reached recursion depth limit of " + RECURSION_DEPTH_LIMIT);
290+
protected JSONObject(Map<?, ?> m, int recursionDepth, JSONParserConfiguration jsonParserConfiguration) {
291+
if (recursionDepth > jsonParserConfiguration.getMaxNestingDepth()) {
292+
throw new JSONException("JSONObject has reached recursion depth limit of " + jsonParserConfiguration.getMaxNestingDepth());
290293
}
291294
if (m == null) {
292295
this.map = new HashMap<String, Object>();
@@ -299,7 +302,7 @@ protected JSONObject(Map<?, ?> m, int recursionDepth) {
299302
final Object value = e.getValue();
300303
if (value != null) {
301304
testValidity(value);
302-
this.map.put(String.valueOf(e.getKey()), wrap(value, recursionDepth + 1));
305+
this.map.put(String.valueOf(e.getKey()), wrap(value, recursionDepth + 1, jsonParserConfiguration));
303306
}
304307
}
305308
}
@@ -2578,15 +2581,15 @@ public static Object wrap(Object object) {
25782581
return wrap(object, null);
25792582
}
25802583

2581-
public static Object wrap(Object object, int recursionDepth) {
2582-
return wrap(object, null, recursionDepth);
2584+
public static Object wrap(Object object, int recursionDepth, JSONParserConfiguration jsonParserConfiguration) {
2585+
return wrap(object, null, recursionDepth, jsonParserConfiguration);
25832586
}
25842587

25852588
private static Object wrap(Object object, Set<Object> objectsRecord) {
2586-
return wrap(object, objectsRecord, 0);
2589+
return wrap(object, objectsRecord, 0, new JSONParserConfiguration());
25872590
}
25882591

2589-
private static Object wrap(Object object, Set<Object> objectsRecord, int recursionDepth) {
2592+
private static Object wrap(Object object, Set<Object> objectsRecord, int recursionDepth, JSONParserConfiguration jsonParserConfiguration) {
25902593
try {
25912594
if (NULL.equals(object)) {
25922595
return NULL;
@@ -2604,14 +2607,14 @@ private static Object wrap(Object object, Set<Object> objectsRecord, int recursi
26042607

26052608
if (object instanceof Collection) {
26062609
Collection<?> coll = (Collection<?>) object;
2607-
return new JSONArray(coll, recursionDepth);
2610+
return new JSONArray(coll, recursionDepth, jsonParserConfiguration);
26082611
}
26092612
if (object.getClass().isArray()) {
26102613
return new JSONArray(object);
26112614
}
26122615
if (object instanceof Map) {
26132616
Map<?, ?> map = (Map<?, ?>) object;
2614-
return new JSONObject(map, recursionDepth);
2617+
return new JSONObject(map, recursionDepth, jsonParserConfiguration);
26152618
}
26162619
Package objectPackage = object.getClass().getPackage();
26172620
String objectPackageName = objectPackage != null ? objectPackage
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package org.json;
2+
3+
/**
4+
* Configuration object for the JSON parser. The configuration is immutable.
5+
*/
6+
public class JSONParserConfiguration extends ParserConfiguration {
7+
8+
/**
9+
* We can override the default maximum nesting depth if needed.
10+
*/
11+
public static final int DEFAULT_MAXIMUM_NESTING_DEPTH = ParserConfiguration.DEFAULT_MAXIMUM_NESTING_DEPTH;
12+
13+
/**
14+
* Configuration with the default values.
15+
*/
16+
public JSONParserConfiguration() {
17+
this.maxNestingDepth = DEFAULT_MAXIMUM_NESTING_DEPTH;
18+
}
19+
20+
public JSONParserConfiguration(int maxNestingDepth) {
21+
this.maxNestingDepth = maxNestingDepth;
22+
}
23+
24+
@Override
25+
protected JSONParserConfiguration clone() {
26+
return new JSONParserConfiguration(DEFAULT_MAXIMUM_NESTING_DEPTH);
27+
}
28+
29+
}

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

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import org.json.JSONArray;
2929
import org.json.JSONException;
3030
import org.json.JSONObject;
31+
import org.json.JSONParserConfiguration;
3132
import org.json.JSONPointerException;
3233
import org.json.JSONString;
3334
import org.json.JSONTokener;
@@ -1440,15 +1441,15 @@ public void testRecursiveDepthArray() {
14401441
}
14411442

14421443
@Test
1443-
public void testRecursiveDepthAtPosition999Object() {
1444-
HashMap<String, Object> map = JSONObjectTest.buildNestedMap(999);
1444+
public void testRecursiveDepthAtPositionDefaultObject() {
1445+
HashMap<String, Object> map = JSONObjectTest.buildNestedMap(JSONParserConfiguration.DEFAULT_MAXIMUM_NESTING_DEPTH);
14451446
new JSONArray().put(0, map);
14461447
}
14471448

14481449
@Test
14491450
public void testRecursiveDepthAtPosition1000Object() {
14501451
HashMap<String, Object> map = JSONObjectTest.buildNestedMap(1000);
1451-
new JSONArray().put(0, map);
1452+
new JSONArray().put(0, map, new JSONParserConfiguration(1000));
14521453
}
14531454

14541455
@Test(expected = JSONException.class)
@@ -1465,15 +1466,16 @@ public void testRecursiveDepthArrayLimitedMaps() {
14651466
}
14661467

14671468
@Test
1468-
public void testRecursiveDepthArrayFor999Levels() {
1469-
ArrayList<Object> array = buildNestedArray(999);
1470-
new JSONArray(array);
1469+
public void testRecursiveDepthArrayForDefaultLevels() {
1470+
ArrayList<Object> array = buildNestedArray(JSONParserConfiguration.DEFAULT_MAXIMUM_NESTING_DEPTH);
1471+
new JSONArray(array, new JSONParserConfiguration());
14711472
}
14721473

14731474
@Test
14741475
public void testRecursiveDepthArrayFor1000Levels() {
14751476
ArrayList<Object> array = buildNestedArray(1000);
1476-
new JSONArray(array);
1477+
JSONParserConfiguration parserConfiguration = new JSONParserConfiguration(1000);
1478+
new JSONArray(array, parserConfiguration);
14771479
}
14781480

14791481
@Test(expected = JSONException.class)

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import org.json.JSONException;
3333
import org.json.JSONObject;
3434
import org.json.JSONPointerException;
35+
import org.json.JSONParserConfiguration;
3536
import org.json.JSONString;
3637
import org.json.JSONTokener;
3738
import org.json.XML;
@@ -3737,16 +3738,17 @@ public void testCircularReferenceMultipleLevel() {
37373738
}
37383739

37393740
@Test
3740-
public void issue743SerializationMapWith999Objects() {
3741-
HashMap<String, Object> map = buildNestedMap(999);
3741+
public void issue743SerializationMapWith512Objects() {
3742+
HashMap<String, Object> map = buildNestedMap(JSONParserConfiguration.DEFAULT_MAXIMUM_NESTING_DEPTH);
37423743
JSONObject object = new JSONObject(map);
37433744
String jsonString = object.toString();
37443745
}
37453746

37463747
@Test
37473748
public void issue743SerializationMapWith1000Objects() {
37483749
HashMap<String, Object> map = buildNestedMap(1000);
3749-
JSONObject object = new JSONObject(map);
3750+
JSONParserConfiguration parserConfiguration = new JSONParserConfiguration(1000);
3751+
JSONObject object = new JSONObject(map, parserConfiguration);
37503752
String jsonString = object.toString();
37513753
}
37523754

0 commit comments

Comments
 (0)