Merge branch 'stleary:master' into feature-disable-whitespace-trim

This commit is contained in:
Keaton
2024-01-18 09:17:26 +02:00
committed by GitHub
15 changed files with 393 additions and 30 deletions

View File

@@ -46,19 +46,19 @@ public class CookieList {
* @throws JSONException if a called function fails
*/
public static String toString(JSONObject jo) throws JSONException {
boolean b = false;
boolean isEndOfPair = false;
final StringBuilder sb = new StringBuilder();
// Don't use the new entrySet API to maintain Android support
for (final String key : jo.keySet()) {
final Object value = jo.opt(key);
if (!JSONObject.NULL.equals(value)) {
if (b) {
if (isEndOfPair) {
sb.append(';');
}
sb.append(Cookie.escape(key));
sb.append("=");
sb.append(Cookie.escape(value.toString()));
b = true;
isEndOfPair = true;
}
}
return sb.toString();

View File

@@ -149,11 +149,40 @@ public class JSONArray implements Iterable<Object> {
* A Collection.
*/
public JSONArray(Collection<?> collection) {
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);
}
/**
* 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());
}
if (collection == null) {
this.myArrayList = new ArrayList<Object>();
} else {
this.myArrayList = new ArrayList<Object>(collection.size());
this.addAll(collection, true);
this.addAll(collection, true, recursionDepth, jsonParserConfiguration);
}
}
@@ -205,7 +234,7 @@ public class JSONArray implements Iterable<Object> {
throw new JSONException(
"JSONArray initial value should be a string or collection or array.");
}
this.addAll(array, true);
this.addAll(array, true, 0);
}
/**
@@ -1330,7 +1359,8 @@ public class JSONArray implements Iterable<Object> {
* The subscript.
* @param value
* The Map value.
* @return this.
* @return
* reference to self
* @throws JSONException
* If the index is negative or if the value is an invalid
* number.
@@ -1338,7 +1368,27 @@ public class JSONArray implements Iterable<Object> {
* If a key in the map is <code>null</code>
*/
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 object for the JSON parser
* @return reference to self
* @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;
}
@@ -1779,13 +1829,14 @@ public class JSONArray implements Iterable<Object> {
* @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(Collection<?> collection, boolean wrap) {
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));
this.put(JSONObject.wrap(o, recursionDepth + 1, jsonParserConfiguration));
}
} else {
for (Object o: collection){
@@ -1814,7 +1865,24 @@ public class JSONArray implements Iterable<Object> {
}
}
}
/**
* 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);
}
/**
* Add an array's elements to the JSONArray.
*
@@ -1823,21 +1891,40 @@ public class JSONArray implements Iterable<Object> {
* 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());
}
/**
* 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 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.
* @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, 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)));
this.put(JSONObject.wrap(Array.get(array, i), recursionDepth + 1, jsonParserConfiguration));
}
} else {
for (int i = 0; i < length; i += 1) {
@@ -1850,7 +1937,7 @@ public class JSONArray implements Iterable<Object> {
// 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 {

View File

@@ -55,11 +55,13 @@ public class JSONMLParserConfiguration extends ParserConfiguration {
);
}
@SuppressWarnings("unchecked")
@Override
public JSONMLParserConfiguration withKeepStrings(final boolean newVal) {
return super.withKeepStrings(newVal);
}
@SuppressWarnings("unchecked")
@Override
public JSONMLParserConfiguration withMaxNestingDepth(int maxNestingDepth) {
return super.withMaxNestingDepth(maxNestingDepth);

View File

@@ -276,6 +276,30 @@ public class JSONObject {
* If a key in the map is <code>null</code>
*/
public JSONObject(Map<?, ?> m) {
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);
}
/**
* Construct a JSONObject from a map with recursion depth.
*
*/
private 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<String, Object>();
} else {
@@ -287,7 +311,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, jsonParserConfiguration));
}
}
}
@@ -1841,6 +1865,10 @@ public class JSONObject {
}
}
//If the superclass is Object, no annotations will be found any more
if (c.getSuperclass().equals(Object.class))
return null;
try {
return getAnnotation(
c.getSuperclass().getMethod(m.getName(), m.getParameterTypes()),
@@ -1895,6 +1923,10 @@ public class JSONObject {
}
}
//If the superclass is Object, no annotations will be found any more
if (c.getSuperclass().equals(Object.class))
return -1;
try {
int d = getAnnotationDepth(
c.getSuperclass().getMethod(m.getName(), m.getParameterTypes()),
@@ -2566,7 +2598,31 @@ public class JSONObject {
return wrap(object, null);
}
/**
* Wrap an object, if necessary. If the object is <code>null</code>, 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);
}
private static Object wrap(Object object, Set<Object> objectsRecord) {
return wrap(object, objectsRecord, 0, new JSONParserConfiguration());
}
private static Object wrap(Object object, Set<Object> objectsRecord, int recursionDepth, JSONParserConfiguration jsonParserConfiguration) {
try {
if (NULL.equals(object)) {
return NULL;
@@ -2584,14 +2640,14 @@ public class JSONObject {
if (object instanceof Collection) {
Collection<?> coll = (Collection<?>) object;
return new JSONArray(coll);
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);
return new JSONObject(map, recursionDepth, jsonParserConfiguration);
}
Package objectPackage = object.getClass().getPackage();
String objectPackageName = objectPackage != null ? objectPackage

View File

@@ -0,0 +1,26 @@
package org.json;
/**
* Configuration object for the JSON parser. The configuration is immutable.
*/
public class JSONParserConfiguration extends ParserConfiguration {
/**
* Configuration with the default values.
*/
public JSONParserConfiguration() {
super();
}
@Override
protected JSONParserConfiguration clone() {
return new JSONParserConfiguration();
}
@SuppressWarnings("unchecked")
@Override
public JSONParserConfiguration withMaxNestingDepth(final int maxNestingDepth) {
return super.withMaxNestingDepth(maxNestingDepth);
}
}

View File

@@ -24,7 +24,7 @@ class NumberConversionUtil {
val = "-0."+val.substring(2);
}
char initial = val.charAt(0);
if ((initial >= '0' && initial <= '9') || initial == '-' ) {
if ( isNumericChar(initial) || initial == '-' ) {
// decimal representation
if (isDecimalNotation(val)) {
// Use a BigDecimal all the time so we keep the original
@@ -53,13 +53,13 @@ class NumberConversionUtil {
initial = val.charAt(0);
if(initial == '0' && val.length() > 1) {
char at1 = val.charAt(1);
if(at1 >= '0' && at1 <= '9') {
if(isNumericChar(at1)) {
throw new NumberFormatException("val ["+input+"] is not a valid number.");
}
} else if (initial == '-' && val.length() > 2) {
char at1 = val.charAt(1);
char at2 = val.charAt(2);
if(at1 == '0' && at2 >= '0' && at2 <= '9') {
if(at1 == '0' && isNumericChar(at2)) {
throw new NumberFormatException("val ["+input+"] is not a valid number.");
}
}
@@ -83,6 +83,16 @@ class NumberConversionUtil {
throw new NumberFormatException("val ["+input+"] is not a valid number.");
}
/**
* Checks if the character is a numeric digit ('0' to '9').
*
* @param c The character to be checked.
* @return true if the character is a numeric digit, false otherwise.
*/
private static boolean isNumericChar(char c) {
return (c <= '9' && c >= '0');
}
/**
* Checks if the value could be considered a number in decimal number system.
* @param value

View File

@@ -75,6 +75,7 @@ public class ParserConfiguration {
*
* @return The existing configuration will not be modified. A new configuration is returned.
*/
@SuppressWarnings("unchecked")
public <T extends ParserConfiguration> T withKeepStrings(final boolean newVal) {
T newConfig = (T)this.clone();
newConfig.keepStrings = newVal;
@@ -101,6 +102,7 @@ public class ParserConfiguration {
*
* @return The existing configuration will not be modified. A new configuration is returned.
*/
@SuppressWarnings("unchecked")
public <T extends ParserConfiguration> T withMaxNestingDepth(int maxNestingDepth) {
T newConfig = (T)this.clone();

View File

@@ -892,14 +892,14 @@ public class XML {
string = (object == null) ? "null" : escape(object.toString());
String indentationSuffix = (indentFactor > 0) ? "\n" : "";
if(tagName == null){
return indent(indent) + "\"" + string + "\"" + ((indentFactor > 0) ? "\n" : "");
return indent(indent) + "\"" + string + "\"" + indentationSuffix;
} else if(string.length() == 0){
return indent(indent) + "<" + tagName + "/>" + ((indentFactor > 0) ? "\n" : "");
return indent(indent) + "<" + tagName + "/>" + indentationSuffix;
} else {
return indent(indent) + "<" + tagName
+ ">" + string + "</" + tagName + ">" + ((indentFactor > 0) ? "\n" : "");
+ ">" + string + "</" + tagName + ">" + indentationSuffix;
}
}

View File

@@ -204,6 +204,7 @@ public class XMLParserConfiguration extends ParserConfiguration {
*
* @return The existing configuration will not be modified. A new configuration is returned.
*/
@SuppressWarnings("unchecked")
@Override
public XMLParserConfiguration withKeepStrings(final boolean newVal) {
return super.withKeepStrings(newVal);
@@ -321,6 +322,7 @@ public class XMLParserConfiguration extends ParserConfiguration {
* @param maxNestingDepth the maximum nesting depth allowed to the XML parser
* @return The existing configuration will not be modified. A new configuration is returned.
*/
@SuppressWarnings("unchecked")
@Override
public XMLParserConfiguration withMaxNestingDepth(int maxNestingDepth) {
return super.withMaxNestingDepth(maxNestingDepth);
@@ -328,7 +330,7 @@ public class XMLParserConfiguration extends ParserConfiguration {
/**
* To enable explicit end tag with empty value.
* @param closeEmptyTag
* @param closeEmptyTag new value for the closeEmptyTag property
* @return same instance of configuration with empty tag config updated
*/
public XMLParserConfiguration withCloseEmptyTag(boolean closeEmptyTag){