From 6d811607ddf4922a49fb37e3a813e2a59ca809a7 Mon Sep 17 00:00:00 2001 From: sk02241994 Date: Fri, 3 Nov 2023 19:54:23 +0530 Subject: [PATCH 1/5] Resolving issue #743 - Recursive depth issue found in JSONObject - Recursive depth issue found in JSONArray --- src/main/java/org/json/JSONArray.java | 29 ++++++++++++++----- src/main/java/org/json/JSONObject.java | 26 +++++++++++++++-- .../java/org/json/junit/JSONArrayTest.java | 21 ++++++++++++++ .../java/org/json/junit/JSONObjectTest.java | 17 +++++++++++ 4 files changed, 83 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/json/JSONArray.java b/src/main/java/org/json/JSONArray.java index ed7982f..eec7852 100644 --- a/src/main/java/org/json/JSONArray.java +++ b/src/main/java/org/json/JSONArray.java @@ -149,11 +149,18 @@ public class JSONArray implements Iterable { * A Collection. */ public JSONArray(Collection collection) { + this(collection, 0); + } + + protected JSONArray(Collection collection, int recursionDepth) { + if (recursionDepth > JSONObject.RECURSION_DEPTH_LIMIT) { + throw new JSONException("JSONArray has reached recursion depth limit of " + JSONObject.RECURSION_DEPTH_LIMIT); + } if (collection == null) { this.myArrayList = new ArrayList(); } else { this.myArrayList = new ArrayList(collection.size()); - this.addAll(collection, true); + this.addAll(collection, true, recursionDepth); } } @@ -205,7 +212,7 @@ public class JSONArray implements Iterable { throw new JSONException( "JSONArray initial value should be a string or collection or array."); } - this.addAll(array, true); + this.addAll(array, true, 0); } /** @@ -1779,13 +1786,15 @@ public class JSONArray implements Iterable { * @param wrap * {@code true} to call {@link JSONObject#wrap(Object)} for each item, * {@code false} to add the items directly + * @param recursionDepth + * variable to keep the count of how nested the object creation is happening. * */ - private void addAll(Collection collection, boolean wrap) { + private void addAll(Collection collection, boolean wrap, int recursionDepth) { this.myArrayList.ensureCapacity(this.myArrayList.size() + collection.size()); if (wrap) { for (Object o: collection){ - this.put(JSONObject.wrap(o)); + this.put(JSONObject.wrap(o, recursionDepth + 1)); } } else { for (Object o: collection){ @@ -1815,6 +1824,10 @@ public class JSONArray implements Iterable { } } + private void addAll(Object array, boolean wrap) throws JSONException { + this.addAll(array, wrap, 0); + } + /** * Add an array's elements to the JSONArray. * @@ -1825,19 +1838,21 @@ public class JSONArray implements Iterable { * @param wrap * {@code true} to call {@link JSONObject#wrap(Object)} for each item, * {@code false} to add the items directly + * @param recursionDepth + * Variable to keep the count of how nested the object creation is happening. * * @throws JSONException * If not an array or if an array value is non-finite number. * @throws NullPointerException * Thrown if the array parameter is null. */ - private void addAll(Object array, boolean wrap) throws JSONException { + private void addAll(Object array, boolean wrap, int recursionDepth) throws JSONException { if (array.getClass().isArray()) { int length = Array.getLength(array); this.myArrayList.ensureCapacity(this.myArrayList.size() + length); if (wrap) { for (int i = 0; i < length; i += 1) { - this.put(JSONObject.wrap(Array.get(array, i))); + this.put(JSONObject.wrap(Array.get(array, i), recursionDepth + 1)); } } else { for (int i = 0; i < length; i += 1) { @@ -1850,7 +1865,7 @@ public class JSONArray implements Iterable { // JSONArray this.myArrayList.addAll(((JSONArray)array).myArrayList); } else if (array instanceof Collection) { - this.addAll((Collection)array, wrap); + this.addAll((Collection)array, wrap, recursionDepth); } else if (array instanceof Iterable) { this.addAll((Iterable)array, wrap); } else { diff --git a/src/main/java/org/json/JSONObject.java b/src/main/java/org/json/JSONObject.java index 7f4885e..72c0ebd 100644 --- a/src/main/java/org/json/JSONObject.java +++ b/src/main/java/org/json/JSONObject.java @@ -147,6 +147,7 @@ public class JSONObject { * The map where the JSONObject's properties are kept. */ private final Map map; + public static final int RECURSION_DEPTH_LIMIT = 1000; public Class getMapType() { return map.getClass(); @@ -276,6 +277,17 @@ public class JSONObject { * If a key in the map is null */ public JSONObject(Map m) { + this(m, 0); + } + + /** + * Construct a JSONObject from a map with recursion depth. + * + */ + protected JSONObject(Map m, int recursionDepth) { + if (recursionDepth > RECURSION_DEPTH_LIMIT) { + throw new JSONException("JSONObject has reached recursion depth limit of " + RECURSION_DEPTH_LIMIT); + } if (m == null) { this.map = new HashMap(); } else { @@ -287,7 +299,7 @@ public class JSONObject { final Object value = e.getValue(); if (value != null) { testValidity(value); - this.map.put(String.valueOf(e.getKey()), wrap(value)); + this.map.put(String.valueOf(e.getKey()), wrap(value, recursionDepth + 1)); } } } @@ -2566,7 +2578,15 @@ public class JSONObject { return wrap(object, null); } + public static Object wrap(Object object, int recursionDepth) { + return wrap(object, null, recursionDepth); + } + private static Object wrap(Object object, Set objectsRecord) { + return wrap(object, objectsRecord, 0); + } + + private static Object wrap(Object object, Set objectsRecord, int recursionDepth) { try { if (NULL.equals(object)) { return NULL; @@ -2584,14 +2604,14 @@ public class JSONObject { if (object instanceof Collection) { Collection coll = (Collection) object; - return new JSONArray(coll); + return new JSONArray(coll, recursionDepth); } if (object.getClass().isArray()) { return new JSONArray(object); } if (object instanceof Map) { Map map = (Map) object; - return new JSONObject(map); + return new JSONObject(map, recursionDepth); } Package objectPackage = object.getClass().getPackage(); String objectPackageName = objectPackage != null ? objectPackage diff --git a/src/test/java/org/json/junit/JSONArrayTest.java b/src/test/java/org/json/junit/JSONArrayTest.java index 7b0d52e..44a1d7b 100644 --- a/src/test/java/org/json/junit/JSONArrayTest.java +++ b/src/test/java/org/json/junit/JSONArrayTest.java @@ -1417,4 +1417,25 @@ public class JSONArrayTest { .put(2); assertFalse(ja1.similar(ja3)); } + + @Test(expected = JSONException.class) + public void testRecursiveDepth() { + HashMap map = new HashMap<>(); + map.put("t", map); + new JSONArray().put(map); + } + + @Test(expected = JSONException.class) + public void testRecursiveDepthAtPosition() { + HashMap map = new HashMap<>(); + map.put("t", map); + new JSONArray().put(0, map); + } + + @Test(expected = JSONException.class) + public void testRecursiveDepthArray() { + ArrayList array = new ArrayList<>(); + array.add(array); + new JSONArray(array); + } } diff --git a/src/test/java/org/json/junit/JSONObjectTest.java b/src/test/java/org/json/junit/JSONObjectTest.java index d9adbca..dff4503 100644 --- a/src/test/java/org/json/junit/JSONObjectTest.java +++ b/src/test/java/org/json/junit/JSONObjectTest.java @@ -3718,4 +3718,21 @@ public class JSONObjectTest { assertThrows(JSONException.class, () -> new JSONObject(bean)); } } + + @Test(expected = JSONException.class) + public void issue743SerializationMap() { + HashMap map = new HashMap<>(); + map.put("t", map); + JSONObject object = new JSONObject(map); + String jsonString = object.toString(); + } + + @Test(expected = JSONException.class) + public void testCircularReferenceMultipleLevel() { + HashMap inside = new HashMap<>(); + HashMap jsonObject = new HashMap<>(); + inside.put("inside", jsonObject); + jsonObject.put("test", inside); + new JSONObject(jsonObject); + } } From dcac3bc18e2acbdf617f3debab234bae857fe5b8 Mon Sep 17 00:00:00 2001 From: sk02241994 Date: Tue, 28 Nov 2023 10:29:30 +0530 Subject: [PATCH 2/5] Adding test case for nested json with depth of 999, 1000, 1001 --- .../java/org/json/junit/JSONArrayTest.java | 52 +++++++++++++++++++ .../java/org/json/junit/JSONObjectTest.java | 37 +++++++++++++ 2 files changed, 89 insertions(+) diff --git a/src/test/java/org/json/junit/JSONArrayTest.java b/src/test/java/org/json/junit/JSONArrayTest.java index 44a1d7b..5f50fc7 100644 --- a/src/test/java/org/json/junit/JSONArrayTest.java +++ b/src/test/java/org/json/junit/JSONArrayTest.java @@ -1438,4 +1438,56 @@ public class JSONArrayTest { array.add(array); new JSONArray(array); } + + @Test + public void testRecursiveDepthAtPosition999Object() { + HashMap map = JSONObjectTest.buildNestedMap(999); + new JSONArray().put(0, map); + } + + @Test + public void testRecursiveDepthAtPosition1000Object() { + HashMap map = JSONObjectTest.buildNestedMap(1000); + new JSONArray().put(0, map); + } + + @Test(expected = JSONException.class) + public void testRecursiveDepthAtPosition1001Object() { + HashMap map = JSONObjectTest.buildNestedMap(1001); + new JSONArray().put(0, map); + } + + @Test(expected = JSONException.class) + public void testRecursiveDepthArrayLimitedMaps() { + ArrayList array = new ArrayList<>(); + array.add(array); + new JSONArray(array); + } + + @Test + public void testRecursiveDepthArrayFor999Levels() { + ArrayList array = buildNestedArray(999); + new JSONArray(array); + } + + @Test + public void testRecursiveDepthArrayFor1000Levels() { + ArrayList array = buildNestedArray(1000); + new JSONArray(array); + } + + @Test(expected = JSONException.class) + public void testRecursiveDepthArrayFor1001Levels() { + ArrayList array = buildNestedArray(1001); + new JSONArray(array); + } + + public static ArrayList buildNestedArray(int maxDepth) { + if (maxDepth <= 0) { + return new ArrayList<>(); + } + ArrayList nestedArray = new ArrayList<>(); + nestedArray.add(buildNestedArray(maxDepth - 1)); + return nestedArray; + } } diff --git a/src/test/java/org/json/junit/JSONObjectTest.java b/src/test/java/org/json/junit/JSONObjectTest.java index dff4503..e157fd5 100644 --- a/src/test/java/org/json/junit/JSONObjectTest.java +++ b/src/test/java/org/json/junit/JSONObjectTest.java @@ -3735,4 +3735,41 @@ public class JSONObjectTest { jsonObject.put("test", inside); new JSONObject(jsonObject); } + + @Test + public void issue743SerializationMapWith999Objects() { + HashMap map = buildNestedMap(999); + JSONObject object = new JSONObject(map); + String jsonString = object.toString(); + } + + @Test + public void issue743SerializationMapWith1000Objects() { + HashMap map = buildNestedMap(1000); + JSONObject object = new JSONObject(map); + String jsonString = object.toString(); + } + + @Test(expected = JSONException.class) + public void issue743SerializationMapWith1001Objects() { + HashMap map = buildNestedMap(1001); + JSONObject object = new JSONObject(map); + String jsonString = object.toString(); + } + + /** + * Method to build nested map of max maxDepth + * + * @param maxDepth + * @return + */ + public static HashMap buildNestedMap(int maxDepth) { + if (maxDepth <= 0) { + return new HashMap<>(); + } + HashMap nestedMap = new HashMap<>(); + nestedMap.put("t", buildNestedMap(maxDepth - 1)); + return nestedMap; + } + } From abea194120cbfe684444a9012aac70fafaef5cfa Mon Sep 17 00:00:00 2001 From: sk02241994 Date: Fri, 22 Dec 2023 15:44:33 +0530 Subject: [PATCH 3/5] Adding JSONParserConfiguration for configuring the depth of nested maps --- src/main/java/org/json/JSONArray.java | 69 +++++++++++++++---- src/main/java/org/json/JSONObject.java | 27 ++++---- .../org/json/JSONParserConfiguration.java | 29 ++++++++ .../java/org/json/junit/JSONArrayTest.java | 16 +++-- .../java/org/json/junit/JSONObjectTest.java | 8 ++- 5 files changed, 115 insertions(+), 34 deletions(-) create mode 100644 src/main/java/org/json/JSONParserConfiguration.java diff --git a/src/main/java/org/json/JSONArray.java b/src/main/java/org/json/JSONArray.java index eec7852..6e19a54 100644 --- a/src/main/java/org/json/JSONArray.java +++ b/src/main/java/org/json/JSONArray.java @@ -149,18 +149,22 @@ public class JSONArray implements Iterable { * A Collection. */ public JSONArray(Collection collection) { - this(collection, 0); + this(collection, 0, new JSONParserConfiguration()); } - protected JSONArray(Collection collection, int recursionDepth) { - if (recursionDepth > JSONObject.RECURSION_DEPTH_LIMIT) { - throw new JSONException("JSONArray has reached recursion depth limit of " + JSONObject.RECURSION_DEPTH_LIMIT); + public JSONArray(Collection collection, JSONParserConfiguration jsonParserConfiguration) { + this(collection, 0, jsonParserConfiguration); + } + + protected JSONArray(Collection collection, int recursionDepth, JSONParserConfiguration jsonParserConfiguration) { + if (recursionDepth > jsonParserConfiguration.getMaxNestingDepth()) { + throw new JSONException("JSONArray has reached recursion depth limit of " + jsonParserConfiguration.getMaxNestingDepth()); } if (collection == null) { this.myArrayList = new ArrayList(); } else { this.myArrayList = new ArrayList(collection.size()); - this.addAll(collection, true, recursionDepth); + this.addAll(collection, true, recursionDepth, jsonParserConfiguration); } } @@ -1345,7 +1349,27 @@ public class JSONArray implements Iterable { * If a key in the map is null */ public JSONArray put(int index, Map value) throws JSONException { - this.put(index, new JSONObject(value)); + this.put(index, new JSONObject(value, new JSONParserConfiguration())); + return this; + } + + /** + * Put a value in the JSONArray, where the value will be a JSONObject that + * is produced from a Map. + * + * @param index + * The subscript + * @param value + * The Map value. + * @param jsonParserConfiguration + * Configuration for recursive depth + * @return + * @throws JSONException + * If the index is negative or if the value is an invalid + * number. + */ + public JSONArray put(int index, Map value, JSONParserConfiguration jsonParserConfiguration) throws JSONException { + this.put(index, new JSONObject(value, jsonParserConfiguration)); return this; } @@ -1790,11 +1814,11 @@ public class JSONArray implements Iterable { * variable to keep the count of how nested the object creation is happening. * */ - private void addAll(Collection collection, boolean wrap, int recursionDepth) { + private void addAll(Collection collection, boolean wrap, int recursionDepth, JSONParserConfiguration jsonParserConfiguration) { this.myArrayList.ensureCapacity(this.myArrayList.size() + collection.size()); if (wrap) { for (Object o: collection){ - this.put(JSONObject.wrap(o, recursionDepth + 1)); + this.put(JSONObject.wrap(o, recursionDepth + 1, jsonParserConfiguration)); } } else { for (Object o: collection){ @@ -1823,7 +1847,14 @@ public class JSONArray implements Iterable { } } } - + + /** + * Add an array's elements to the JSONArray. + * + * @param array + * @param wrap + * @throws JSONException + */ private void addAll(Object array, boolean wrap) throws JSONException { this.addAll(array, wrap, 0); } @@ -1836,23 +1867,37 @@ public class JSONArray implements Iterable { * JSONArray, Collection, or Iterable, an exception will be * thrown. * @param wrap + * @param recursionDepth + */ + private void addAll(Object array, boolean wrap, int recursionDepth) { + addAll(array, wrap, recursionDepth, new JSONParserConfiguration()); + } + /** + * Add an array's elements to the JSONArray. + *` + * @param array + * Array. If the parameter passed is null, or not an array, + * JSONArray, Collection, or Iterable, an exception will be + * thrown. + * @param wrap * {@code true} to call {@link JSONObject#wrap(Object)} for each item, * {@code false} to add the items directly * @param recursionDepth * Variable to keep the count of how nested the object creation is happening. - * + * @param recursionDepth + * Variable to pass parser custom configuration for json parsing. * @throws JSONException * If not an array or if an array value is non-finite number. * @throws NullPointerException * Thrown if the array parameter is null. */ - private void addAll(Object array, boolean wrap, int recursionDepth) throws JSONException { + private void addAll(Object array, boolean wrap, int recursionDepth, JSONParserConfiguration jsonParserConfiguration) throws JSONException { if (array.getClass().isArray()) { int length = Array.getLength(array); this.myArrayList.ensureCapacity(this.myArrayList.size() + length); if (wrap) { for (int i = 0; i < length; i += 1) { - this.put(JSONObject.wrap(Array.get(array, i), recursionDepth + 1)); + this.put(JSONObject.wrap(Array.get(array, i), recursionDepth + 1, jsonParserConfiguration)); } } else { for (int i = 0; i < length; i += 1) { diff --git a/src/main/java/org/json/JSONObject.java b/src/main/java/org/json/JSONObject.java index 72c0ebd..18721f7 100644 --- a/src/main/java/org/json/JSONObject.java +++ b/src/main/java/org/json/JSONObject.java @@ -147,7 +147,6 @@ public class JSONObject { * The map where the JSONObject's properties are kept. */ private final Map map; - public static final int RECURSION_DEPTH_LIMIT = 1000; public Class getMapType() { return map.getClass(); @@ -277,16 +276,20 @@ public class JSONObject { * If a key in the map is null */ public JSONObject(Map m) { - this(m, 0); + this(m, 0, new JSONParserConfiguration()); + } + + public JSONObject(Map m, JSONParserConfiguration jsonParserConfiguration) { + this(m, 0, jsonParserConfiguration); } /** * Construct a JSONObject from a map with recursion depth. * */ - protected JSONObject(Map m, int recursionDepth) { - if (recursionDepth > RECURSION_DEPTH_LIMIT) { - throw new JSONException("JSONObject has reached recursion depth limit of " + RECURSION_DEPTH_LIMIT); + protected JSONObject(Map m, int recursionDepth, JSONParserConfiguration jsonParserConfiguration) { + if (recursionDepth > jsonParserConfiguration.getMaxNestingDepth()) { + throw new JSONException("JSONObject has reached recursion depth limit of " + jsonParserConfiguration.getMaxNestingDepth()); } if (m == null) { this.map = new HashMap(); @@ -299,7 +302,7 @@ public class JSONObject { final Object value = e.getValue(); if (value != null) { testValidity(value); - this.map.put(String.valueOf(e.getKey()), wrap(value, recursionDepth + 1)); + this.map.put(String.valueOf(e.getKey()), wrap(value, recursionDepth + 1, jsonParserConfiguration)); } } } @@ -2578,15 +2581,15 @@ public class JSONObject { return wrap(object, null); } - public static Object wrap(Object object, int recursionDepth) { - return wrap(object, null, recursionDepth); + public static Object wrap(Object object, int recursionDepth, JSONParserConfiguration jsonParserConfiguration) { + return wrap(object, null, recursionDepth, jsonParserConfiguration); } private static Object wrap(Object object, Set objectsRecord) { - return wrap(object, objectsRecord, 0); + return wrap(object, objectsRecord, 0, new JSONParserConfiguration()); } - private static Object wrap(Object object, Set objectsRecord, int recursionDepth) { + private static Object wrap(Object object, Set objectsRecord, int recursionDepth, JSONParserConfiguration jsonParserConfiguration) { try { if (NULL.equals(object)) { return NULL; @@ -2604,14 +2607,14 @@ public class JSONObject { if (object instanceof Collection) { Collection coll = (Collection) object; - return new JSONArray(coll, recursionDepth); + return new JSONArray(coll, recursionDepth, jsonParserConfiguration); } if (object.getClass().isArray()) { return new JSONArray(object); } if (object instanceof Map) { Map map = (Map) object; - return new JSONObject(map, recursionDepth); + return new JSONObject(map, recursionDepth, jsonParserConfiguration); } Package objectPackage = object.getClass().getPackage(); String objectPackageName = objectPackage != null ? objectPackage diff --git a/src/main/java/org/json/JSONParserConfiguration.java b/src/main/java/org/json/JSONParserConfiguration.java new file mode 100644 index 0000000..910d1cf --- /dev/null +++ b/src/main/java/org/json/JSONParserConfiguration.java @@ -0,0 +1,29 @@ +package org.json; + +/** + * Configuration object for the JSON parser. The configuration is immutable. + */ +public class JSONParserConfiguration extends ParserConfiguration { + + /** + * We can override the default maximum nesting depth if needed. + */ + public static final int DEFAULT_MAXIMUM_NESTING_DEPTH = ParserConfiguration.DEFAULT_MAXIMUM_NESTING_DEPTH; + + /** + * Configuration with the default values. + */ + public JSONParserConfiguration() { + this.maxNestingDepth = DEFAULT_MAXIMUM_NESTING_DEPTH; + } + + public JSONParserConfiguration(int maxNestingDepth) { + this.maxNestingDepth = maxNestingDepth; + } + + @Override + protected JSONParserConfiguration clone() { + return new JSONParserConfiguration(DEFAULT_MAXIMUM_NESTING_DEPTH); + } + +} diff --git a/src/test/java/org/json/junit/JSONArrayTest.java b/src/test/java/org/json/junit/JSONArrayTest.java index 5f50fc7..349422d 100644 --- a/src/test/java/org/json/junit/JSONArrayTest.java +++ b/src/test/java/org/json/junit/JSONArrayTest.java @@ -28,6 +28,7 @@ import java.util.Map; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; +import org.json.JSONParserConfiguration; import org.json.JSONPointerException; import org.json.JSONString; import org.json.JSONTokener; @@ -1440,15 +1441,15 @@ public class JSONArrayTest { } @Test - public void testRecursiveDepthAtPosition999Object() { - HashMap map = JSONObjectTest.buildNestedMap(999); + public void testRecursiveDepthAtPositionDefaultObject() { + HashMap map = JSONObjectTest.buildNestedMap(JSONParserConfiguration.DEFAULT_MAXIMUM_NESTING_DEPTH); new JSONArray().put(0, map); } @Test public void testRecursiveDepthAtPosition1000Object() { HashMap map = JSONObjectTest.buildNestedMap(1000); - new JSONArray().put(0, map); + new JSONArray().put(0, map, new JSONParserConfiguration(1000)); } @Test(expected = JSONException.class) @@ -1465,15 +1466,16 @@ public class JSONArrayTest { } @Test - public void testRecursiveDepthArrayFor999Levels() { - ArrayList array = buildNestedArray(999); - new JSONArray(array); + public void testRecursiveDepthArrayForDefaultLevels() { + ArrayList array = buildNestedArray(JSONParserConfiguration.DEFAULT_MAXIMUM_NESTING_DEPTH); + new JSONArray(array, new JSONParserConfiguration()); } @Test public void testRecursiveDepthArrayFor1000Levels() { ArrayList array = buildNestedArray(1000); - new JSONArray(array); + JSONParserConfiguration parserConfiguration = new JSONParserConfiguration(1000); + new JSONArray(array, parserConfiguration); } @Test(expected = JSONException.class) diff --git a/src/test/java/org/json/junit/JSONObjectTest.java b/src/test/java/org/json/junit/JSONObjectTest.java index e157fd5..1a911d8 100644 --- a/src/test/java/org/json/junit/JSONObjectTest.java +++ b/src/test/java/org/json/junit/JSONObjectTest.java @@ -32,6 +32,7 @@ import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import org.json.JSONPointerException; +import org.json.JSONParserConfiguration; import org.json.JSONString; import org.json.JSONTokener; import org.json.XML; @@ -3737,8 +3738,8 @@ public class JSONObjectTest { } @Test - public void issue743SerializationMapWith999Objects() { - HashMap map = buildNestedMap(999); + public void issue743SerializationMapWith512Objects() { + HashMap map = buildNestedMap(JSONParserConfiguration.DEFAULT_MAXIMUM_NESTING_DEPTH); JSONObject object = new JSONObject(map); String jsonString = object.toString(); } @@ -3746,7 +3747,8 @@ public class JSONObjectTest { @Test public void issue743SerializationMapWith1000Objects() { HashMap map = buildNestedMap(1000); - JSONObject object = new JSONObject(map); + JSONParserConfiguration parserConfiguration = new JSONParserConfiguration(1000); + JSONObject object = new JSONObject(map, parserConfiguration); String jsonString = object.toString(); } From ffd48afa42f014dfbd48f86c3cef96ccc4e6c7df Mon Sep 17 00:00:00 2001 From: sk02241994 Date: Sat, 23 Dec 2023 10:53:54 +0530 Subject: [PATCH 4/5] Review comments --- .../java/org/json/JSONParserConfiguration.java | 18 +++++++----------- .../java/org/json/junit/JSONArrayTest.java | 9 +++++---- .../java/org/json/junit/JSONObjectTest.java | 5 +++-- 3 files changed, 15 insertions(+), 17 deletions(-) diff --git a/src/main/java/org/json/JSONParserConfiguration.java b/src/main/java/org/json/JSONParserConfiguration.java index 910d1cf..1ec1710 100644 --- a/src/main/java/org/json/JSONParserConfiguration.java +++ b/src/main/java/org/json/JSONParserConfiguration.java @@ -5,25 +5,21 @@ package org.json; */ public class JSONParserConfiguration extends ParserConfiguration { - /** - * We can override the default maximum nesting depth if needed. - */ - public static final int DEFAULT_MAXIMUM_NESTING_DEPTH = ParserConfiguration.DEFAULT_MAXIMUM_NESTING_DEPTH; - /** * Configuration with the default values. */ public JSONParserConfiguration() { - this.maxNestingDepth = DEFAULT_MAXIMUM_NESTING_DEPTH; - } - - public JSONParserConfiguration(int maxNestingDepth) { - this.maxNestingDepth = maxNestingDepth; + super(); } @Override protected JSONParserConfiguration clone() { - return new JSONParserConfiguration(DEFAULT_MAXIMUM_NESTING_DEPTH); + return new JSONParserConfiguration(); + } + + @Override + public JSONParserConfiguration withMaxNestingDepth(final int maxNestingDepth) { + return super.withMaxNestingDepth(maxNestingDepth); } } diff --git a/src/test/java/org/json/junit/JSONArrayTest.java b/src/test/java/org/json/junit/JSONArrayTest.java index 349422d..fd01379 100644 --- a/src/test/java/org/json/junit/JSONArrayTest.java +++ b/src/test/java/org/json/junit/JSONArrayTest.java @@ -32,6 +32,7 @@ import org.json.JSONParserConfiguration; import org.json.JSONPointerException; import org.json.JSONString; import org.json.JSONTokener; +import org.json.ParserConfiguration; import org.json.junit.data.MyJsonString; import org.junit.Ignore; import org.junit.Test; @@ -1442,14 +1443,14 @@ public class JSONArrayTest { @Test public void testRecursiveDepthAtPositionDefaultObject() { - HashMap map = JSONObjectTest.buildNestedMap(JSONParserConfiguration.DEFAULT_MAXIMUM_NESTING_DEPTH); + HashMap map = JSONObjectTest.buildNestedMap(ParserConfiguration.DEFAULT_MAXIMUM_NESTING_DEPTH); new JSONArray().put(0, map); } @Test public void testRecursiveDepthAtPosition1000Object() { HashMap map = JSONObjectTest.buildNestedMap(1000); - new JSONArray().put(0, map, new JSONParserConfiguration(1000)); + new JSONArray().put(0, map, new JSONParserConfiguration().withMaxNestingDepth(1000)); } @Test(expected = JSONException.class) @@ -1467,14 +1468,14 @@ public class JSONArrayTest { @Test public void testRecursiveDepthArrayForDefaultLevels() { - ArrayList array = buildNestedArray(JSONParserConfiguration.DEFAULT_MAXIMUM_NESTING_DEPTH); + ArrayList array = buildNestedArray(ParserConfiguration.DEFAULT_MAXIMUM_NESTING_DEPTH); new JSONArray(array, new JSONParserConfiguration()); } @Test public void testRecursiveDepthArrayFor1000Levels() { ArrayList array = buildNestedArray(1000); - JSONParserConfiguration parserConfiguration = new JSONParserConfiguration(1000); + JSONParserConfiguration parserConfiguration = new JSONParserConfiguration().withMaxNestingDepth(1000); new JSONArray(array, parserConfiguration); } diff --git a/src/test/java/org/json/junit/JSONObjectTest.java b/src/test/java/org/json/junit/JSONObjectTest.java index 1a911d8..96f3673 100644 --- a/src/test/java/org/json/junit/JSONObjectTest.java +++ b/src/test/java/org/json/junit/JSONObjectTest.java @@ -35,6 +35,7 @@ import org.json.JSONPointerException; import org.json.JSONParserConfiguration; import org.json.JSONString; import org.json.JSONTokener; +import org.json.ParserConfiguration; import org.json.XML; import org.json.junit.data.BrokenToString; import org.json.junit.data.ExceptionalBean; @@ -3739,7 +3740,7 @@ public class JSONObjectTest { @Test public void issue743SerializationMapWith512Objects() { - HashMap map = buildNestedMap(JSONParserConfiguration.DEFAULT_MAXIMUM_NESTING_DEPTH); + HashMap map = buildNestedMap(ParserConfiguration.DEFAULT_MAXIMUM_NESTING_DEPTH); JSONObject object = new JSONObject(map); String jsonString = object.toString(); } @@ -3747,7 +3748,7 @@ public class JSONObjectTest { @Test public void issue743SerializationMapWith1000Objects() { HashMap map = buildNestedMap(1000); - JSONParserConfiguration parserConfiguration = new JSONParserConfiguration(1000); + JSONParserConfiguration parserConfiguration = new JSONParserConfiguration().withMaxNestingDepth(1000); JSONObject object = new JSONObject(map, parserConfiguration); String jsonString = object.toString(); } From 7701f2183966dd4f1efad1b762b47a89009e60ad Mon Sep 17 00:00:00 2001 From: sk02241994 Date: Sun, 24 Dec 2023 11:02:47 +0530 Subject: [PATCH 5/5] Adding comments --- src/main/java/org/json/JSONArray.java | 38 ++++++++++++++++++++++---- src/main/java/org/json/JSONObject.java | 29 ++++++++++++++++++-- 2 files changed, 59 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/json/JSONArray.java b/src/main/java/org/json/JSONArray.java index 6e19a54..50146a8 100644 --- a/src/main/java/org/json/JSONArray.java +++ b/src/main/java/org/json/JSONArray.java @@ -152,11 +152,29 @@ public class JSONArray implements Iterable { this(collection, 0, new JSONParserConfiguration()); } + /** + * Construct a JSONArray from a Collection. + * + * @param collection + * A Collection. + * @param jsonParserConfiguration + * Configuration object for the JSON parser + */ public JSONArray(Collection collection, JSONParserConfiguration jsonParserConfiguration) { this(collection, 0, jsonParserConfiguration); } - protected JSONArray(Collection collection, int recursionDepth, JSONParserConfiguration jsonParserConfiguration) { + /** + * Construct a JSONArray from a collection with recursion depth. + * + * @param collection + * A Collection. + * @param recursionDepth + * Variable for tracking the count of nested object creations. + * @param jsonParserConfiguration + * Configuration object for the JSON parser + */ + JSONArray(Collection collection, int recursionDepth, JSONParserConfiguration jsonParserConfiguration) { if (recursionDepth > jsonParserConfiguration.getMaxNestingDepth()) { throw new JSONException("JSONArray has reached recursion depth limit of " + jsonParserConfiguration.getMaxNestingDepth()); } @@ -1362,7 +1380,7 @@ public class JSONArray implements Iterable { * @param value * The Map value. * @param jsonParserConfiguration - * Configuration for recursive depth + * Configuration object for the JSON parser * @return * @throws JSONException * If the index is negative or if the value is an invalid @@ -1811,8 +1829,7 @@ public class JSONArray implements Iterable { * {@code true} to call {@link JSONObject#wrap(Object)} for each item, * {@code false} to add the items directly * @param recursionDepth - * variable to keep the count of how nested the object creation is happening. - * + * Variable for tracking the count of nested object creations. */ private void addAll(Collection collection, boolean wrap, int recursionDepth, JSONParserConfiguration jsonParserConfiguration) { this.myArrayList.ensureCapacity(this.myArrayList.size() + collection.size()); @@ -1852,8 +1869,14 @@ public class JSONArray implements Iterable { * Add an array's elements to the JSONArray. * * @param array + * Array. If the parameter passed is null, or not an array, + * JSONArray, Collection, or Iterable, an exception will be + * thrown. * @param wrap + * {@code true} to call {@link JSONObject#wrap(Object)} for each item, + * {@code false} to add the items directly * @throws JSONException + * If not an array or if an array value is non-finite number. */ private void addAll(Object array, boolean wrap) throws JSONException { this.addAll(array, wrap, 0); @@ -1867,7 +1890,10 @@ public class JSONArray implements Iterable { * JSONArray, Collection, or Iterable, an exception will be * thrown. * @param wrap + * {@code true} to call {@link JSONObject#wrap(Object)} for each item, + * {@code false} to add the items directly * @param recursionDepth + * Variable for tracking the count of nested object creations. */ private void addAll(Object array, boolean wrap, int recursionDepth) { addAll(array, wrap, recursionDepth, new JSONParserConfiguration()); @@ -1883,8 +1909,8 @@ public class JSONArray implements Iterable { * {@code true} to call {@link JSONObject#wrap(Object)} for each item, * {@code false} to add the items directly * @param recursionDepth - * Variable to keep the count of how nested the object creation is happening. - * @param recursionDepth + * Variable for tracking the count of nested object creations. + * @param jsonParserConfiguration * Variable to pass parser custom configuration for json parsing. * @throws JSONException * If not an array or if an array value is non-finite number. diff --git a/src/main/java/org/json/JSONObject.java b/src/main/java/org/json/JSONObject.java index 18721f7..4bd032b 100644 --- a/src/main/java/org/json/JSONObject.java +++ b/src/main/java/org/json/JSONObject.java @@ -279,6 +279,15 @@ public class JSONObject { this(m, 0, new JSONParserConfiguration()); } + /** + * Construct a JSONObject from a Map with custom json parse configurations. + * + * @param m + * A map object that can be used to initialize the contents of + * the JSONObject. + * @param jsonParserConfiguration + * Variable to pass parser custom configuration for json parsing. + */ public JSONObject(Map m, JSONParserConfiguration jsonParserConfiguration) { this(m, 0, jsonParserConfiguration); } @@ -287,7 +296,7 @@ public class JSONObject { * Construct a JSONObject from a map with recursion depth. * */ - protected JSONObject(Map m, int recursionDepth, JSONParserConfiguration jsonParserConfiguration) { + private JSONObject(Map m, int recursionDepth, JSONParserConfiguration jsonParserConfiguration) { if (recursionDepth > jsonParserConfiguration.getMaxNestingDepth()) { throw new JSONException("JSONObject has reached recursion depth limit of " + jsonParserConfiguration.getMaxNestingDepth()); } @@ -2581,7 +2590,23 @@ public class JSONObject { return wrap(object, null); } - public static Object wrap(Object object, int recursionDepth, JSONParserConfiguration jsonParserConfiguration) { + /** + * Wrap an object, if necessary. If the object is null, return the NULL + * object. If it is an array or collection, wrap it in a JSONArray. If it is + * a map, wrap it in a JSONObject. If it is a standard property (Double, + * String, et al) then it is already wrapped. Otherwise, if it comes from + * one of the java packages, turn it into a string. And if it doesn't, try + * to wrap it in a JSONObject. If the wrapping fails, then null is returned. + * + * @param object + * The object to wrap + * @param recursionDepth + * Variable for tracking the count of nested object creations. + * @param jsonParserConfiguration + * Variable to pass parser custom configuration for json parsing. + * @return The wrapped value + */ + static Object wrap(Object object, int recursionDepth, JSONParserConfiguration jsonParserConfiguration) { return wrap(object, null, recursionDepth, jsonParserConfiguration); }