#653 - optLong vs getLong inconsistencies

For exponential decimal conversion, number is not touched.
Leading zeros removed from numeric number strings before converting to number.
This commit is contained in:
rudrajyoti biswas 2023-10-06 21:34:00 +05:30
parent 79af389f7a
commit 1a38879c90
3 changed files with 73 additions and 4 deletions

View File

@ -2379,12 +2379,13 @@ public class JSONObject {
* returns for this function are BigDecimal, Double, BigInteger, Long, and Integer. * 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. * When a Double is returned, it should always be a valid Double and not NaN or +-infinity.
* *
* @param val value to convert * @param input value to convert
* @return Number representation of the value. * @return Number representation of the value.
* @throws NumberFormatException thrown if the value is not a valid number. A public * @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. * caller should catch this and wrap it in a {@link JSONException} if applicable.
*/ */
protected static Number stringToNumber(final String val) throws NumberFormatException { protected static Number stringToNumber(final String input) throws NumberFormatException {
String val = input;
char initial = val.charAt(0); char initial = val.charAt(0);
if ((initial >= '0' && initial <= '9') || initial == '-') { if ((initial >= '0' && initial <= '9') || initial == '-') {
// decimal representation // decimal representation
@ -2411,6 +2412,8 @@ public class JSONObject {
} }
} }
} }
val = removeLeadingZerosOfNumber(input);
initial = val.charAt(0);
// block items like 00 01 etc. Java number parsers treat these as Octal. // block items like 00 01 etc. Java number parsers treat these as Octal.
if(initial == '0' && val.length() > 1) { if(initial == '0' && val.length() > 1) {
char at1 = val.charAt(1); char at1 = val.charAt(1);
@ -2886,4 +2889,33 @@ public class JSONObject {
"JavaBean object contains recursively defined member variable of key " + quote(key) "JavaBean object contains recursively defined member variable of key " + quote(key)
); );
} }
/**
* For a prospective number, remove the leading zeros
* @param value prospective number
* @return number without leading zeros
*/
private static String removeLeadingZerosOfNumber(String value){
char[] chars = value.toCharArray();
int leftMostUnsignedIndex = 0;
if (chars[0] == '-'){
leftMostUnsignedIndex = 1;
}
int firstNonZeroCharIndex = -1;
for (int i=leftMostUnsignedIndex;i<value.length();i++){
if (chars[i] != '0'){
firstNonZeroCharIndex = i;
break;
}
}
if (firstNonZeroCharIndex == -1){
return value;
}
StringBuilder result = new StringBuilder();
if (leftMostUnsignedIndex == 1){
result.append('-');
}
result.append(value.substring(firstNonZeroCharIndex));
return result.toString();
}
} }

View File

@ -23,7 +23,10 @@ public class JSONObjectNumberTest {
@Parameters(name = "{index}: {0}") @Parameters(name = "{index}: {0}")
public static Collection<Object[]> data() { public static Collection<Object[]> data() {
return Arrays.asList(new Object[][]{ return Arrays.asList(new Object[][]{
{"{value:50}", 1}, {"{value:0050}", 1},
{"{value:0050.0000}", 1},
{"{value:-0050}", -1},
{"{value:-0050.0000}", -1},
{"{value:50.0}", 1}, {"{value:50.0}", 1},
{"{value:5e1}", 1}, {"{value:5e1}", 1},
{"{value:5E1}", 1}, {"{value:5E1}", 1},
@ -32,6 +35,7 @@ public class JSONObjectNumberTest {
{"{value:-50}", -1}, {"{value:-50}", -1},
{"{value:-50.0}", -1}, {"{value:-50.0}", -1},
{"{value:-5e1}", -1}, {"{value:-5e1}", -1},
{"{value:-0005e1}", -1},
{"{value:-5E1}", -1}, {"{value:-5E1}", -1},
{"{value:-5e1}", -1}, {"{value:-5e1}", -1},
{"{value:'-50'}", -1} {"{value:'-50'}", -1}

View File

@ -1063,12 +1063,16 @@ public class JSONObjectTest {
"\"tooManyZeros\":00,"+ "\"tooManyZeros\":00,"+
"\"negativeInfinite\":-Infinity,"+ "\"negativeInfinite\":-Infinity,"+
"\"negativeNaN\":-NaN,"+ "\"negativeNaN\":-NaN,"+
"\"negativeNaNWithLeadingZeros\":-00NaN,"+
"\"negativeFraction\":-.01,"+ "\"negativeFraction\":-.01,"+
"\"tooManyZerosFraction\":00.001,"+ "\"tooManyZerosFraction\":00.001,"+
"\"negativeHexFloat\":-0x1.fffp1,"+ "\"negativeHexFloat\":-0x1.fffp1,"+
"\"hexFloat\":0x1.0P-1074,"+ "\"hexFloat\":0x1.0P-1074,"+
"\"floatIdentifier\":0.1f,"+ "\"floatIdentifier\":0.1f,"+
"\"doubleIdentifier\":0.1d"+ "\"doubleIdentifier\":0.1d,"+
"\"integerWithLeadingZeros\":000900,"+
"\"integerWithAllZeros\":00000,"+
"\"compositeWithLeadingZeros\":00800.90d"+
"}"; "}";
JSONObject jsonObject = new JSONObject(str); JSONObject jsonObject = new JSONObject(str);
Object obj; Object obj;
@ -1085,10 +1089,17 @@ public class JSONObjectTest {
obj = jsonObject.get("negativeNaN"); obj = jsonObject.get("negativeNaN");
assertTrue( "negativeNaN currently evaluates to string", assertTrue( "negativeNaN currently evaluates to string",
obj.equals("-NaN")); obj.equals("-NaN"));
obj = jsonObject.get("negativeNaNWithLeadingZeros");
assertTrue( "negativeNaNWithLeadingZeros currently evaluates to string",
obj.equals("-00NaN"));
assertTrue( "negativeFraction currently evaluates to double -0.01", assertTrue( "negativeFraction currently evaluates to double -0.01",
jsonObject.get( "negativeFraction" ).equals(BigDecimal.valueOf(-0.01))); jsonObject.get( "negativeFraction" ).equals(BigDecimal.valueOf(-0.01)));
assertTrue( "tooManyZerosFraction currently evaluates to double 0.001", assertTrue( "tooManyZerosFraction currently evaluates to double 0.001",
jsonObject.get( "tooManyZerosFraction" ).equals(BigDecimal.valueOf(0.001))); jsonObject.get( "tooManyZerosFraction" ).equals(BigDecimal.valueOf(0.001)));
assertTrue( "tooManyZerosFraction currently evaluates to double 0.001",
jsonObject.getLong( "tooManyZerosFraction" )==0);
assertTrue( "tooManyZerosFraction currently evaluates to double 0.001",
jsonObject.optLong( "tooManyZerosFraction" )==0);
assertTrue( "negativeHexFloat currently evaluates to double -3.99951171875", assertTrue( "negativeHexFloat currently evaluates to double -3.99951171875",
jsonObject.get( "negativeHexFloat" ).equals(Double.valueOf(-3.99951171875))); jsonObject.get( "negativeHexFloat" ).equals(Double.valueOf(-3.99951171875)));
assertTrue("hexFloat currently evaluates to double 4.9E-324", assertTrue("hexFloat currently evaluates to double 4.9E-324",
@ -1097,6 +1108,28 @@ public class JSONObjectTest {
jsonObject.get("floatIdentifier").equals(Double.valueOf(0.1))); jsonObject.get("floatIdentifier").equals(Double.valueOf(0.1)));
assertTrue("doubleIdentifier currently evaluates to double 0.1", assertTrue("doubleIdentifier currently evaluates to double 0.1",
jsonObject.get("doubleIdentifier").equals(Double.valueOf(0.1))); jsonObject.get("doubleIdentifier").equals(Double.valueOf(0.1)));
assertTrue("Integer does not evaluate to 900",
jsonObject.get("integerWithLeadingZeros").equals(900));
assertTrue("Integer does not evaluate to 900",
jsonObject.getInt("integerWithLeadingZeros")==900);
assertTrue("Integer does not evaluate to 900",
jsonObject.optInt("integerWithLeadingZeros")==900);
assertTrue("Integer does not evaluate to 0",
jsonObject.get("integerWithAllZeros").equals("00000"));
assertTrue("Integer does not evaluate to 0",
jsonObject.getInt("integerWithAllZeros")==0);
assertTrue("Integer does not evaluate to 0",
jsonObject.optInt("integerWithAllZeros")==0);
assertTrue("Double does not evaluate to 800.90",
jsonObject.get("compositeWithLeadingZeros").equals(800.90));
assertTrue("Double does not evaluate to 800.90",
jsonObject.getDouble("compositeWithLeadingZeros")==800.9d);
assertTrue("Integer does not evaluate to 800",
jsonObject.optInt("compositeWithLeadingZeros")==800);
assertTrue("Long does not evaluate to 800.90",
jsonObject.getLong("compositeWithLeadingZeros")==800);
assertTrue("Long does not evaluate to 800.90",
jsonObject.optLong("compositeWithLeadingZeros")==800);
Util.checkJSONObjectMaps(jsonObject); Util.checkJSONObjectMaps(jsonObject);
} }