From 1a38879c9099078a1cc63a80312da318235ad0f6 Mon Sep 17 00:00:00 2001 From: rudrajyoti biswas Date: Fri, 6 Oct 2023 21:34:00 +0530 Subject: [PATCH] #653 - optLong vs getLong inconsistencies For exponential decimal conversion, number is not touched. Leading zeros removed from numeric number strings before converting to number. --- src/main/java/org/json/JSONObject.java | 36 +++++++++++++++++-- .../org/json/junit/JSONObjectNumberTest.java | 6 +++- .../java/org/json/junit/JSONObjectTest.java | 35 +++++++++++++++++- 3 files changed, 73 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/json/JSONObject.java b/src/main/java/org/json/JSONObject.java index acef67d9f..5eb332225 100644 --- a/src/main/java/org/json/JSONObject.java +++ b/src/main/java/org/json/JSONObject.java @@ -2379,12 +2379,13 @@ protected static boolean isDecimalNotation(final String val) { * 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 + * @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. */ - 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); if ((initial >= '0' && initial <= '9') || initial == '-') { // decimal representation @@ -2411,6 +2412,8 @@ protected static Number stringToNumber(final String val) throws NumberFormatExce } } } + val = removeLeadingZerosOfNumber(input); + initial = val.charAt(0); // block items like 00 01 etc. Java number parsers treat these as Octal. if(initial == '0' && val.length() > 1) { char at1 = val.charAt(1); @@ -2886,4 +2889,33 @@ private static JSONException recursivelyDefinedObjectException(String 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 data() { 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:5e1}", 1}, {"{value:5E1}", 1}, @@ -32,6 +35,7 @@ public static Collection data() { {"{value:-50}", -1}, {"{value:-50.0}", -1}, {"{value:-5e1}", -1}, + {"{value:-0005e1}", -1}, {"{value:-5E1}", -1}, {"{value:-5e1}", -1}, {"{value:'-50'}", -1} diff --git a/src/test/java/org/json/junit/JSONObjectTest.java b/src/test/java/org/json/junit/JSONObjectTest.java index 01889d54b..b63552141 100644 --- a/src/test/java/org/json/junit/JSONObjectTest.java +++ b/src/test/java/org/json/junit/JSONObjectTest.java @@ -1063,12 +1063,16 @@ public void jsonInvalidNumberValues() { "\"tooManyZeros\":00,"+ "\"negativeInfinite\":-Infinity,"+ "\"negativeNaN\":-NaN,"+ + "\"negativeNaNWithLeadingZeros\":-00NaN,"+ "\"negativeFraction\":-.01,"+ "\"tooManyZerosFraction\":00.001,"+ "\"negativeHexFloat\":-0x1.fffp1,"+ "\"hexFloat\":0x1.0P-1074,"+ "\"floatIdentifier\":0.1f,"+ - "\"doubleIdentifier\":0.1d"+ + "\"doubleIdentifier\":0.1d,"+ + "\"integerWithLeadingZeros\":000900,"+ + "\"integerWithAllZeros\":00000,"+ + "\"compositeWithLeadingZeros\":00800.90d"+ "}"; JSONObject jsonObject = new JSONObject(str); Object obj; @@ -1085,10 +1089,17 @@ public void jsonInvalidNumberValues() { obj = jsonObject.get("negativeNaN"); assertTrue( "negativeNaN currently evaluates to string", obj.equals("-NaN")); + obj = jsonObject.get("negativeNaNWithLeadingZeros"); + assertTrue( "negativeNaNWithLeadingZeros currently evaluates to string", + obj.equals("-00NaN")); assertTrue( "negativeFraction currently evaluates to double -0.01", jsonObject.get( "negativeFraction" ).equals(BigDecimal.valueOf(-0.01))); assertTrue( "tooManyZerosFraction currently evaluates to double 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", jsonObject.get( "negativeHexFloat" ).equals(Double.valueOf(-3.99951171875))); assertTrue("hexFloat currently evaluates to double 4.9E-324", @@ -1097,6 +1108,28 @@ public void jsonInvalidNumberValues() { jsonObject.get("floatIdentifier").equals(Double.valueOf(0.1))); assertTrue("doubleIdentifier currently evaluates to double 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); }