Skip to content

Commit 495cec9

Browse files
authored
Merge pull request #783 from rudrajyotib/master
optLong vs getLong inconsistencies
2 parents c4cd526 + 56cb5f8 commit 495cec9

File tree

5 files changed

+292
-20
lines changed

5 files changed

+292
-20
lines changed

src/main/java/org/json/JSONObject.java

Lines changed: 60 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2385,14 +2385,21 @@ protected static boolean isDecimalNotation(final String val) {
23852385
* returns for this function are BigDecimal, Double, BigInteger, Long, and Integer.
23862386
* When a Double is returned, it should always be a valid Double and not NaN or +-infinity.
23872387
*
2388-
* @param val value to convert
2388+
* @param input value to convert
23892389
* @return Number representation of the value.
23902390
* @throws NumberFormatException thrown if the value is not a valid number. A public
23912391
* caller should catch this and wrap it in a {@link JSONException} if applicable.
23922392
*/
2393-
protected static Number stringToNumber(final String val) throws NumberFormatException {
2393+
protected static Number stringToNumber(final String input) throws NumberFormatException {
2394+
String val = input;
2395+
if (val.startsWith(".")){
2396+
val = "0"+val;
2397+
}
2398+
if (val.startsWith("-.")){
2399+
val = "-0."+val.substring(2);
2400+
}
23942401
char initial = val.charAt(0);
2395-
if ((initial >= '0' && initial <= '9') || initial == '-') {
2402+
if ((initial >= '0' && initial <= '9') || initial == '-' ) {
23962403
// decimal representation
23972404
if (isDecimalNotation(val)) {
23982405
// Use a BigDecimal all the time so we keep the original
@@ -2409,25 +2416,26 @@ protected static Number stringToNumber(final String val) throws NumberFormatExce
24092416
try {
24102417
Double d = Double.valueOf(val);
24112418
if(d.isNaN() || d.isInfinite()) {
2412-
throw new NumberFormatException("val ["+val+"] is not a valid number.");
2419+
throw new NumberFormatException("val ["+input+"] is not a valid number.");
24132420
}
24142421
return d;
24152422
} catch (NumberFormatException ignore) {
2416-
throw new NumberFormatException("val ["+val+"] is not a valid number.");
2423+
throw new NumberFormatException("val ["+input+"] is not a valid number.");
24172424
}
24182425
}
24192426
}
2420-
// block items like 00 01 etc. Java number parsers treat these as Octal.
2427+
val = removeLeadingZerosOfNumber(input);
2428+
initial = val.charAt(0);
24212429
if(initial == '0' && val.length() > 1) {
24222430
char at1 = val.charAt(1);
24232431
if(at1 >= '0' && at1 <= '9') {
2424-
throw new NumberFormatException("val ["+val+"] is not a valid number.");
2432+
throw new NumberFormatException("val ["+input+"] is not a valid number.");
24252433
}
24262434
} else if (initial == '-' && val.length() > 2) {
24272435
char at1 = val.charAt(1);
24282436
char at2 = val.charAt(2);
24292437
if(at1 == '0' && at2 >= '0' && at2 <= '9') {
2430-
throw new NumberFormatException("val ["+val+"] is not a valid number.");
2438+
throw new NumberFormatException("val ["+input+"] is not a valid number.");
24312439
}
24322440
}
24332441
// integer representation.
@@ -2447,7 +2455,7 @@ protected static Number stringToNumber(final String val) throws NumberFormatExce
24472455
}
24482456
return bi;
24492457
}
2450-
throw new NumberFormatException("val ["+val+"] is not a valid number.");
2458+
throw new NumberFormatException("val ["+input+"] is not a valid number.");
24512459
}
24522460

24532461
/**
@@ -2483,8 +2491,7 @@ public static Object stringToValue(String string) {
24832491
* produced, then the value will just be a string.
24842492
*/
24852493

2486-
char initial = string.charAt(0);
2487-
if ((initial >= '0' && initial <= '9') || initial == '-') {
2494+
if (potentialNumber(string)) {
24882495
try {
24892496
return stringToNumber(string);
24902497
} catch (Exception ignore) {
@@ -2493,6 +2500,28 @@ public static Object stringToValue(String string) {
24932500
return string;
24942501
}
24952502

2503+
2504+
private static boolean potentialNumber(String value){
2505+
if (value == null || value.isEmpty()){
2506+
return false;
2507+
}
2508+
return potentialPositiveNumberStartingAtIndex(value, (value.charAt(0)=='-'?1:0));
2509+
}
2510+
2511+
private static boolean potentialPositiveNumberStartingAtIndex(String value,int index){
2512+
if (index >= value.length()){
2513+
return false;
2514+
}
2515+
return digitAtIndex(value, (value.charAt(index)=='.'?index+1:index));
2516+
}
2517+
2518+
private static boolean digitAtIndex(String value, int index){
2519+
if (index >= value.length()){
2520+
return false;
2521+
}
2522+
return value.charAt(index) >= '0' && value.charAt(index) <= '9';
2523+
}
2524+
24962525
/**
24972526
* Throw an exception if the object is a NaN or infinite number.
24982527
*
@@ -2892,4 +2921,24 @@ private static JSONException recursivelyDefinedObjectException(String key) {
28922921
"JavaBean object contains recursively defined member variable of key " + quote(key)
28932922
);
28942923
}
2924+
2925+
/**
2926+
* For a prospective number, remove the leading zeros
2927+
* @param value prospective number
2928+
* @return number without leading zeros
2929+
*/
2930+
private static String removeLeadingZerosOfNumber(String value){
2931+
if (value.equals("-")){return value;}
2932+
boolean negativeFirstChar = (value.charAt(0) == '-');
2933+
int counter = negativeFirstChar ? 1:0;
2934+
while (counter < value.length()){
2935+
if (value.charAt(counter) != '0'){
2936+
if (negativeFirstChar) {return "-".concat(value.substring(counter));}
2937+
return value.substring(counter);
2938+
}
2939+
++counter;
2940+
}
2941+
if (negativeFirstChar) {return "-0";}
2942+
return "0";
2943+
}
28952944
}
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
package org.json.junit;
2+
3+
import org.json.JSONObject;
4+
import org.junit.Test;
5+
6+
import java.math.BigDecimal;
7+
import java.math.BigInteger;
8+
9+
import static org.junit.Assert.assertEquals;
10+
11+
public class JSONObjectDecimalTest {
12+
13+
@Test
14+
public void shouldParseDecimalNumberThatStartsWithDecimalPoint(){
15+
JSONObject jsonObject = new JSONObject("{value:0.50}");
16+
assertEquals("Float not recognized", 0.5f, jsonObject.getFloat("value"), 0.0f);
17+
assertEquals("Float not recognized", 0.5f, jsonObject.optFloat("value"), 0.0f);
18+
assertEquals("Float not recognized", 0.5f, jsonObject.optFloatObject("value"), 0.0f);
19+
assertEquals("Double not recognized", 0.5d, jsonObject.optDouble("value"), 0.0f);
20+
assertEquals("Double not recognized", 0.5d, jsonObject.optDoubleObject("value"), 0.0f);
21+
assertEquals("Double not recognized", 0.5d, jsonObject.getDouble("value"), 0.0f);
22+
assertEquals("Long not recognized", 0, jsonObject.optLong("value"), 0);
23+
assertEquals("Long not recognized", 0, jsonObject.getLong("value"), 0);
24+
assertEquals("Long not recognized", 0, jsonObject.optLongObject("value"), 0);
25+
assertEquals("Integer not recognized", 0, jsonObject.optInt("value"), 0);
26+
assertEquals("Integer not recognized", 0, jsonObject.getInt("value"), 0);
27+
assertEquals("Integer not recognized", 0, jsonObject.optIntegerObject("value"), 0);
28+
assertEquals("Number not recognized", 0, jsonObject.getNumber("value").intValue(), 0);
29+
assertEquals("Number not recognized", 0, jsonObject.getNumber("value").longValue(), 0);
30+
assertEquals("BigDecimal not recognized", 0, BigDecimal.valueOf(.5).compareTo(jsonObject.getBigDecimal("value")));
31+
assertEquals("BigInteger not recognized",0, BigInteger.valueOf(0).compareTo(jsonObject.getBigInteger("value")));
32+
}
33+
34+
35+
36+
@Test
37+
public void shouldParseNegativeDecimalNumberThatStartsWithDecimalPoint(){
38+
JSONObject jsonObject = new JSONObject("{value:-.50}");
39+
assertEquals("Float not recognized", -0.5f, jsonObject.getFloat("value"), 0.0f);
40+
assertEquals("Float not recognized", -0.5f, jsonObject.optFloat("value"), 0.0f);
41+
assertEquals("Float not recognized", -0.5f, jsonObject.optFloatObject("value"), 0.0f);
42+
assertEquals("Double not recognized", -0.5d, jsonObject.optDouble("value"), 0.0f);
43+
assertEquals("Double not recognized", -0.5d, jsonObject.optDoubleObject("value"), 0.0f);
44+
assertEquals("Double not recognized", -0.5d, jsonObject.getDouble("value"), 0.0f);
45+
assertEquals("Long not recognized", 0, jsonObject.optLong("value"), 0);
46+
assertEquals("Long not recognized", 0, jsonObject.getLong("value"), 0);
47+
assertEquals("Long not recognized", 0, jsonObject.optLongObject("value"), 0);
48+
assertEquals("Integer not recognized", 0, jsonObject.optInt("value"), 0);
49+
assertEquals("Integer not recognized", 0, jsonObject.getInt("value"), 0);
50+
assertEquals("Integer not recognized", 0, jsonObject.optIntegerObject("value"), 0);
51+
assertEquals("Number not recognized", 0, jsonObject.getNumber("value").intValue(), 0);
52+
assertEquals("Number not recognized", 0, jsonObject.getNumber("value").longValue(), 0);
53+
assertEquals("BigDecimal not recognized", 0, BigDecimal.valueOf(-.5).compareTo(jsonObject.getBigDecimal("value")));
54+
assertEquals("BigInteger not recognized",0, BigInteger.valueOf(0).compareTo(jsonObject.getBigInteger("value")));
55+
}
56+
57+
@Test
58+
public void shouldParseDecimalNumberThatHasZeroBeforeWithDecimalPoint(){
59+
JSONObject jsonObject = new JSONObject("{value:00.050}");
60+
assertEquals("Float not recognized", 0.05f, jsonObject.getFloat("value"), 0.0f);
61+
assertEquals("Float not recognized", 0.05f, jsonObject.optFloat("value"), 0.0f);
62+
assertEquals("Float not recognized", 0.05f, jsonObject.optFloatObject("value"), 0.0f);
63+
assertEquals("Double not recognized", 0.05d, jsonObject.optDouble("value"), 0.0f);
64+
assertEquals("Double not recognized", 0.05d, jsonObject.optDoubleObject("value"), 0.0f);
65+
assertEquals("Double not recognized", 0.05d, jsonObject.getDouble("value"), 0.0f);
66+
assertEquals("Long not recognized", 0, jsonObject.optLong("value"), 0);
67+
assertEquals("Long not recognized", 0, jsonObject.getLong("value"), 0);
68+
assertEquals("Long not recognized", 0, jsonObject.optLongObject("value"), 0);
69+
assertEquals("Integer not recognized", 0, jsonObject.optInt("value"), 0);
70+
assertEquals("Integer not recognized", 0, jsonObject.getInt("value"), 0);
71+
assertEquals("Integer not recognized", 0, jsonObject.optIntegerObject("value"), 0);
72+
assertEquals("Number not recognized", 0, jsonObject.getNumber("value").intValue(), 0);
73+
assertEquals("Number not recognized", 0, jsonObject.getNumber("value").longValue(), 0);
74+
assertEquals("BigDecimal not recognized", 0, BigDecimal.valueOf(.05).compareTo(jsonObject.getBigDecimal("value")));
75+
assertEquals("BigInteger not recognized",0, BigInteger.valueOf(0).compareTo(jsonObject.getBigInteger("value")));
76+
}
77+
78+
@Test
79+
public void shouldParseNegativeDecimalNumberThatHasZeroBeforeWithDecimalPoint(){
80+
JSONObject jsonObject = new JSONObject("{value:-00.050}");
81+
assertEquals("Float not recognized", -0.05f, jsonObject.getFloat("value"), 0.0f);
82+
assertEquals("Float not recognized", -0.05f, jsonObject.optFloat("value"), 0.0f);
83+
assertEquals("Float not recognized", -0.05f, jsonObject.optFloatObject("value"), 0.0f);
84+
assertEquals("Double not recognized", -0.05d, jsonObject.optDouble("value"), 0.0f);
85+
assertEquals("Double not recognized", -0.05d, jsonObject.optDoubleObject("value"), 0.0f);
86+
assertEquals("Double not recognized", -0.05d, jsonObject.getDouble("value"), 0.0f);
87+
assertEquals("Long not recognized", 0, jsonObject.optLong("value"), 0);
88+
assertEquals("Long not recognized", 0, jsonObject.getLong("value"), 0);
89+
assertEquals("Long not recognized", 0, jsonObject.optLongObject("value"), 0);
90+
assertEquals("Integer not recognized", 0, jsonObject.optInt("value"), 0);
91+
assertEquals("Integer not recognized", 0, jsonObject.getInt("value"), 0);
92+
assertEquals("Integer not recognized", 0, jsonObject.optIntegerObject("value"), 0);
93+
assertEquals("Number not recognized", 0, jsonObject.getNumber("value").intValue(), 0);
94+
assertEquals("Number not recognized", 0, jsonObject.getNumber("value").longValue(), 0);
95+
assertEquals("BigDecimal not recognized", 0, BigDecimal.valueOf(-.05).compareTo(jsonObject.getBigDecimal("value")));
96+
assertEquals("BigInteger not recognized",0, BigInteger.valueOf(0).compareTo(jsonObject.getBigInteger("value")));
97+
}
98+
99+
100+
}

src/test/java/org/json/junit/JSONObjectNumberTest.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,10 @@ public class JSONObjectNumberTest {
2323
@Parameters(name = "{index}: {0}")
2424
public static Collection<Object[]> data() {
2525
return Arrays.asList(new Object[][]{
26-
{"{value:50}", 1},
26+
{"{value:0050}", 1},
27+
{"{value:0050.0000}", 1},
28+
{"{value:-0050}", -1},
29+
{"{value:-0050.0000}", -1},
2730
{"{value:50.0}", 1},
2831
{"{value:5e1}", 1},
2932
{"{value:5E1}", 1},
@@ -32,6 +35,7 @@ public static Collection<Object[]> data() {
3235
{"{value:-50}", -1},
3336
{"{value:-50.0}", -1},
3437
{"{value:-5e1}", -1},
38+
{"{value:-0005e1}", -1},
3539
{"{value:-5E1}", -1},
3640
{"{value:-5e1}", -1},
3741
{"{value:'-50'}", -1}

0 commit comments

Comments
 (0)