mirror of
https://github.com/stleary/JSON-java.git
synced 2026-05-20 00:00:59 -04:00
Merge branch 'master' into gh-pages
This commit is contained in:
@@ -5,7 +5,6 @@ Public Domain.
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.io.Writer;
|
||||
import java.lang.reflect.Array;
|
||||
import java.math.BigDecimal;
|
||||
@@ -68,6 +67,12 @@ public class JSONArray implements Iterable<Object> {
|
||||
*/
|
||||
private final ArrayList<Object> myArrayList;
|
||||
|
||||
// strict mode checks after constructor require access to this object
|
||||
private JSONTokener jsonTokener;
|
||||
|
||||
// strict mode checks after constructor require access to this object
|
||||
private JSONParserConfiguration jsonParserConfiguration;
|
||||
|
||||
/**
|
||||
* Construct an empty JSONArray.
|
||||
*/
|
||||
@@ -84,11 +89,31 @@ public class JSONArray implements Iterable<Object> {
|
||||
* If there is a syntax error.
|
||||
*/
|
||||
public JSONArray(JSONTokener x) throws JSONException {
|
||||
this(x, new JSONParserConfiguration());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a JSONArray from a JSONTokener and a JSONParserConfiguration.
|
||||
*
|
||||
* @param x A JSONTokener instance from which the JSONArray is constructed.
|
||||
* @param jsonParserConfiguration A JSONParserConfiguration instance that controls the behavior of the parser.
|
||||
* @throws JSONException If a syntax error occurs during the construction of the JSONArray.
|
||||
*/
|
||||
public JSONArray(JSONTokener x, JSONParserConfiguration jsonParserConfiguration) throws JSONException {
|
||||
this();
|
||||
|
||||
if (this.jsonParserConfiguration == null) {
|
||||
this.jsonParserConfiguration = jsonParserConfiguration;
|
||||
}
|
||||
if (this.jsonTokener == null) {
|
||||
this.jsonTokener = x;
|
||||
this.jsonTokener.setJsonParserConfiguration(this.jsonParserConfiguration);
|
||||
}
|
||||
|
||||
if (x.nextClean() != '[') {
|
||||
throw x.syntaxError("A JSONArray text must start with '['");
|
||||
}
|
||||
|
||||
|
||||
char nextChar = x.nextClean();
|
||||
if (nextChar == 0) {
|
||||
// array is unclosed. No ']' found, instead EOF
|
||||
@@ -115,6 +140,17 @@ public class JSONArray implements Iterable<Object> {
|
||||
throw x.syntaxError("Expected a ',' or ']'");
|
||||
}
|
||||
if (nextChar == ']') {
|
||||
// trailing commas are not allowed in strict mode
|
||||
if (jsonParserConfiguration.isStrictMode()) {
|
||||
throw x.syntaxError("Strict mode error: Expected another array element");
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (nextChar == ',') {
|
||||
// consecutive commas are not allowed in strict mode
|
||||
if (jsonParserConfiguration.isStrictMode()) {
|
||||
throw x.syntaxError("Strict mode error: Expected a valid array element");
|
||||
}
|
||||
return;
|
||||
}
|
||||
x.back();
|
||||
@@ -139,7 +175,32 @@ public class JSONArray implements Iterable<Object> {
|
||||
* If there is a syntax error.
|
||||
*/
|
||||
public JSONArray(String source) throws JSONException {
|
||||
this(new JSONTokener(source));
|
||||
this(source, new JSONParserConfiguration());
|
||||
// Strict mode does not allow trailing chars
|
||||
if (this.jsonParserConfiguration.isStrictMode() &&
|
||||
this.jsonTokener.nextClean() != 0) {
|
||||
throw jsonTokener.syntaxError("Strict mode error: Unparsed characters found at end of input text");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a JSONArray from a source JSON text.
|
||||
*
|
||||
* @param source
|
||||
* A string that begins with <code>[</code> <small>(left
|
||||
* bracket)</small> and ends with <code>]</code>
|
||||
* <small>(right bracket)</small>.
|
||||
* @param jsonParserConfiguration the parser config object
|
||||
* @throws JSONException
|
||||
* If there is a syntax error.
|
||||
*/
|
||||
public JSONArray(String source, JSONParserConfiguration jsonParserConfiguration) throws JSONException {
|
||||
this(new JSONTokener(source), jsonParserConfiguration);
|
||||
// Strict mode does not allow trailing chars
|
||||
if (this.jsonParserConfiguration.isStrictMode() &&
|
||||
this.jsonTokener.nextClean() != 0) {
|
||||
throw jsonTokener.syntaxError("Strict mode error: Unparsed characters found at end of input text");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1695,7 +1756,10 @@ public class JSONArray implements Iterable<Object> {
|
||||
*/
|
||||
@SuppressWarnings("resource")
|
||||
public String toString(int indentFactor) throws JSONException {
|
||||
StringWriter sw = new StringWriter();
|
||||
// each value requires a comma, so multiply the count by 2
|
||||
// We don't want to oversize the initial capacity
|
||||
int initialSize = myArrayList.size() * 2;
|
||||
Writer sw = new StringBuilderWriter(Math.max(initialSize, 16));
|
||||
return this.write(sw, indentFactor, 0).toString();
|
||||
}
|
||||
|
||||
@@ -1937,7 +2001,7 @@ public class JSONArray implements Iterable<Object> {
|
||||
// JSONArray
|
||||
this.myArrayList.addAll(((JSONArray)array).myArrayList);
|
||||
} else if (array instanceof Collection) {
|
||||
this.addAll((Collection<?>)array, wrap, recursionDepth);
|
||||
this.addAll((Collection<?>)array, wrap, recursionDepth, jsonParserConfiguration);
|
||||
} else if (array instanceof Iterable) {
|
||||
this.addAll((Iterable<?>)array, wrap);
|
||||
} else {
|
||||
|
||||
@@ -6,7 +6,6 @@ Public Domain.
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.io.Writer;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Field;
|
||||
@@ -15,17 +14,8 @@ import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
@@ -162,6 +152,12 @@ public class JSONObject {
|
||||
*/
|
||||
public static final Object NULL = new Null();
|
||||
|
||||
// strict mode checks after constructor require access to this object
|
||||
private JSONTokener jsonTokener;
|
||||
|
||||
// strict mode checks after constructor require access to this object
|
||||
private JSONParserConfiguration jsonParserConfiguration;
|
||||
|
||||
/**
|
||||
* Construct an empty JSONObject.
|
||||
*/
|
||||
@@ -205,7 +201,31 @@ public class JSONObject {
|
||||
* duplicated key.
|
||||
*/
|
||||
public JSONObject(JSONTokener x) throws JSONException {
|
||||
this(x, new JSONParserConfiguration());
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a JSONObject from a JSONTokener with custom json parse configurations.
|
||||
*
|
||||
* @param x
|
||||
* A JSONTokener object containing the source string.
|
||||
* @param jsonParserConfiguration
|
||||
* Variable to pass parser custom configuration for json parsing.
|
||||
* @throws JSONException
|
||||
* If there is a syntax error in the source string or a
|
||||
* duplicated key.
|
||||
*/
|
||||
public JSONObject(JSONTokener x, JSONParserConfiguration jsonParserConfiguration) throws JSONException {
|
||||
this();
|
||||
|
||||
if (this.jsonParserConfiguration == null) {
|
||||
this.jsonParserConfiguration = jsonParserConfiguration;
|
||||
}
|
||||
if (this.jsonTokener == null) {
|
||||
this.jsonTokener = x;
|
||||
this.jsonTokener.setJsonParserConfiguration(this.jsonParserConfiguration);
|
||||
}
|
||||
|
||||
char c;
|
||||
String key;
|
||||
|
||||
@@ -234,13 +254,14 @@ public class JSONObject {
|
||||
|
||||
if (key != null) {
|
||||
// Check if key exists
|
||||
if (this.opt(key) != null) {
|
||||
// key already exists
|
||||
boolean keyExists = this.opt(key) != null;
|
||||
if (keyExists && !jsonParserConfiguration.isOverwriteDuplicateKey()) {
|
||||
throw x.syntaxError("Duplicate key \"" + key + "\"");
|
||||
}
|
||||
// Only add value if non-null
|
||||
|
||||
Object value = x.nextValue();
|
||||
if (value!=null) {
|
||||
// Only add value if non-null
|
||||
if (value != null) {
|
||||
this.put(key, value);
|
||||
}
|
||||
}
|
||||
@@ -249,8 +270,16 @@ public class JSONObject {
|
||||
|
||||
switch (x.nextClean()) {
|
||||
case ';':
|
||||
// In strict mode semicolon is not a valid separator
|
||||
if (jsonParserConfiguration.isStrictMode()) {
|
||||
throw x.syntaxError("Strict mode error: Invalid character ';' found");
|
||||
}
|
||||
case ',':
|
||||
if (x.nextClean() == '}') {
|
||||
// trailing commas are not allowed in strict mode
|
||||
if (jsonParserConfiguration.isStrictMode()) {
|
||||
throw x.syntaxError("Strict mode error: Expected another object element");
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (x.end()) {
|
||||
@@ -296,7 +325,6 @@ public class JSONObject {
|
||||
|
||||
/**
|
||||
* Construct a JSONObject from a map with recursion depth.
|
||||
*
|
||||
*/
|
||||
private JSONObject(Map<?, ?> m, int recursionDepth, JSONParserConfiguration jsonParserConfiguration) {
|
||||
if (recursionDepth > jsonParserConfiguration.getMaxNestingDepth()) {
|
||||
@@ -427,7 +455,35 @@ public class JSONObject {
|
||||
* duplicated key.
|
||||
*/
|
||||
public JSONObject(String source) throws JSONException {
|
||||
this(new JSONTokener(source));
|
||||
this(source, new JSONParserConfiguration());
|
||||
// Strict mode does not allow trailing chars
|
||||
if (this.jsonParserConfiguration.isStrictMode() &&
|
||||
this.jsonTokener.nextClean() != 0) {
|
||||
throw new JSONException("Strict mode error: Unparsed characters found at end of input text");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a JSONObject from a source JSON text string with custom json parse configurations.
|
||||
* This is the most commonly used JSONObject constructor.
|
||||
*
|
||||
* @param source
|
||||
* A string beginning with <code>{</code> <small>(left
|
||||
* brace)</small> and ending with <code>}</code>
|
||||
* <small>(right brace)</small>.
|
||||
* @param jsonParserConfiguration
|
||||
* Variable to pass parser custom configuration for json parsing.
|
||||
* @exception JSONException
|
||||
* If there is a syntax error in the source string or a
|
||||
* duplicated key.
|
||||
*/
|
||||
public JSONObject(String source, JSONParserConfiguration jsonParserConfiguration) throws JSONException {
|
||||
this(new JSONTokener(source), jsonParserConfiguration);
|
||||
// Strict mode does not allow trailing chars
|
||||
if (this.jsonParserConfiguration.isStrictMode() &&
|
||||
this.jsonTokener.nextClean() != 0) {
|
||||
throw new JSONException("Strict mode error: Unparsed characters found at end of input text");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2224,7 +2280,10 @@ public class JSONObject {
|
||||
*/
|
||||
@SuppressWarnings("resource")
|
||||
public static String quote(String string) {
|
||||
StringWriter sw = new StringWriter();
|
||||
if (string == null || string.isEmpty()) {
|
||||
return "\"\"";
|
||||
}
|
||||
Writer sw = new StringBuilderWriter(string.length() + 2);
|
||||
try {
|
||||
return quote(string, sw).toString();
|
||||
} catch (IOException ignored) {
|
||||
@@ -2623,7 +2682,10 @@ public class JSONObject {
|
||||
*/
|
||||
@SuppressWarnings("resource")
|
||||
public String toString(int indentFactor) throws JSONException {
|
||||
StringWriter w = new StringWriter();
|
||||
// 6 characters are the minimum to serialise a key value pair e.g.: "k":1,
|
||||
// and we don't want to oversize the initial capacity
|
||||
int initialSize = map.size() * 6;
|
||||
Writer w = new StringBuilderWriter(Math.max(initialSize, 16));
|
||||
return this.write(w, indentFactor, 0).toString();
|
||||
}
|
||||
|
||||
@@ -2766,6 +2828,7 @@ public class JSONObject {
|
||||
if (value == null || value.equals(null)) {
|
||||
writer.write("null");
|
||||
} else if (value instanceof JSONString) {
|
||||
// JSONString must be checked first, so it can overwrite behaviour of other types below
|
||||
Object o;
|
||||
try {
|
||||
o = ((JSONString) value).toJSONString();
|
||||
@@ -2773,6 +2836,10 @@ public class JSONObject {
|
||||
throw new JSONException(e);
|
||||
}
|
||||
writer.write(o != null ? o.toString() : quote(value.toString()));
|
||||
} else if (value instanceof String) {
|
||||
// assuming most values are Strings, so testing it early
|
||||
quote(value.toString(), writer);
|
||||
return writer;
|
||||
} else if (value instanceof Number) {
|
||||
// not all Numbers may match actual JSON Numbers. i.e. fractions or Imaginary
|
||||
final String numberAsString = numberToString((Number) value);
|
||||
|
||||
@@ -4,23 +4,109 @@ package org.json;
|
||||
* Configuration object for the JSON parser. The configuration is immutable.
|
||||
*/
|
||||
public class JSONParserConfiguration extends ParserConfiguration {
|
||||
/**
|
||||
* Used to indicate whether to overwrite duplicate key or not.
|
||||
*/
|
||||
private boolean overwriteDuplicateKey;
|
||||
|
||||
/**
|
||||
* Configuration with the default values.
|
||||
*/
|
||||
public JSONParserConfiguration() {
|
||||
super();
|
||||
}
|
||||
/**
|
||||
* Configuration with the default values.
|
||||
*/
|
||||
public JSONParserConfiguration() {
|
||||
super();
|
||||
this.overwriteDuplicateKey = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JSONParserConfiguration clone() {
|
||||
return new JSONParserConfiguration();
|
||||
}
|
||||
/**
|
||||
* This flag, when set to true, instructs the parser to enforce strict mode when parsing JSON text.
|
||||
* Garbage chars at the end of the doc, unquoted string, and single-quoted strings are all disallowed.
|
||||
*/
|
||||
private boolean strictMode;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public JSONParserConfiguration withMaxNestingDepth(final int maxNestingDepth) {
|
||||
return super.withMaxNestingDepth(maxNestingDepth);
|
||||
}
|
||||
@Override
|
||||
protected JSONParserConfiguration clone() {
|
||||
JSONParserConfiguration clone = new JSONParserConfiguration();
|
||||
clone.overwriteDuplicateKey = overwriteDuplicateKey;
|
||||
clone.maxNestingDepth = maxNestingDepth;
|
||||
return clone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the maximum nesting depth that the parser will descend before throwing an exception
|
||||
* when parsing a map into JSONObject or parsing a {@link java.util.Collection} instance into
|
||||
* JSONArray. The default max nesting depth is 512, which means the parser will throw a JsonException
|
||||
* if the maximum depth is reached.
|
||||
*
|
||||
* @param maxNestingDepth the maximum nesting depth allowed to the JSON parser
|
||||
* @return The existing configuration will not be modified. A new configuration is returned.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public JSONParserConfiguration withMaxNestingDepth(final int maxNestingDepth) {
|
||||
JSONParserConfiguration clone = this.clone();
|
||||
clone.maxNestingDepth = maxNestingDepth;
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Controls the parser's behavior when meeting duplicate keys.
|
||||
* If set to false, the parser will throw a JSONException when meeting a duplicate key.
|
||||
* Or the duplicate key's value will be overwritten.
|
||||
*
|
||||
* @param overwriteDuplicateKey defines should the parser overwrite duplicate keys.
|
||||
* @return The existing configuration will not be modified. A new configuration is returned.
|
||||
*/
|
||||
public JSONParserConfiguration withOverwriteDuplicateKey(final boolean overwriteDuplicateKey) {
|
||||
JSONParserConfiguration clone = this.clone();
|
||||
clone.overwriteDuplicateKey = overwriteDuplicateKey;
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the strict mode configuration for the JSON parser with default true value
|
||||
* <p>
|
||||
* When strict mode is enabled, the parser will throw a JSONException if it encounters an invalid character
|
||||
* immediately following the final ']' character in the input. This is useful for ensuring strict adherence to the
|
||||
* JSON syntax, as any characters after the final closing bracket of a JSON array are considered invalid.
|
||||
* @return a new JSONParserConfiguration instance with the updated strict mode setting
|
||||
*/
|
||||
public JSONParserConfiguration withStrictMode() {
|
||||
return withStrictMode(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the strict mode configuration for the JSON parser.
|
||||
* <p>
|
||||
* When strict mode is enabled, the parser will throw a JSONException if it encounters an invalid character
|
||||
* immediately following the final ']' character in the input. This is useful for ensuring strict adherence to the
|
||||
* JSON syntax, as any characters after the final closing bracket of a JSON array are considered invalid.
|
||||
*
|
||||
* @param mode a boolean value indicating whether strict mode should be enabled or not
|
||||
* @return a new JSONParserConfiguration instance with the updated strict mode setting
|
||||
*/
|
||||
public JSONParserConfiguration withStrictMode(final boolean mode) {
|
||||
JSONParserConfiguration clone = this.clone();
|
||||
clone.strictMode = mode;
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
/**
|
||||
* The parser's behavior when meeting duplicate keys, controls whether the parser should
|
||||
* overwrite duplicate keys or not.
|
||||
*
|
||||
* @return The <code>overwriteDuplicateKey</code> configuration value.
|
||||
*/
|
||||
public boolean isOverwriteDuplicateKey() {
|
||||
return this.overwriteDuplicateKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the current strict mode setting.
|
||||
*/
|
||||
public boolean isStrictMode() {
|
||||
return this.strictMode;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,8 @@ public class JSONTokener {
|
||||
/** the number of characters read in the previous line. */
|
||||
private long characterPreviousLine;
|
||||
|
||||
// access to this object is required for strict mode checking
|
||||
private JSONParserConfiguration jsonParserConfiguration;
|
||||
|
||||
/**
|
||||
* Construct a JSONTokener from a Reader. The caller must close the Reader.
|
||||
@@ -70,6 +72,21 @@ public class JSONTokener {
|
||||
this(new StringReader(s));
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter
|
||||
* @return jsonParserConfiguration
|
||||
*/
|
||||
public JSONParserConfiguration getJsonParserConfiguration() {
|
||||
return jsonParserConfiguration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter
|
||||
* @param jsonParserConfiguration new value for jsonParserConfiguration
|
||||
*/
|
||||
public void setJsonParserConfiguration(JSONParserConfiguration jsonParserConfiguration) {
|
||||
this.jsonParserConfiguration = jsonParserConfiguration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Back up one character. This provides a sort of lookahead capability,
|
||||
@@ -299,7 +316,8 @@ public class JSONTokener {
|
||||
case 0:
|
||||
case '\n':
|
||||
case '\r':
|
||||
throw this.syntaxError("Unterminated string");
|
||||
throw this.syntaxError("Unterminated string. " +
|
||||
"Character with int code " + (int) c + " is not allowed within a quoted string.");
|
||||
case '\\':
|
||||
c = this.next();
|
||||
switch (c) {
|
||||
@@ -319,10 +337,12 @@ public class JSONTokener {
|
||||
sb.append('\r');
|
||||
break;
|
||||
case 'u':
|
||||
String next = this.next(4);
|
||||
try {
|
||||
sb.append((char)Integer.parseInt(this.next(4), 16));
|
||||
sb.append((char)Integer.parseInt(next, 16));
|
||||
} catch (NumberFormatException e) {
|
||||
throw this.syntaxError("Illegal escape.", e);
|
||||
throw this.syntaxError("Illegal escape. " +
|
||||
"\\u must be followed by a 4 digit hexadecimal number. \\" + next + " is not valid.", e);
|
||||
}
|
||||
break;
|
||||
case '"':
|
||||
@@ -332,7 +352,7 @@ public class JSONTokener {
|
||||
sb.append(c);
|
||||
break;
|
||||
default:
|
||||
throw this.syntaxError("Illegal escape.");
|
||||
throw this.syntaxError("Illegal escape. Escape sequence \\" + c + " is not valid.");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -406,14 +426,14 @@ public class JSONTokener {
|
||||
case '{':
|
||||
this.back();
|
||||
try {
|
||||
return new JSONObject(this);
|
||||
return new JSONObject(this, jsonParserConfiguration);
|
||||
} catch (StackOverflowError e) {
|
||||
throw new JSONException("JSON Array or Object depth too large to process.", e);
|
||||
}
|
||||
case '[':
|
||||
this.back();
|
||||
try {
|
||||
return new JSONArray(this);
|
||||
return new JSONArray(this, jsonParserConfiguration);
|
||||
} catch (StackOverflowError e) {
|
||||
throw new JSONException("JSON Array or Object depth too large to process.", e);
|
||||
}
|
||||
@@ -424,6 +444,12 @@ public class JSONTokener {
|
||||
Object nextSimpleValue(char c) {
|
||||
String string;
|
||||
|
||||
// Strict mode only allows strings with explicit double quotes
|
||||
if (jsonParserConfiguration != null &&
|
||||
jsonParserConfiguration.isStrictMode() &&
|
||||
c == '\'') {
|
||||
throw this.syntaxError("Strict mode error: Single quoted strings are not allowed");
|
||||
}
|
||||
switch (c) {
|
||||
case '"':
|
||||
case '\'':
|
||||
@@ -452,7 +478,14 @@ public class JSONTokener {
|
||||
if ("".equals(string)) {
|
||||
throw this.syntaxError("Missing value");
|
||||
}
|
||||
return JSONObject.stringToValue(string);
|
||||
Object obj = JSONObject.stringToValue(string);
|
||||
// Strict mode only allows strings with explicit double quotes
|
||||
if (jsonParserConfiguration != null &&
|
||||
jsonParserConfiguration.isStrictMode() &&
|
||||
obj instanceof String) {
|
||||
throw this.syntaxError(String.format("Strict mode error: Value '%s' is not surrounded by quotes", obj));
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -20,12 +20,12 @@ public class ParserConfiguration {
|
||||
|
||||
/**
|
||||
* Specifies if values should be kept as strings (<code>true</code>), or if
|
||||
* they should try to be guessed into JSON values (numeric, boolean, string)
|
||||
* they should try to be guessed into JSON values (numeric, boolean, string).
|
||||
*/
|
||||
protected boolean keepStrings;
|
||||
|
||||
/**
|
||||
* The maximum nesting depth when parsing a document.
|
||||
* The maximum nesting depth when parsing an object.
|
||||
*/
|
||||
protected int maxNestingDepth;
|
||||
|
||||
@@ -59,14 +59,14 @@ public class ParserConfiguration {
|
||||
// map should be cloned as well. If the values of the map are known to also
|
||||
// be immutable, then a shallow clone of the map is acceptable.
|
||||
return new ParserConfiguration(
|
||||
this.keepStrings,
|
||||
this.maxNestingDepth
|
||||
this.keepStrings,
|
||||
this.maxNestingDepth
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* When parsing the XML into JSONML, specifies if values should be kept as strings (<code>true</code>), or if
|
||||
* they should try to be guessed into JSON values (numeric, boolean, string)
|
||||
* they should try to be guessed into JSON values (numeric, boolean, string).
|
||||
*
|
||||
* @return The <code>keepStrings</code> configuration value.
|
||||
*/
|
||||
@@ -78,22 +78,21 @@ public class ParserConfiguration {
|
||||
* When parsing the XML into JSONML, specifies if values should be kept as strings (<code>true</code>), or if
|
||||
* they should try to be guessed into JSON values (numeric, boolean, string)
|
||||
*
|
||||
* @param newVal
|
||||
* new value to use for the <code>keepStrings</code> configuration option.
|
||||
* @param <T> the type of the configuration object
|
||||
*
|
||||
* @param newVal new value to use for the <code>keepStrings</code> configuration option.
|
||||
* @param <T> the type of the configuration object
|
||||
* @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();
|
||||
T newConfig = (T) this.clone();
|
||||
newConfig.keepStrings = newVal;
|
||||
return newConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* The maximum nesting depth that the parser will descend before throwing an exception
|
||||
* when parsing the XML into JSONML.
|
||||
* when parsing an object (e.g. Map, Collection) into JSON-related objects.
|
||||
*
|
||||
* @return the maximum nesting depth set for this configuration
|
||||
*/
|
||||
public int getMaxNestingDepth() {
|
||||
@@ -102,18 +101,19 @@ public class ParserConfiguration {
|
||||
|
||||
/**
|
||||
* Defines the maximum nesting depth that the parser will descend before throwing an exception
|
||||
* when parsing the XML into JSONML. The default max nesting depth is 512, which means the parser
|
||||
* will throw a JsonException if the maximum depth is reached.
|
||||
* when parsing an object (e.g. Map, Collection) into JSON-related objects.
|
||||
* The default max nesting depth is 512, which means the parser will throw a JsonException if
|
||||
* the maximum depth is reached.
|
||||
* Using any negative value as a parameter is equivalent to setting no limit to the nesting depth,
|
||||
* which means the parses will go as deep as the maximum call stack size allows.
|
||||
*
|
||||
* @param maxNestingDepth the maximum nesting depth allowed to the XML parser
|
||||
* @param <T> the type of the configuration object
|
||||
*
|
||||
* @param <T> the type of the configuration object
|
||||
* @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();
|
||||
T newConfig = (T) this.clone();
|
||||
|
||||
if (maxNestingDepth > UNDEFINED_MAXIMUM_NESTING_DEPTH) {
|
||||
newConfig.maxNestingDepth = maxNestingDepth;
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
package org.json;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
|
||||
/**
|
||||
* Performance optimised alternative for {@link java.io.StringWriter}
|
||||
* using internally a {@link StringBuilder} instead of a {@link StringBuffer}.
|
||||
*/
|
||||
public class StringBuilderWriter extends Writer {
|
||||
private final StringBuilder builder;
|
||||
|
||||
/**
|
||||
* Create a new string builder writer using the default initial string-builder buffer size.
|
||||
*/
|
||||
public StringBuilderWriter() {
|
||||
builder = new StringBuilder();
|
||||
lock = builder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new string builder writer using the specified initial string-builder buffer size.
|
||||
*
|
||||
* @param initialSize The number of {@code char} values that will fit into this buffer
|
||||
* before it is automatically expanded
|
||||
*
|
||||
* @throws IllegalArgumentException If {@code initialSize} is negative
|
||||
*/
|
||||
public StringBuilderWriter(int initialSize) {
|
||||
builder = new StringBuilder(initialSize);
|
||||
lock = builder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(int c) {
|
||||
builder.append((char) c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(char[] cbuf, int offset, int length) {
|
||||
if ((offset < 0) || (offset > cbuf.length) || (length < 0) ||
|
||||
((offset + length) > cbuf.length) || ((offset + length) < 0)) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
} else if (length == 0) {
|
||||
return;
|
||||
}
|
||||
builder.append(cbuf, offset, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(String str) {
|
||||
builder.append(str);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(String str, int offset, int length) {
|
||||
builder.append(str, offset, offset + length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StringBuilderWriter append(CharSequence csq) {
|
||||
write(String.valueOf(csq));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StringBuilderWriter append(CharSequence csq, int start, int end) {
|
||||
if (csq == null) {
|
||||
csq = "null";
|
||||
}
|
||||
return append(csq.subSequence(start, end));
|
||||
}
|
||||
|
||||
@Override
|
||||
public StringBuilderWriter append(char c) {
|
||||
write(c);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user