mirror of
https://github.com/fankes/JSON-java-compat.git
synced 2025-09-09 03:54:36 +08:00
Merge branch 'master' into 863-improve-toString-performance-StringBuilderWriter
This commit is contained in:
@@ -25,6 +25,12 @@ Public Domain.
|
||||
*/
|
||||
public class CDL {
|
||||
|
||||
/**
|
||||
* Constructs a new CDL object.
|
||||
*/
|
||||
public CDL() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the next value. The value can be wrapped in quotes. The value can
|
||||
* be empty.
|
||||
|
@@ -15,6 +15,12 @@ Public Domain.
|
||||
*/
|
||||
public class Cookie {
|
||||
|
||||
/**
|
||||
* Constructs a new Cookie object.
|
||||
*/
|
||||
public Cookie() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce a copy of a string in which the characters '+', '%', '=', ';'
|
||||
* and control characters are replaced with "%hh". This is a gentle form
|
||||
|
@@ -11,6 +11,12 @@ Public Domain.
|
||||
*/
|
||||
public class CookieList {
|
||||
|
||||
/**
|
||||
* Constructs a new CookieList object.
|
||||
*/
|
||||
public CookieList() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a cookie list into a JSONObject. A cookie list is a sequence
|
||||
* of name/value pairs. The names are separated from the values by '='.
|
||||
|
@@ -13,6 +13,12 @@ import java.util.Locale;
|
||||
*/
|
||||
public class HTTP {
|
||||
|
||||
/**
|
||||
* Constructs a new HTTP object.
|
||||
*/
|
||||
public HTTP() {
|
||||
}
|
||||
|
||||
/** Carriage return/line feed. */
|
||||
public static final String CRLF = "\r\n";
|
||||
|
||||
|
@@ -359,7 +359,7 @@ public class JSONArray implements Iterable<Object> {
|
||||
if (object instanceof Number) {
|
||||
return (Number)object;
|
||||
}
|
||||
return NumberConversionUtil.stringToNumber(object.toString());
|
||||
return JSONObject.stringToNumber(object.toString());
|
||||
} catch (Exception e) {
|
||||
throw wrongValueFormatException(index, "number", object, e);
|
||||
}
|
||||
@@ -1106,7 +1106,7 @@ public class JSONArray implements Iterable<Object> {
|
||||
|
||||
if (val instanceof String) {
|
||||
try {
|
||||
return NumberConversionUtil.stringToNumber((String) val);
|
||||
return JSONObject.stringToNumber((String) val);
|
||||
} catch (Exception e) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
@@ -13,6 +13,13 @@ Public Domain.
|
||||
* @version 2016-01-30
|
||||
*/
|
||||
public class JSONML {
|
||||
|
||||
/**
|
||||
* Constructs a new JSONML object.
|
||||
*/
|
||||
public JSONML() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse XML values and store them in a JSONArray.
|
||||
* @param x The XMLTokener containing the source string.
|
||||
|
@@ -14,22 +14,10 @@ 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;
|
||||
|
||||
import static org.json.NumberConversionUtil.potentialNumber;
|
||||
import static org.json.NumberConversionUtil.stringToNumber;
|
||||
|
||||
/**
|
||||
* A JSONObject is an unordered collection of name/value pairs. Its external
|
||||
* form is a string wrapped in curly braces with colons between the names and
|
||||
@@ -207,6 +195,21 @@ 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();
|
||||
char c;
|
||||
String key;
|
||||
@@ -236,13 +239,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);
|
||||
}
|
||||
}
|
||||
@@ -298,7 +302,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()) {
|
||||
@@ -429,7 +432,25 @@ public class JSONObject {
|
||||
* duplicated key.
|
||||
*/
|
||||
public JSONObject(String source) throws JSONException {
|
||||
this(new JSONTokener(source));
|
||||
this(source, new JSONParserConfiguration());
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2462,7 +2483,8 @@ public class JSONObject {
|
||||
* produced, then the value will just be a string.
|
||||
*/
|
||||
|
||||
if (potentialNumber(string)) {
|
||||
char initial = string.charAt(0);
|
||||
if ((initial >= '0' && initial <= '9') || initial == '-') {
|
||||
try {
|
||||
return stringToNumber(string);
|
||||
} catch (Exception ignore) {
|
||||
@@ -2471,8 +2493,75 @@ public class JSONObject {
|
||||
return string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a string to a number using the narrowest possible type. Possible
|
||||
* returns for this function are BigDecimal, Double, BigInteger, Long, and Integer.
|
||||
* When a Double is returned, it should always be a valid Double and not NaN or +-infinity.
|
||||
*
|
||||
* @param val value to convert
|
||||
* @return Number representation of the value.
|
||||
* @throws NumberFormatException thrown if the value is not a valid number. A public
|
||||
* caller should catch this and wrap it in a {@link JSONException} if applicable.
|
||||
*/
|
||||
protected static Number stringToNumber(final String val) throws NumberFormatException {
|
||||
char initial = val.charAt(0);
|
||||
if ((initial >= '0' && initial <= '9') || initial == '-') {
|
||||
// decimal representation
|
||||
if (isDecimalNotation(val)) {
|
||||
// Use a BigDecimal all the time so we keep the original
|
||||
// representation. BigDecimal doesn't support -0.0, ensure we
|
||||
// keep that by forcing a decimal.
|
||||
try {
|
||||
BigDecimal bd = new BigDecimal(val);
|
||||
if(initial == '-' && BigDecimal.ZERO.compareTo(bd)==0) {
|
||||
return Double.valueOf(-0.0);
|
||||
}
|
||||
return bd;
|
||||
} catch (NumberFormatException retryAsDouble) {
|
||||
// this is to support "Hex Floats" like this: 0x1.0P-1074
|
||||
try {
|
||||
Double d = Double.valueOf(val);
|
||||
if(d.isNaN() || d.isInfinite()) {
|
||||
throw new NumberFormatException("val ["+val+"] is not a valid number.");
|
||||
}
|
||||
return d;
|
||||
} catch (NumberFormatException ignore) {
|
||||
throw new NumberFormatException("val ["+val+"] is not a valid number.");
|
||||
}
|
||||
}
|
||||
}
|
||||
// block items like 00 01 etc. Java number parsers treat these as Octal.
|
||||
if(initial == '0' && val.length() > 1) {
|
||||
char at1 = val.charAt(1);
|
||||
if(at1 >= '0' && at1 <= '9') {
|
||||
throw new NumberFormatException("val ["+val+"] 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') {
|
||||
throw new NumberFormatException("val ["+val+"] is not a valid number.");
|
||||
}
|
||||
}
|
||||
// integer representation.
|
||||
// This will narrow any values to the smallest reasonable Object representation
|
||||
// (Integer, Long, or BigInteger)
|
||||
|
||||
|
||||
// BigInteger down conversion: We use a similar bitLength compare as
|
||||
// BigInteger#intValueExact uses. Increases GC, but objects hold
|
||||
// only what they need. i.e. Less runtime overhead if the value is
|
||||
// long lived.
|
||||
BigInteger bi = new BigInteger(val);
|
||||
if(bi.bitLength() <= 31){
|
||||
return Integer.valueOf(bi.intValue());
|
||||
}
|
||||
if(bi.bitLength() <= 63){
|
||||
return Long.valueOf(bi.longValue());
|
||||
}
|
||||
return bi;
|
||||
}
|
||||
throw new NumberFormatException("val ["+val+"] is not a valid number.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Throw an exception if the object is a NaN or infinite number.
|
||||
@@ -2906,5 +2995,23 @@ public class JSONObject {
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* For a prospective number, remove the leading zeros
|
||||
* @param value prospective number
|
||||
* @return number without leading zeros
|
||||
*/
|
||||
private static String removeLeadingZerosOfNumber(String value){
|
||||
if (value.equals("-")){return value;}
|
||||
boolean negativeFirstChar = (value.charAt(0) == '-');
|
||||
int counter = negativeFirstChar ? 1:0;
|
||||
while (counter < value.length()){
|
||||
if (value.charAt(counter) != '0'){
|
||||
if (negativeFirstChar) {return "-".concat(value.substring(counter));}
|
||||
return value.substring(counter);
|
||||
}
|
||||
++counter;
|
||||
}
|
||||
if (negativeFirstChar) {return "-0";}
|
||||
return "0";
|
||||
}
|
||||
}
|
||||
|
@@ -4,23 +4,67 @@ 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();
|
||||
}
|
||||
@Override
|
||||
protected JSONParserConfiguration clone() {
|
||||
JSONParserConfiguration clone = new JSONParserConfiguration();
|
||||
clone.overwriteDuplicateKey = overwriteDuplicateKey;
|
||||
clone.maxNestingDepth = maxNestingDepth;
|
||||
return clone;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public JSONParserConfiguration withMaxNestingDepth(final int maxNestingDepth) {
|
||||
return super.withMaxNestingDepth(maxNestingDepth);
|
||||
}
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
|
@@ -42,6 +42,12 @@ public class JSONPointer {
|
||||
*/
|
||||
public static class Builder {
|
||||
|
||||
/**
|
||||
* Constructs a new Builder object.
|
||||
*/
|
||||
public Builder() {
|
||||
}
|
||||
|
||||
// Segments for the eventual JSONPointer string
|
||||
private final List<String> refTokens = new ArrayList<String>();
|
||||
|
||||
|
@@ -21,6 +21,7 @@ import java.lang.annotation.Target;
|
||||
@Target({METHOD})
|
||||
public @interface JSONPropertyName {
|
||||
/**
|
||||
* The value of the JSON property.
|
||||
* @return The name of the property as to be used in the JSON Object.
|
||||
*/
|
||||
String value();
|
||||
|
@@ -1,152 +0,0 @@
|
||||
package org.json;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
|
||||
class NumberConversionUtil {
|
||||
|
||||
/**
|
||||
* Converts a string to a number using the narrowest possible type. Possible
|
||||
* returns for this function are BigDecimal, Double, BigInteger, Long, and Integer.
|
||||
* When a Double is returned, it should always be a valid Double and not NaN or +-infinity.
|
||||
*
|
||||
* @param input value to convert
|
||||
* @return Number representation of the value.
|
||||
* @throws NumberFormatException thrown if the value is not a valid number. A public
|
||||
* caller should catch this and wrap it in a {@link JSONException} if applicable.
|
||||
*/
|
||||
static Number stringToNumber(final String input) throws NumberFormatException {
|
||||
String val = input;
|
||||
if (val.startsWith(".")){
|
||||
val = "0"+val;
|
||||
}
|
||||
if (val.startsWith("-.")){
|
||||
val = "-0."+val.substring(2);
|
||||
}
|
||||
char initial = val.charAt(0);
|
||||
if ( isNumericChar(initial) || initial == '-' ) {
|
||||
// decimal representation
|
||||
if (isDecimalNotation(val)) {
|
||||
// Use a BigDecimal all the time so we keep the original
|
||||
// representation. BigDecimal doesn't support -0.0, ensure we
|
||||
// keep that by forcing a decimal.
|
||||
try {
|
||||
BigDecimal bd = new BigDecimal(val);
|
||||
if(initial == '-' && BigDecimal.ZERO.compareTo(bd)==0) {
|
||||
return Double.valueOf(-0.0);
|
||||
}
|
||||
return bd;
|
||||
} catch (NumberFormatException retryAsDouble) {
|
||||
// this is to support "Hex Floats" like this: 0x1.0P-1074
|
||||
try {
|
||||
Double d = Double.valueOf(val);
|
||||
if(d.isNaN() || d.isInfinite()) {
|
||||
throw new NumberFormatException("val ["+input+"] is not a valid number.");
|
||||
}
|
||||
return d;
|
||||
} catch (NumberFormatException ignore) {
|
||||
throw new NumberFormatException("val ["+input+"] is not a valid number.");
|
||||
}
|
||||
}
|
||||
}
|
||||
val = removeLeadingZerosOfNumber(input);
|
||||
initial = val.charAt(0);
|
||||
if(initial == '0' && val.length() > 1) {
|
||||
char at1 = val.charAt(1);
|
||||
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' && isNumericChar(at2)) {
|
||||
throw new NumberFormatException("val ["+input+"] is not a valid number.");
|
||||
}
|
||||
}
|
||||
// integer representation.
|
||||
// This will narrow any values to the smallest reasonable Object representation
|
||||
// (Integer, Long, or BigInteger)
|
||||
|
||||
// BigInteger down conversion: We use a similar bitLength compare as
|
||||
// BigInteger#intValueExact uses. Increases GC, but objects hold
|
||||
// only what they need. i.e. Less runtime overhead if the value is
|
||||
// long lived.
|
||||
BigInteger bi = new BigInteger(val);
|
||||
if(bi.bitLength() <= 31){
|
||||
return Integer.valueOf(bi.intValue());
|
||||
}
|
||||
if(bi.bitLength() <= 63){
|
||||
return Long.valueOf(bi.longValue());
|
||||
}
|
||||
return bi;
|
||||
}
|
||||
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
|
||||
* @return
|
||||
*/
|
||||
static boolean potentialNumber(String value){
|
||||
if (value == null || value.isEmpty()){
|
||||
return false;
|
||||
}
|
||||
return potentialPositiveNumberStartingAtIndex(value, (value.charAt(0)=='-'?1:0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if the value should be tried as a decimal. It makes no test if there are actual digits.
|
||||
*
|
||||
* @param val value to test
|
||||
* @return true if the string is "-0" or if it contains '.', 'e', or 'E', false otherwise.
|
||||
*/
|
||||
private static boolean isDecimalNotation(final String val) {
|
||||
return val.indexOf('.') > -1 || val.indexOf('e') > -1
|
||||
|| val.indexOf('E') > -1 || "-0".equals(val);
|
||||
}
|
||||
|
||||
private static boolean potentialPositiveNumberStartingAtIndex(String value,int index){
|
||||
if (index >= value.length()){
|
||||
return false;
|
||||
}
|
||||
return digitAtIndex(value, (value.charAt(index)=='.'?index+1:index));
|
||||
}
|
||||
|
||||
private static boolean digitAtIndex(String value, int index){
|
||||
if (index >= value.length()){
|
||||
return false;
|
||||
}
|
||||
return value.charAt(index) >= '0' && value.charAt(index) <= '9';
|
||||
}
|
||||
|
||||
/**
|
||||
* For a prospective number, remove the leading zeros
|
||||
* @param value prospective number
|
||||
* @return number without leading zeros
|
||||
*/
|
||||
private static String removeLeadingZerosOfNumber(String value){
|
||||
if (value.equals("-")){return value;}
|
||||
boolean negativeFirstChar = (value.charAt(0) == '-');
|
||||
int counter = negativeFirstChar ? 1:0;
|
||||
while (counter < value.length()){
|
||||
if (value.charAt(counter) != '0'){
|
||||
if (negativeFirstChar) {return "-".concat(value.substring(counter));}
|
||||
return value.substring(counter);
|
||||
}
|
||||
++counter;
|
||||
}
|
||||
if (negativeFirstChar) {return "-0";}
|
||||
return "0";
|
||||
}
|
||||
}
|
@@ -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;
|
||||
|
@@ -13,6 +13,13 @@ import java.util.Properties;
|
||||
* @version 2015-05-05
|
||||
*/
|
||||
public class Property {
|
||||
|
||||
/**
|
||||
* Constructs a new Property object.
|
||||
*/
|
||||
public Property() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a property file object into a JSONObject. The property file object is a table of name value pairs.
|
||||
* @param properties java.util.Properties
|
||||
|
@@ -10,10 +10,6 @@ import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.util.Iterator;
|
||||
|
||||
import static org.json.NumberConversionUtil.potentialNumber;
|
||||
import static org.json.NumberConversionUtil.stringToNumber;
|
||||
|
||||
|
||||
/**
|
||||
* This provides static methods to convert an XML text into a JSONObject, and to
|
||||
* covert a JSONObject into an XML text.
|
||||
@@ -24,6 +20,12 @@ import static org.json.NumberConversionUtil.stringToNumber;
|
||||
@SuppressWarnings("boxing")
|
||||
public class XML {
|
||||
|
||||
/**
|
||||
* Constructs a new XML object.
|
||||
*/
|
||||
public XML() {
|
||||
}
|
||||
|
||||
/** The Character '&'. */
|
||||
public static final Character AMP = '&';
|
||||
|
||||
@@ -493,6 +495,76 @@ public class XML {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* direct copy of {@link JSONObject#stringToNumber(String)} to maintain Android support.
|
||||
*/
|
||||
private static Number stringToNumber(final String val) throws NumberFormatException {
|
||||
char initial = val.charAt(0);
|
||||
if ((initial >= '0' && initial <= '9') || initial == '-') {
|
||||
// decimal representation
|
||||
if (isDecimalNotation(val)) {
|
||||
// Use a BigDecimal all the time so we keep the original
|
||||
// representation. BigDecimal doesn't support -0.0, ensure we
|
||||
// keep that by forcing a decimal.
|
||||
try {
|
||||
BigDecimal bd = new BigDecimal(val);
|
||||
if(initial == '-' && BigDecimal.ZERO.compareTo(bd)==0) {
|
||||
return Double.valueOf(-0.0);
|
||||
}
|
||||
return bd;
|
||||
} catch (NumberFormatException retryAsDouble) {
|
||||
// this is to support "Hex Floats" like this: 0x1.0P-1074
|
||||
try {
|
||||
Double d = Double.valueOf(val);
|
||||
if(d.isNaN() || d.isInfinite()) {
|
||||
throw new NumberFormatException("val ["+val+"] is not a valid number.");
|
||||
}
|
||||
return d;
|
||||
} catch (NumberFormatException ignore) {
|
||||
throw new NumberFormatException("val ["+val+"] is not a valid number.");
|
||||
}
|
||||
}
|
||||
}
|
||||
// block items like 00 01 etc. Java number parsers treat these as Octal.
|
||||
if(initial == '0' && val.length() > 1) {
|
||||
char at1 = val.charAt(1);
|
||||
if(at1 >= '0' && at1 <= '9') {
|
||||
throw new NumberFormatException("val ["+val+"] 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') {
|
||||
throw new NumberFormatException("val ["+val+"] is not a valid number.");
|
||||
}
|
||||
}
|
||||
// integer representation.
|
||||
// This will narrow any values to the smallest reasonable Object representation
|
||||
// (Integer, Long, or BigInteger)
|
||||
|
||||
// BigInteger down conversion: We use a similar bitLength compare as
|
||||
// BigInteger#intValueExact uses. Increases GC, but objects hold
|
||||
// only what they need. i.e. Less runtime overhead if the value is
|
||||
// long lived.
|
||||
BigInteger bi = new BigInteger(val);
|
||||
if(bi.bitLength() <= 31){
|
||||
return Integer.valueOf(bi.intValue());
|
||||
}
|
||||
if(bi.bitLength() <= 63){
|
||||
return Long.valueOf(bi.longValue());
|
||||
}
|
||||
return bi;
|
||||
}
|
||||
throw new NumberFormatException("val ["+val+"] is not a valid number.");
|
||||
}
|
||||
|
||||
/**
|
||||
* direct copy of {@link JSONObject#isDecimalNotation(String)} to maintain Android support.
|
||||
*/
|
||||
private static boolean isDecimalNotation(final String val) {
|
||||
return val.indexOf('.') > -1 || val.indexOf('e') > -1
|
||||
|| val.indexOf('E') > -1 || "-0".equals(val);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method tries to convert the given string value to the target object
|
||||
@@ -537,7 +609,8 @@ public class XML {
|
||||
* produced, then the value will just be a string.
|
||||
*/
|
||||
|
||||
if (potentialNumber(string)) {
|
||||
char initial = string.charAt(0);
|
||||
if ((initial >= '0' && initial <= '9') || initial == '-') {
|
||||
try {
|
||||
return stringToNumber(string);
|
||||
} catch (Exception ignore) {
|
||||
@@ -546,11 +619,6 @@ public class XML {
|
||||
return string;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Convert a well-formed (but not necessarily valid) XML string into a
|
||||
* JSONObject. Some information may be lost in this transformation because
|
||||
@@ -969,5 +1037,4 @@ public class XML {
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user