Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed opt/get Int/Long/Double inconsistencies #661

Closed
wants to merge 7 commits into from
65 changes: 23 additions & 42 deletions src/main/java/org/json/JSONObject.java
Original file line number Diff line number Diff line change
Expand Up @@ -2223,61 +2223,42 @@ protected static boolean isDecimalNotation(final String val) {
* 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 == '-') {
String trimmedVal = val.trim();
char initial = trimmedVal.charAt(0);
if (trimmedVal.matches("-?\\d?(\\.\\d+)?")) {
// decimal representation
if (isDecimalNotation(val)) {
if (isDecimalNotation(trimmedVal)) {
// 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);
BigDecimal bd = new BigDecimal(trimmedVal);
if(initial == '-' && BigDecimal.ZERO.compareTo(bd)==0) {
return Double.valueOf(-0.0);
return -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.");
} else {
// 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(trimmedVal);
if(bi.bitLength() <= 31){
return bi.intValue();
}
if(bi.bitLength() <= 63){
return bi.longValue();
}
return bi;
}
// 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.");
}
Expand Down
104 changes: 104 additions & 0 deletions src/test/java/org/json/junit/JSONStringTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ of this software and associated documentation files (the "Software"), to deal
import static org.junit.Assert.*;

import java.io.StringWriter;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;

import org.json.*;
Expand Down Expand Up @@ -339,6 +341,108 @@ public void testNullStringValue() throws Exception {
}
}

/**
* Test for parsing long numerals from String format
*
*/

@Test
public void testStringLongValue() throws Exception {
JSONObject json = new JSONObject("{\"num1\":\"01234\", \"num2\": \"332211\", \"num3\":\"0987\"}");

assertEquals(1234L, json.getLong("num1"));
assertEquals(1234L, json.optLong("num1"));
assertEquals(332211L, json.getLong("num2"));
assertEquals(332211L, json.optLong("num2"));
assertEquals(987, json.getLong("num3"));
assertEquals(987, json.optLong("num3"));
}


/**
* Test for parsing int numerals from String format
*
*/

@Test
public void testStringIntValue() throws Exception {
JSONObject json = new JSONObject("{\"num1\":\"01234\", \"num2\": \"332211\", \"num3\":\"0987\"}");

assertEquals(1234, json.getInt("num1"));
assertEquals(1234, json.optInt("num1"));
assertEquals(332211, json.getInt("num2"));
assertEquals(332211, json.optInt("num2"));
assertEquals(987, json.getInt("num3"));
assertEquals(987, json.optInt("num3"));
}

/**
* Test for parsing double numerals from String format
*
*/

@Test
public void testStringDoubleValue() throws Exception {
JSONObject json = new JSONObject("{\"num1\":\".123\", \"num2\": \"0.123\", \"num3\":\"8.123\"}");

assertEquals(.123, json.getDouble("num1"), 0);
assertEquals(.123, json.optDouble("num1"), 0);
assertEquals(0.123, json.getDouble("num2"), 0);
assertEquals(0.123, json.optDouble("num2"), 0);
assertEquals(8.123, json.getDouble("num3"), 0);
assertEquals(8.123, json.optDouble("num3"), 0);
}

/**
* Test for parsing float numerals from String format
*/

@Test
public void testStringFloatValue() throws Exception {
JSONObject json = new JSONObject("{\"num1\":\".123\", \"num2\": \"0.123\", \"num3\":\"8.123\"}");

assertEquals(.123, json.getFloat("num1"), 0.000001);
assertEquals(.123, json.optFloat("num1"), 0.000001);
assertEquals(0.123, json.getFloat("num2"), 0.000001);
assertEquals(0.123, json.optFloat("num2"), 0.000001);
assertEquals(8.123, json.getFloat("num3"), 0.000001);
assertEquals(8.123, json.optFloat("num3"), 0.000001);
}


/**
* Test for parsing BigDecimal numerals from String format
*
*/

@Test
public void testStringBigDecimalValue() throws Exception {
JSONObject json = new JSONObject("{\"num1\":\".123\", \"num2\": \"0.123\", \"num3\":\"8.123\"}");

assertEquals(new BigDecimal(".123"), json.getBigDecimal("num1"));
assertEquals(new BigDecimal(".123"), json.optBigDecimal("num1", BigDecimal.ONE));
assertEquals(new BigDecimal("0.123"), json.getBigDecimal("num2"));
assertEquals(new BigDecimal("0.123"), json.optBigDecimal("num2", BigDecimal.ONE));
assertEquals(new BigDecimal("8.123"), json.getBigDecimal("num3"));
assertEquals(new BigDecimal("8.123"), json.optBigDecimal("num3", BigDecimal.ONE));
}

/**
* Test for parsing BigInteger numerals from String format
*/

@Test
public void testStringBigIntegerValue() throws Exception {
JSONObject json = new JSONObject("{\"num1\":\"01234\", \"num2\": \"332211\", \"num3\":\"0987\"}");

assertEquals(BigInteger.valueOf(1234), json.getBigInteger("num1"));
assertEquals(BigInteger.valueOf(1234), json.getBigInteger("num1"));
assertEquals(BigInteger.valueOf(332211), json.getBigInteger("num2"));
assertEquals(BigInteger.valueOf(332211), json.getBigInteger("num2"));
assertEquals(BigInteger.valueOf(987), json.getBigInteger("num3"));
assertEquals(BigInteger.valueOf(987), json.getBigInteger("num3"));
}

/**
* A JSONString that returns a valid JSON string value.
*/
Expand Down