1
0
Fork 0
mirror of https://github.com/ethauvin/JSON-java.git synced 2025-06-17 07:50:52 -07:00

updates the getNumber/optNumber to not return invalid Doubles

This commit is contained in:
John J. Aylward 2017-05-18 19:49:50 -04:00
parent a7f8ff24df
commit 849b392c01
2 changed files with 54 additions and 30 deletions

View file

@ -738,7 +738,11 @@ public class JSONArray implements Iterable<Object> {
return BigInteger.valueOf(((Number) val).longValue());
}
try {
return new BigDecimal(val.toString()).toBigInteger();
final String valStr = val.toString();
if(JSONObject.isDecimalNotation(valStr)) {
return new BigDecimal(valStr).toBigInteger();
}
return new BigInteger(valStr);
} catch (Exception e) {
return defaultValue;
}

View file

@ -1068,7 +1068,11 @@ public class JSONObject {
// jo.optInt("double"); -- will return 1, not an error
// this conversion to BigDecimal then to BigInteger is to maintain
// that type cast support that may truncate the decimal.
return new BigDecimal(val.toString()).toBigInteger();
final String valStr = val.toString();
if(isDecimalNotation(valStr)) {
return new BigDecimal(valStr).toBigInteger();
}
return new BigInteger(valStr);
} catch (Exception e) {
return defaultValue;
}
@ -1759,12 +1763,22 @@ public class JSONObject {
return false;
}
}
/**
* 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.
*/
protected static boolean isDecimalNotation(final String val) {
return val.indexOf('.') > -1 || val.indexOf('e') > -1
|| val.indexOf('E') > -1 || "-0".equals(val);
}
/**
* Converts a string to a number using the narrowest possible type. Possible
* returns for this function are BigDecimal, Double, BigInteger, Long, and Integer.
*
* An Exception is thrown if
* 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.
@ -1775,46 +1789,52 @@ public class JSONObject {
char initial = val.charAt(0);
if ((initial >= '0' && initial <= '9') || initial == '-') {
// decimal representation
if (val.indexOf('.') > -1 || val.indexOf('e') > -1
|| val.indexOf('E') > -1
|| "-0".equals(val)) {
if (isDecimalNotation(val)) {
// quick dirty way to see if we need a BigDecimal instead of a Double
// this only handles some cases of overflow or underflow
if (val.length()>14) {
return new BigDecimal(val);
}
return Double.valueOf(val);
final Double d = Double.valueOf(val);
if (d.isInfinite() || d.isNaN()) {
// if we can't parse it as a double, go up to BigDecimal
// this is probably due to underflow like 4.32e-678
// or overflow like 4.65e5324. The size of the string is small
// but can't be held in a Double.
return new BigDecimal(val);
}
return d;
}
// integer representation.
// This will narrow any values to the smallest reasonable Object representation
// (Integer, Long, or BigInteger)
// string version
// The compare string length method reduces GC,
// but leads to smaller integers being placed in larger wrappers even though not
// needed. i.e. 1,000,000,000 -> Long even though it's an Integer
// 1,000,000,000,000,000,000 -> BigInteger even though it's a Long
// string version
if(val.length()<=9){
return Integer.valueOf(val);
}
if(val.length()<=18){
return Long.valueOf(val);
}
return new BigInteger(val);
//if(val.length()<=9){
// return Integer.valueOf(val);
//}
//if(val.length()<=18){
// return Long.valueOf(val);
//}
//return new BigInteger(val);
// BigInteger version: We use a similar bitLenth 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. Which is the better tradeoff? This is closer to what's
// in stringToValue.
//BigInteger bi = new BigInteger((String)val);
//if(bi.bitLength()<=31){
// return Integer.valueOf(bi.intValue());
//}
//if(bi.bitLength()<=63){
// return Long.valueOf(bi.longValue());
//}
//return bi;
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.");
}
@ -1849,9 +1869,9 @@ public class JSONObject {
char initial = string.charAt(0);
if ((initial >= '0' && initial <= '9') || initial == '-') {
try {
if (string.indexOf('.') > -1 || string.indexOf('e') > -1
|| string.indexOf('E') > -1
|| "-0".equals(string)) {
// if we want full Big Number support this block can be replaced with:
// return stringToNumber(string);
if (isDecimalNotation(string)) {
Double d = Double.valueOf(string);
if (!d.isInfinite() && !d.isNaN()) {
return d;