mirror of
https://github.com/stleary/JSON-java.git
synced 2025-08-03 03:15:32 -04:00
Adding JSONParserConfiguration for configuring the depth of nested maps
This commit is contained in:
parent
dcac3bc18e
commit
abea194120
@ -149,18 +149,22 @@ public class JSONArray implements Iterable<Object> {
|
|||||||
* A Collection.
|
* A Collection.
|
||||||
*/
|
*/
|
||||||
public JSONArray(Collection<?> collection) {
|
public JSONArray(Collection<?> collection) {
|
||||||
this(collection, 0);
|
this(collection, 0, new JSONParserConfiguration());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected JSONArray(Collection<?> collection, int recursionDepth) {
|
public JSONArray(Collection<?> collection, JSONParserConfiguration jsonParserConfiguration) {
|
||||||
if (recursionDepth > JSONObject.RECURSION_DEPTH_LIMIT) {
|
this(collection, 0, jsonParserConfiguration);
|
||||||
throw new JSONException("JSONArray has reached recursion depth limit of " + JSONObject.RECURSION_DEPTH_LIMIT);
|
}
|
||||||
|
|
||||||
|
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) {
|
if (collection == null) {
|
||||||
this.myArrayList = new ArrayList<Object>();
|
this.myArrayList = new ArrayList<Object>();
|
||||||
} else {
|
} else {
|
||||||
this.myArrayList = new ArrayList<Object>(collection.size());
|
this.myArrayList = new ArrayList<Object>(collection.size());
|
||||||
this.addAll(collection, true, recursionDepth);
|
this.addAll(collection, true, recursionDepth, jsonParserConfiguration);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1345,7 +1349,27 @@ public class JSONArray implements Iterable<Object> {
|
|||||||
* If a key in the map is <code>null</code>
|
* If a key in the map is <code>null</code>
|
||||||
*/
|
*/
|
||||||
public JSONArray put(int index, Map<?, ?> value) throws JSONException {
|
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;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1790,11 +1814,11 @@ public class JSONArray implements Iterable<Object> {
|
|||||||
* variable to keep the count of how nested the object creation is happening.
|
* 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());
|
this.myArrayList.ensureCapacity(this.myArrayList.size() + collection.size());
|
||||||
if (wrap) {
|
if (wrap) {
|
||||||
for (Object o: collection){
|
for (Object o: collection){
|
||||||
this.put(JSONObject.wrap(o, recursionDepth + 1));
|
this.put(JSONObject.wrap(o, recursionDepth + 1, jsonParserConfiguration));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (Object o: collection){
|
for (Object o: collection){
|
||||||
@ -1823,7 +1847,14 @@ public class JSONArray implements Iterable<Object> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add an array's elements to the JSONArray.
|
||||||
|
*
|
||||||
|
* @param array
|
||||||
|
* @param wrap
|
||||||
|
* @throws JSONException
|
||||||
|
*/
|
||||||
private void addAll(Object array, boolean wrap) throws JSONException {
|
private void addAll(Object array, boolean wrap) throws JSONException {
|
||||||
this.addAll(array, wrap, 0);
|
this.addAll(array, wrap, 0);
|
||||||
}
|
}
|
||||||
@ -1836,23 +1867,37 @@ public class JSONArray implements Iterable<Object> {
|
|||||||
* JSONArray, Collection, or Iterable, an exception will be
|
* JSONArray, Collection, or Iterable, an exception will be
|
||||||
* thrown.
|
* thrown.
|
||||||
* @param wrap
|
* @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 true} to call {@link JSONObject#wrap(Object)} for each item,
|
||||||
* {@code false} to add the items directly
|
* {@code false} to add the items directly
|
||||||
* @param recursionDepth
|
* @param recursionDepth
|
||||||
* Variable to keep the count of how nested the object creation is happening.
|
* 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
|
* @throws JSONException
|
||||||
* If not an array or if an array value is non-finite number.
|
* If not an array or if an array value is non-finite number.
|
||||||
* @throws NullPointerException
|
* @throws NullPointerException
|
||||||
* Thrown if the array parameter is null.
|
* 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()) {
|
if (array.getClass().isArray()) {
|
||||||
int length = Array.getLength(array);
|
int length = Array.getLength(array);
|
||||||
this.myArrayList.ensureCapacity(this.myArrayList.size() + length);
|
this.myArrayList.ensureCapacity(this.myArrayList.size() + length);
|
||||||
if (wrap) {
|
if (wrap) {
|
||||||
for (int i = 0; i < length; i += 1) {
|
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 {
|
} else {
|
||||||
for (int i = 0; i < length; i += 1) {
|
for (int i = 0; i < length; i += 1) {
|
||||||
|
@ -147,7 +147,6 @@ public class JSONObject {
|
|||||||
* The map where the JSONObject's properties are kept.
|
* The map where the JSONObject's properties are kept.
|
||||||
*/
|
*/
|
||||||
private final Map<String, Object> map;
|
private final Map<String, Object> map;
|
||||||
public static final int RECURSION_DEPTH_LIMIT = 1000;
|
|
||||||
|
|
||||||
public Class<? extends Map> getMapType() {
|
public Class<? extends Map> getMapType() {
|
||||||
return map.getClass();
|
return map.getClass();
|
||||||
@ -277,16 +276,20 @@ public class JSONObject {
|
|||||||
* If a key in the map is <code>null</code>
|
* If a key in the map is <code>null</code>
|
||||||
*/
|
*/
|
||||||
public JSONObject(Map<?, ?> m) {
|
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.
|
* Construct a JSONObject from a map with recursion depth.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
protected JSONObject(Map<?, ?> m, int recursionDepth) {
|
protected JSONObject(Map<?, ?> m, int recursionDepth, JSONParserConfiguration jsonParserConfiguration) {
|
||||||
if (recursionDepth > RECURSION_DEPTH_LIMIT) {
|
if (recursionDepth > jsonParserConfiguration.getMaxNestingDepth()) {
|
||||||
throw new JSONException("JSONObject has reached recursion depth limit of " + RECURSION_DEPTH_LIMIT);
|
throw new JSONException("JSONObject has reached recursion depth limit of " + jsonParserConfiguration.getMaxNestingDepth());
|
||||||
}
|
}
|
||||||
if (m == null) {
|
if (m == null) {
|
||||||
this.map = new HashMap<String, Object>();
|
this.map = new HashMap<String, Object>();
|
||||||
@ -299,7 +302,7 @@ public class JSONObject {
|
|||||||
final Object value = e.getValue();
|
final Object value = e.getValue();
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
testValidity(value);
|
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);
|
return wrap(object, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object wrap(Object object, int recursionDepth) {
|
public static Object wrap(Object object, int recursionDepth, JSONParserConfiguration jsonParserConfiguration) {
|
||||||
return wrap(object, null, recursionDepth);
|
return wrap(object, null, recursionDepth, jsonParserConfiguration);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Object wrap(Object object, Set<Object> objectsRecord) {
|
private static Object wrap(Object object, Set<Object> objectsRecord) {
|
||||||
return wrap(object, objectsRecord, 0);
|
return wrap(object, objectsRecord, 0, new JSONParserConfiguration());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Object wrap(Object object, Set<Object> objectsRecord, int recursionDepth) {
|
private static Object wrap(Object object, Set<Object> objectsRecord, int recursionDepth, JSONParserConfiguration jsonParserConfiguration) {
|
||||||
try {
|
try {
|
||||||
if (NULL.equals(object)) {
|
if (NULL.equals(object)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -2604,14 +2607,14 @@ public class JSONObject {
|
|||||||
|
|
||||||
if (object instanceof Collection) {
|
if (object instanceof Collection) {
|
||||||
Collection<?> coll = (Collection<?>) object;
|
Collection<?> coll = (Collection<?>) object;
|
||||||
return new JSONArray(coll, recursionDepth);
|
return new JSONArray(coll, recursionDepth, jsonParserConfiguration);
|
||||||
}
|
}
|
||||||
if (object.getClass().isArray()) {
|
if (object.getClass().isArray()) {
|
||||||
return new JSONArray(object);
|
return new JSONArray(object);
|
||||||
}
|
}
|
||||||
if (object instanceof Map) {
|
if (object instanceof Map) {
|
||||||
Map<?, ?> map = (Map<?, ?>) object;
|
Map<?, ?> map = (Map<?, ?>) object;
|
||||||
return new JSONObject(map, recursionDepth);
|
return new JSONObject(map, recursionDepth, jsonParserConfiguration);
|
||||||
}
|
}
|
||||||
Package objectPackage = object.getClass().getPackage();
|
Package objectPackage = object.getClass().getPackage();
|
||||||
String objectPackageName = objectPackage != null ? objectPackage
|
String objectPackageName = objectPackage != null ? objectPackage
|
||||||
|
29
src/main/java/org/json/JSONParserConfiguration.java
Normal file
29
src/main/java/org/json/JSONParserConfiguration.java
Normal file
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -28,6 +28,7 @@ import java.util.Map;
|
|||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
import org.json.JSONParserConfiguration;
|
||||||
import org.json.JSONPointerException;
|
import org.json.JSONPointerException;
|
||||||
import org.json.JSONString;
|
import org.json.JSONString;
|
||||||
import org.json.JSONTokener;
|
import org.json.JSONTokener;
|
||||||
@ -1440,15 +1441,15 @@ public class JSONArrayTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRecursiveDepthAtPosition999Object() {
|
public void testRecursiveDepthAtPositionDefaultObject() {
|
||||||
HashMap<String, Object> map = JSONObjectTest.buildNestedMap(999);
|
HashMap<String, Object> map = JSONObjectTest.buildNestedMap(JSONParserConfiguration.DEFAULT_MAXIMUM_NESTING_DEPTH);
|
||||||
new JSONArray().put(0, map);
|
new JSONArray().put(0, map);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRecursiveDepthAtPosition1000Object() {
|
public void testRecursiveDepthAtPosition1000Object() {
|
||||||
HashMap<String, Object> map = JSONObjectTest.buildNestedMap(1000);
|
HashMap<String, Object> map = JSONObjectTest.buildNestedMap(1000);
|
||||||
new JSONArray().put(0, map);
|
new JSONArray().put(0, map, new JSONParserConfiguration(1000));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = JSONException.class)
|
@Test(expected = JSONException.class)
|
||||||
@ -1465,15 +1466,16 @@ public class JSONArrayTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRecursiveDepthArrayFor999Levels() {
|
public void testRecursiveDepthArrayForDefaultLevels() {
|
||||||
ArrayList<Object> array = buildNestedArray(999);
|
ArrayList<Object> array = buildNestedArray(JSONParserConfiguration.DEFAULT_MAXIMUM_NESTING_DEPTH);
|
||||||
new JSONArray(array);
|
new JSONArray(array, new JSONParserConfiguration());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRecursiveDepthArrayFor1000Levels() {
|
public void testRecursiveDepthArrayFor1000Levels() {
|
||||||
ArrayList<Object> array = buildNestedArray(1000);
|
ArrayList<Object> array = buildNestedArray(1000);
|
||||||
new JSONArray(array);
|
JSONParserConfiguration parserConfiguration = new JSONParserConfiguration(1000);
|
||||||
|
new JSONArray(array, parserConfiguration);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = JSONException.class)
|
@Test(expected = JSONException.class)
|
||||||
|
@ -32,6 +32,7 @@ import org.json.JSONArray;
|
|||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
import org.json.JSONPointerException;
|
import org.json.JSONPointerException;
|
||||||
|
import org.json.JSONParserConfiguration;
|
||||||
import org.json.JSONString;
|
import org.json.JSONString;
|
||||||
import org.json.JSONTokener;
|
import org.json.JSONTokener;
|
||||||
import org.json.XML;
|
import org.json.XML;
|
||||||
@ -3737,8 +3738,8 @@ public class JSONObjectTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void issue743SerializationMapWith999Objects() {
|
public void issue743SerializationMapWith512Objects() {
|
||||||
HashMap<String, Object> map = buildNestedMap(999);
|
HashMap<String, Object> map = buildNestedMap(JSONParserConfiguration.DEFAULT_MAXIMUM_NESTING_DEPTH);
|
||||||
JSONObject object = new JSONObject(map);
|
JSONObject object = new JSONObject(map);
|
||||||
String jsonString = object.toString();
|
String jsonString = object.toString();
|
||||||
}
|
}
|
||||||
@ -3746,7 +3747,8 @@ public class JSONObjectTest {
|
|||||||
@Test
|
@Test
|
||||||
public void issue743SerializationMapWith1000Objects() {
|
public void issue743SerializationMapWith1000Objects() {
|
||||||
HashMap<String, Object> map = buildNestedMap(1000);
|
HashMap<String, Object> map = buildNestedMap(1000);
|
||||||
JSONObject object = new JSONObject(map);
|
JSONParserConfiguration parserConfiguration = new JSONParserConfiguration(1000);
|
||||||
|
JSONObject object = new JSONObject(map, parserConfiguration);
|
||||||
String jsonString = object.toString();
|
String jsonString = object.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user