Merge pull request #869 from stleary/revert-recent-objLong-getLong-changes

Revert recent obj long get long changes
This commit is contained in:
Sean Leary 2024-02-28 09:52:04 -06:00 committed by GitHub
commit 3f97826462
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 241 additions and 580 deletions

View File

@ -360,7 +360,7 @@ public class JSONArray implements Iterable<Object> {
if (object instanceof Number) {
return (Number)object;
}
return NumberConversionUtil.stringToNumber(object.toString());
return JSONObject.stringToNumber(object.toString());
} catch (Exception e) {
throw wrongValueFormatException(index, "number", object, e);
}
@ -1107,7 +1107,7 @@ public class JSONArray implements Iterable<Object> {
if (val instanceof String) {
try {
return NumberConversionUtil.stringToNumber((String) val);
return JSONObject.stringToNumber((String) val);
} catch (Exception e) {
return defaultValue;
}

View File

@ -28,9 +28,6 @@ import java.util.ResourceBundle;
import java.util.Set;
import java.util.regex.Pattern;
import static org.json.NumberConversionUtil.potentialNumber;
import static org.json.NumberConversionUtil.stringToNumber;
/**
* A JSONObject is an unordered collection of name/value pairs. Its external
* form is a string wrapped in curly braces with colons between the names and
@ -2460,7 +2457,8 @@ public class JSONObject {
* produced, then the value will just be a string.
*/
if (potentialNumber(string)) {
char initial = string.charAt(0);
if ((initial >= '0' && initial <= '9') || initial == '-') {
try {
return stringToNumber(string);
} catch (Exception ignore) {
@ -2469,8 +2467,75 @@ public class JSONObject {
return string;
}
/**
* Converts a string to a number using the narrowest possible type. Possible
* 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
* @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 {
char initial = val.charAt(0);
if ((initial >= '0' && initial <= '9') || initial == '-') {
// decimal representation
if (isDecimalNotation(val)) {
// 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);
if(initial == '-' && BigDecimal.ZERO.compareTo(bd)==0) {
return Double.valueOf(-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.");
}
}
// 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.");
}
/**
* Throw an exception if the object is a NaN or infinite number.
@ -2896,5 +2961,23 @@ public class JSONObject {
);
}
/**
* For a prospective number, remove the leading zeros
* @param value prospective number
* @return number without leading zeros
*/
private static String removeLeadingZerosOfNumber(String value){
if (value.equals("-")){return value;}
boolean negativeFirstChar = (value.charAt(0) == '-');
int counter = negativeFirstChar ? 1:0;
while (counter < value.length()){
if (value.charAt(counter) != '0'){
if (negativeFirstChar) {return "-".concat(value.substring(counter));}
return value.substring(counter);
}
++counter;
}
if (negativeFirstChar) {return "-0";}
return "0";
}
}

View File

@ -1,152 +0,0 @@
package org.json;
import java.math.BigDecimal;
import java.math.BigInteger;
class NumberConversionUtil {
/**
* Converts a string to a number using the narrowest possible type. Possible
* 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 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.
*/
static Number stringToNumber(final String input) throws NumberFormatException {
String val = input;
if (val.startsWith(".")){
val = "0"+val;
}
if (val.startsWith("-.")){
val = "-0."+val.substring(2);
}
char initial = val.charAt(0);
if ( isNumericChar(initial) || initial == '-' ) {
// decimal representation
if (isDecimalNotation(val)) {
// 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);
if(initial == '-' && BigDecimal.ZERO.compareTo(bd)==0) {
return Double.valueOf(-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 ["+input+"] is not a valid number.");
}
return d;
} catch (NumberFormatException ignore) {
throw new NumberFormatException("val ["+input+"] is not a valid number.");
}
}
}
val = removeLeadingZerosOfNumber(input);
initial = val.charAt(0);
if(initial == '0' && val.length() > 1) {
char at1 = val.charAt(1);
if(isNumericChar(at1)) {
throw new NumberFormatException("val ["+input+"] is not a valid number.");
}
} else if (initial == '-' && val.length() > 2) {
char at1 = val.charAt(1);
char at2 = val.charAt(2);
if(at1 == '0' && isNumericChar(at2)) {
throw new NumberFormatException("val ["+input+"] is not a valid number.");
}
}
// 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 ["+input+"] is not a valid number.");
}
/**
* Checks if the character is a numeric digit ('0' to '9').
*
* @param c The character to be checked.
* @return true if the character is a numeric digit, false otherwise.
*/
private static boolean isNumericChar(char c) {
return (c <= '9' && c >= '0');
}
/**
* Checks if the value could be considered a number in decimal number system.
* @param value
* @return
*/
static boolean potentialNumber(String value){
if (value == null || value.isEmpty()){
return false;
}
return potentialPositiveNumberStartingAtIndex(value, (value.charAt(0)=='-'?1:0));
}
/**
* 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.
*/
private static boolean isDecimalNotation(final String val) {
return val.indexOf('.') > -1 || val.indexOf('e') > -1
|| val.indexOf('E') > -1 || "-0".equals(val);
}
private static boolean potentialPositiveNumberStartingAtIndex(String value,int index){
if (index >= value.length()){
return false;
}
return digitAtIndex(value, (value.charAt(index)=='.'?index+1:index));
}
private static boolean digitAtIndex(String value, int index){
if (index >= value.length()){
return false;
}
return value.charAt(index) >= '0' && value.charAt(index) <= '9';
}
/**
* For a prospective number, remove the leading zeros
* @param value prospective number
* @return number without leading zeros
*/
private static String removeLeadingZerosOfNumber(String value){
if (value.equals("-")){return value;}
boolean negativeFirstChar = (value.charAt(0) == '-');
int counter = negativeFirstChar ? 1:0;
while (counter < value.length()){
if (value.charAt(counter) != '0'){
if (negativeFirstChar) {return "-".concat(value.substring(counter));}
return value.substring(counter);
}
++counter;
}
if (negativeFirstChar) {return "-0";}
return "0";
}
}

View File

@ -10,10 +10,6 @@ import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Iterator;
import static org.json.NumberConversionUtil.potentialNumber;
import static org.json.NumberConversionUtil.stringToNumber;
/**
* This provides static methods to convert an XML text into a JSONObject, and to
* covert a JSONObject into an XML text.
@ -499,6 +495,76 @@ public class XML {
return true;
}
/**
* direct copy of {@link JSONObject#stringToNumber(String)} to maintain Android support.
*/
private static Number stringToNumber(final String val) throws NumberFormatException {
char initial = val.charAt(0);
if ((initial >= '0' && initial <= '9') || initial == '-') {
// decimal representation
if (isDecimalNotation(val)) {
// 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);
if(initial == '-' && BigDecimal.ZERO.compareTo(bd)==0) {
return Double.valueOf(-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.");
}
}
// 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.");
}
/**
* direct copy of {@link JSONObject#isDecimalNotation(String)} to maintain Android support.
*/
private static boolean isDecimalNotation(final String val) {
return val.indexOf('.') > -1 || val.indexOf('e') > -1
|| val.indexOf('E') > -1 || "-0".equals(val);
}
/**
* This method tries to convert the given string value to the target object
@ -543,7 +609,8 @@ public class XML {
* produced, then the value will just be a string.
*/
if (potentialNumber(string)) {
char initial = string.charAt(0);
if ((initial >= '0' && initial <= '9') || initial == '-') {
try {
return stringToNumber(string);
} catch (Exception ignore) {
@ -552,11 +619,6 @@ public class XML {
return string;
}
/**
* Convert a well-formed (but not necessarily valid) XML string into a
* JSONObject. Some information may be lost in this transformation because
@ -975,5 +1037,4 @@ public class XML {
}
return sb.toString();
}
}

View File

@ -1,174 +0,0 @@
package org.json;
import org.junit.Test;
import java.math.BigDecimal;
import java.math.BigInteger;
import static org.junit.Assert.*;
public class NumberConversionUtilTest {
@Test
public void shouldParseDecimalFractionNumbersWithMultipleLeadingZeros(){
Number number = NumberConversionUtil.stringToNumber("00.10d");
assertEquals("Do not match", 0.10d, number.doubleValue(),0.0d);
assertEquals("Do not match", 0.10f, number.floatValue(),0.0f);
assertEquals("Do not match", 0, number.longValue(),0);
assertEquals("Do not match", 0, number.intValue(),0);
}
@Test
public void shouldParseDecimalFractionNumbersWithSingleLeadingZero(){
Number number = NumberConversionUtil.stringToNumber("0.10d");
assertEquals("Do not match", 0.10d, number.doubleValue(),0.0d);
assertEquals("Do not match", 0.10f, number.floatValue(),0.0f);
assertEquals("Do not match", 0, number.longValue(),0);
assertEquals("Do not match", 0, number.intValue(),0);
}
@Test
public void shouldParseDecimalFractionNumbersWithZerosAfterDecimalPoint(){
Number number = NumberConversionUtil.stringToNumber("0.010d");
assertEquals("Do not match", 0.010d, number.doubleValue(),0.0d);
assertEquals("Do not match", 0.010f, number.floatValue(),0.0f);
assertEquals("Do not match", 0, number.longValue(),0);
assertEquals("Do not match", 0, number.intValue(),0);
}
@Test
public void shouldParseMixedDecimalFractionNumbersWithMultipleLeadingZeros(){
Number number = NumberConversionUtil.stringToNumber("00200.10d");
assertEquals("Do not match", 200.10d, number.doubleValue(),0.0d);
assertEquals("Do not match", 200.10f, number.floatValue(),0.0f);
assertEquals("Do not match", 200, number.longValue(),0);
assertEquals("Do not match", 200, number.intValue(),0);
}
@Test
public void shouldParseMixedDecimalFractionNumbersWithoutLeadingZero(){
Number number = NumberConversionUtil.stringToNumber("200.10d");
assertEquals("Do not match", 200.10d, number.doubleValue(),0.0d);
assertEquals("Do not match", 200.10f, number.floatValue(),0.0f);
assertEquals("Do not match", 200, number.longValue(),0);
assertEquals("Do not match", 200, number.intValue(),0);
}
@Test
public void shouldParseMixedDecimalFractionNumbersWithZerosAfterDecimalPoint(){
Number number = NumberConversionUtil.stringToNumber("200.010d");
assertEquals("Do not match", 200.010d, number.doubleValue(),0.0d);
assertEquals("Do not match", 200.010f, number.floatValue(),0.0f);
assertEquals("Do not match", 200, number.longValue(),0);
assertEquals("Do not match", 200, number.intValue(),0);
}
@Test
public void shouldParseNegativeDecimalFractionNumbersWithMultipleLeadingZeros(){
Number number = NumberConversionUtil.stringToNumber("-00.10d");
assertEquals("Do not match", -0.10d, number.doubleValue(),0.0d);
assertEquals("Do not match", -0.10f, number.floatValue(),0.0f);
assertEquals("Do not match", -0, number.longValue(),0);
assertEquals("Do not match", -0, number.intValue(),0);
}
@Test
public void shouldParseNegativeDecimalFractionNumbersWithSingleLeadingZero(){
Number number = NumberConversionUtil.stringToNumber("-0.10d");
assertEquals("Do not match", -0.10d, number.doubleValue(),0.0d);
assertEquals("Do not match", -0.10f, number.floatValue(),0.0f);
assertEquals("Do not match", -0, number.longValue(),0);
assertEquals("Do not match", -0, number.intValue(),0);
}
@Test
public void shouldParseNegativeDecimalFractionNumbersWithZerosAfterDecimalPoint(){
Number number = NumberConversionUtil.stringToNumber("-0.010d");
assertEquals("Do not match", -0.010d, number.doubleValue(),0.0d);
assertEquals("Do not match", -0.010f, number.floatValue(),0.0f);
assertEquals("Do not match", -0, number.longValue(),0);
assertEquals("Do not match", -0, number.intValue(),0);
}
@Test
public void shouldParseNegativeMixedDecimalFractionNumbersWithMultipleLeadingZeros(){
Number number = NumberConversionUtil.stringToNumber("-00200.10d");
assertEquals("Do not match", -200.10d, number.doubleValue(),0.0d);
assertEquals("Do not match", -200.10f, number.floatValue(),0.0f);
assertEquals("Do not match", -200, number.longValue(),0);
assertEquals("Do not match", -200, number.intValue(),0);
}
@Test
public void shouldParseNegativeMixedDecimalFractionNumbersWithoutLeadingZero(){
Number number = NumberConversionUtil.stringToNumber("-200.10d");
assertEquals("Do not match", -200.10d, number.doubleValue(),0.0d);
assertEquals("Do not match", -200.10f, number.floatValue(),0.0f);
assertEquals("Do not match", -200, number.longValue(),0);
assertEquals("Do not match", -200, number.intValue(),0);
}
@Test
public void shouldParseNegativeMixedDecimalFractionNumbersWithZerosAfterDecimalPoint(){
Number number = NumberConversionUtil.stringToNumber("-200.010d");
assertEquals("Do not match", -200.010d, number.doubleValue(),0.0d);
assertEquals("Do not match", -200.010f, number.floatValue(),0.0f);
assertEquals("Do not match", -200, number.longValue(),0);
assertEquals("Do not match", -200, number.intValue(),0);
}
@Test
public void shouldParseNumbersWithExponents(){
Number number = NumberConversionUtil.stringToNumber("23.45e7");
assertEquals("Do not match", 23.45e7d, number.doubleValue(),0.0d);
assertEquals("Do not match", 23.45e7f, number.floatValue(),0.0f);
assertEquals("Do not match", 2.345E8, number.longValue(),0);
assertEquals("Do not match", 2.345E8, number.intValue(),0);
}
@Test
public void shouldParseNegativeNumbersWithExponents(){
Number number = NumberConversionUtil.stringToNumber("-23.45e7");
assertEquals("Do not match", -23.45e7d, number.doubleValue(),0.0d);
assertEquals("Do not match", -23.45e7f, number.floatValue(),0.0f);
assertEquals("Do not match", -2.345E8, number.longValue(),0);
assertEquals("Do not match", -2.345E8, number.intValue(),0);
}
@Test
public void shouldParseBigDecimal(){
Number number = NumberConversionUtil.stringToNumber("19007199254740993.35481234487103587486413587843213584");
assertTrue(number instanceof BigDecimal);
}
@Test
public void shouldParseBigInteger(){
Number number = NumberConversionUtil.stringToNumber("1900719925474099335481234487103587486413587843213584");
assertTrue(number instanceof BigInteger);
}
@Test
public void shouldIdentifyPotentialNumber(){
assertTrue("Does not identify as number", NumberConversionUtil.potentialNumber("112.123"));
assertTrue("Does not identify as number", NumberConversionUtil.potentialNumber("112e123"));
assertTrue("Does not identify as number", NumberConversionUtil.potentialNumber("-112.123"));
assertTrue("Does not identify as number", NumberConversionUtil.potentialNumber("-112e23"));
assertFalse("Does not identify as not number", NumberConversionUtil.potentialNumber("--112.123"));
assertFalse("Does not identify as not number", NumberConversionUtil.potentialNumber("-a112.123"));
assertFalse("Does not identify as not number", NumberConversionUtil.potentialNumber("a112.123"));
assertFalse("Does not identify as not number", NumberConversionUtil.potentialNumber("e112.123"));
}
@Test(expected = NumberFormatException.class)
public void shouldExpectExceptionWhenNumberIsNotFormatted(){
NumberConversionUtil.stringToNumber("112.aa123");
}
}

View File

@ -709,7 +709,7 @@ public class JSONMLTest {
@Test
public void testToJSONArray_jsonOutput() {
final String originalXml = "<root><id>01</id><id>1</id><id>00</id><id>0</id><item id=\"01\"/><title>True</title></root>";
final String expectedJsonString = "[\"root\",[\"id\",1],[\"id\",1],[\"id\",0],[\"id\",0],[\"item\",{\"id\":1}],[\"title\",true]]";
final String expectedJsonString = "[\"root\",[\"id\",\"01\"],[\"id\",1],[\"id\",\"00\"],[\"id\",0],[\"item\",{\"id\":\"01\"}],[\"title\",true]]";
final JSONArray actualJsonOutput = JSONML.toJSONArray(originalXml, false);
assertEquals(expectedJsonString, actualJsonOutput.toString());
}

View File

@ -1,100 +0,0 @@
package org.json.junit;
import org.json.JSONObject;
import org.junit.Test;
import java.math.BigDecimal;
import java.math.BigInteger;
import static org.junit.Assert.assertEquals;
public class JSONObjectDecimalTest {
@Test
public void shouldParseDecimalNumberThatStartsWithDecimalPoint(){
JSONObject jsonObject = new JSONObject("{value:0.50}");
assertEquals("Float not recognized", 0.5f, jsonObject.getFloat("value"), 0.0f);
assertEquals("Float not recognized", 0.5f, jsonObject.optFloat("value"), 0.0f);
assertEquals("Float not recognized", 0.5f, jsonObject.optFloatObject("value"), 0.0f);
assertEquals("Double not recognized", 0.5d, jsonObject.optDouble("value"), 0.0f);
assertEquals("Double not recognized", 0.5d, jsonObject.optDoubleObject("value"), 0.0f);
assertEquals("Double not recognized", 0.5d, jsonObject.getDouble("value"), 0.0f);
assertEquals("Long not recognized", 0, jsonObject.optLong("value"), 0);
assertEquals("Long not recognized", 0, jsonObject.getLong("value"), 0);
assertEquals("Long not recognized", 0, jsonObject.optLongObject("value"), 0);
assertEquals("Integer not recognized", 0, jsonObject.optInt("value"), 0);
assertEquals("Integer not recognized", 0, jsonObject.getInt("value"), 0);
assertEquals("Integer not recognized", 0, jsonObject.optIntegerObject("value"), 0);
assertEquals("Number not recognized", 0, jsonObject.getNumber("value").intValue(), 0);
assertEquals("Number not recognized", 0, jsonObject.getNumber("value").longValue(), 0);
assertEquals("BigDecimal not recognized", 0, BigDecimal.valueOf(.5).compareTo(jsonObject.getBigDecimal("value")));
assertEquals("BigInteger not recognized",0, BigInteger.valueOf(0).compareTo(jsonObject.getBigInteger("value")));
}
@Test
public void shouldParseNegativeDecimalNumberThatStartsWithDecimalPoint(){
JSONObject jsonObject = new JSONObject("{value:-.50}");
assertEquals("Float not recognized", -0.5f, jsonObject.getFloat("value"), 0.0f);
assertEquals("Float not recognized", -0.5f, jsonObject.optFloat("value"), 0.0f);
assertEquals("Float not recognized", -0.5f, jsonObject.optFloatObject("value"), 0.0f);
assertEquals("Double not recognized", -0.5d, jsonObject.optDouble("value"), 0.0f);
assertEquals("Double not recognized", -0.5d, jsonObject.optDoubleObject("value"), 0.0f);
assertEquals("Double not recognized", -0.5d, jsonObject.getDouble("value"), 0.0f);
assertEquals("Long not recognized", 0, jsonObject.optLong("value"), 0);
assertEquals("Long not recognized", 0, jsonObject.getLong("value"), 0);
assertEquals("Long not recognized", 0, jsonObject.optLongObject("value"), 0);
assertEquals("Integer not recognized", 0, jsonObject.optInt("value"), 0);
assertEquals("Integer not recognized", 0, jsonObject.getInt("value"), 0);
assertEquals("Integer not recognized", 0, jsonObject.optIntegerObject("value"), 0);
assertEquals("Number not recognized", 0, jsonObject.getNumber("value").intValue(), 0);
assertEquals("Number not recognized", 0, jsonObject.getNumber("value").longValue(), 0);
assertEquals("BigDecimal not recognized", 0, BigDecimal.valueOf(-.5).compareTo(jsonObject.getBigDecimal("value")));
assertEquals("BigInteger not recognized",0, BigInteger.valueOf(0).compareTo(jsonObject.getBigInteger("value")));
}
@Test
public void shouldParseDecimalNumberThatHasZeroBeforeWithDecimalPoint(){
JSONObject jsonObject = new JSONObject("{value:00.050}");
assertEquals("Float not recognized", 0.05f, jsonObject.getFloat("value"), 0.0f);
assertEquals("Float not recognized", 0.05f, jsonObject.optFloat("value"), 0.0f);
assertEquals("Float not recognized", 0.05f, jsonObject.optFloatObject("value"), 0.0f);
assertEquals("Double not recognized", 0.05d, jsonObject.optDouble("value"), 0.0f);
assertEquals("Double not recognized", 0.05d, jsonObject.optDoubleObject("value"), 0.0f);
assertEquals("Double not recognized", 0.05d, jsonObject.getDouble("value"), 0.0f);
assertEquals("Long not recognized", 0, jsonObject.optLong("value"), 0);
assertEquals("Long not recognized", 0, jsonObject.getLong("value"), 0);
assertEquals("Long not recognized", 0, jsonObject.optLongObject("value"), 0);
assertEquals("Integer not recognized", 0, jsonObject.optInt("value"), 0);
assertEquals("Integer not recognized", 0, jsonObject.getInt("value"), 0);
assertEquals("Integer not recognized", 0, jsonObject.optIntegerObject("value"), 0);
assertEquals("Number not recognized", 0, jsonObject.getNumber("value").intValue(), 0);
assertEquals("Number not recognized", 0, jsonObject.getNumber("value").longValue(), 0);
assertEquals("BigDecimal not recognized", 0, BigDecimal.valueOf(.05).compareTo(jsonObject.getBigDecimal("value")));
assertEquals("BigInteger not recognized",0, BigInteger.valueOf(0).compareTo(jsonObject.getBigInteger("value")));
}
@Test
public void shouldParseNegativeDecimalNumberThatHasZeroBeforeWithDecimalPoint(){
JSONObject jsonObject = new JSONObject("{value:-00.050}");
assertEquals("Float not recognized", -0.05f, jsonObject.getFloat("value"), 0.0f);
assertEquals("Float not recognized", -0.05f, jsonObject.optFloat("value"), 0.0f);
assertEquals("Float not recognized", -0.05f, jsonObject.optFloatObject("value"), 0.0f);
assertEquals("Double not recognized", -0.05d, jsonObject.optDouble("value"), 0.0f);
assertEquals("Double not recognized", -0.05d, jsonObject.optDoubleObject("value"), 0.0f);
assertEquals("Double not recognized", -0.05d, jsonObject.getDouble("value"), 0.0f);
assertEquals("Long not recognized", 0, jsonObject.optLong("value"), 0);
assertEquals("Long not recognized", 0, jsonObject.getLong("value"), 0);
assertEquals("Long not recognized", 0, jsonObject.optLongObject("value"), 0);
assertEquals("Integer not recognized", 0, jsonObject.optInt("value"), 0);
assertEquals("Integer not recognized", 0, jsonObject.getInt("value"), 0);
assertEquals("Integer not recognized", 0, jsonObject.optIntegerObject("value"), 0);
assertEquals("Number not recognized", 0, jsonObject.getNumber("value").intValue(), 0);
assertEquals("Number not recognized", 0, jsonObject.getNumber("value").longValue(), 0);
assertEquals("BigDecimal not recognized", 0, BigDecimal.valueOf(-.05).compareTo(jsonObject.getBigDecimal("value")));
assertEquals("BigInteger not recognized",0, BigInteger.valueOf(0).compareTo(jsonObject.getBigInteger("value")));
}
}

View File

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

View File

@ -4,7 +4,6 @@ package org.json.junit;
Public Domain.
*/
import static java.lang.Double.NaN;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
@ -786,7 +785,7 @@ public class JSONObjectTest {
jsonObject.accumulate("myArray", -23.45e7);
// include an unsupported object for coverage
try {
jsonObject.accumulate("myArray", NaN);
jsonObject.accumulate("myArray", Double.NaN);
fail("Expected exception");
} catch (JSONException ignored) {}
@ -818,7 +817,7 @@ public class JSONObjectTest {
jsonObject.append("myArray", -23.45e7);
// include an unsupported object for coverage
try {
jsonObject.append("myArray", NaN);
jsonObject.append("myArray", Double.NaN);
fail("Expected exception");
} catch (JSONException ignored) {}
@ -843,7 +842,7 @@ public class JSONObjectTest {
public void jsonObjectDoubleToString() {
String [] expectedStrs = {"1", "1", "-23.4", "-2.345E68", "null", "null" };
Double [] doubles = { 1.0, 00001.00000, -23.4, -23.45e67,
NaN, Double.NEGATIVE_INFINITY };
Double.NaN, Double.NEGATIVE_INFINITY };
for (int i = 0; i < expectedStrs.length; ++i) {
String actualStr = JSONObject.doubleToString(doubles[i]);
assertTrue("value expected ["+expectedStrs[i]+
@ -898,11 +897,11 @@ public class JSONObjectTest {
assertTrue("opt doubleKey should be double",
jsonObject.optDouble("doubleKey") == -23.45e7);
assertTrue("opt doubleKey with Default should be double",
jsonObject.optDouble("doubleStrKey", NaN) == 1);
jsonObject.optDouble("doubleStrKey", Double.NaN) == 1);
assertTrue("opt doubleKey should be Double",
Double.valueOf(-23.45e7).equals(jsonObject.optDoubleObject("doubleKey")));
assertTrue("opt doubleKey with Default should be Double",
Double.valueOf(1).equals(jsonObject.optDoubleObject("doubleStrKey", NaN)));
Double.valueOf(1).equals(jsonObject.optDoubleObject("doubleStrKey", Double.NaN)));
assertTrue("opt negZeroKey should be a Double",
jsonObject.opt("negZeroKey") instanceof Double);
assertTrue("get negZeroKey should be a Double",
@ -1068,21 +1067,12 @@ public class JSONObjectTest {
"\"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,"+
"\"doubleIdentifierWithMultipleLeadingZerosBeforeDecimal\":0000000.1d,"+
"\"negativeDoubleIdentifierWithMultipleLeadingZerosBeforeDecimal\":-0000000.1d,"+
"\"doubleIdentifierWithMultipleLeadingZerosAfterDecimal\":0000000.0001d,"+
"\"negativeDoubleIdentifierWithMultipleLeadingZerosAfterDecimal\":-0000000.0001d,"+
"\"integerWithLeadingZeros\":000900,"+
"\"integerWithAllZeros\":00000,"+
"\"compositeWithLeadingZeros\":00800.90d,"+
"\"decimalPositiveWithoutNumberBeforeDecimalPoint\":.90,"+
"\"doubleIdentifier\":0.1d"+
"}";
JSONObject jsonObject = new JSONObject(str);
Object obj;
@ -1092,22 +1082,15 @@ public class JSONObjectTest {
assertTrue("hexNumber currently evaluates to string",
obj.equals("-0x123"));
assertTrue( "tooManyZeros currently evaluates to string",
jsonObject.get( "tooManyZeros" ).equals(0));
jsonObject.get( "tooManyZeros" ).equals("00"));
obj = jsonObject.get("negativeInfinite");
assertTrue( "negativeInfinite currently evaluates to string",
obj.equals("-Infinity"));
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",
@ -1118,53 +1101,6 @@ public class JSONObjectTest {
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("doubleIdentifierWithMultipleLeadingZerosBeforeDecimal currently evaluates to double 0.1",
jsonObject.get("doubleIdentifierWithMultipleLeadingZerosBeforeDecimal").equals(Double.valueOf(0.1)));
assertTrue("negativeDoubleIdentifierWithMultipleLeadingZerosBeforeDecimal currently evaluates to double -0.1",
jsonObject.get("negativeDoubleIdentifierWithMultipleLeadingZerosBeforeDecimal").equals(Double.valueOf(-0.1)));
assertTrue("doubleIdentifierWithMultipleLeadingZerosAfterDecimal currently evaluates to double 0.0001",
jsonObject.get("doubleIdentifierWithMultipleLeadingZerosAfterDecimal").equals(Double.valueOf(0.0001)));
assertTrue("doubleIdentifierWithMultipleLeadingZerosAfterDecimal currently evaluates to double 0.0001",
jsonObject.get("doubleIdentifierWithMultipleLeadingZerosAfterDecimal").equals(Double.valueOf(0.0001)));
assertTrue("negativeDoubleIdentifierWithMultipleLeadingZerosAfterDecimal currently evaluates to double -0.0001",
jsonObject.get("negativeDoubleIdentifierWithMultipleLeadingZerosAfterDecimal").equals(Double.valueOf(-0.0001)));
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(0));
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);
assertEquals("Get long of decimalPositiveWithoutNumberBeforeDecimalPoint does not match",
0.9d,jsonObject.getDouble("decimalPositiveWithoutNumberBeforeDecimalPoint"), 0.0d);
assertEquals("Get long of decimalPositiveWithoutNumberBeforeDecimalPoint does not match",
0.9d,jsonObject.optDouble("decimalPositiveWithoutNumberBeforeDecimalPoint"), 0.0d);
assertEquals("Get long of decimalPositiveWithoutNumberBeforeDecimalPoint does not match",
0.0d,jsonObject.optLong("decimalPositiveWithoutNumberBeforeDecimalPoint"), 0.0d);
assertEquals("Get long of doubleIdentifierWithMultipleLeadingZerosAfterDecimal does not match",
0.0001d,jsonObject.getDouble("doubleIdentifierWithMultipleLeadingZerosAfterDecimal"), 0.0d);
assertEquals("Get long of doubleIdentifierWithMultipleLeadingZerosAfterDecimal does not match",
0.0001d,jsonObject.optDouble("doubleIdentifierWithMultipleLeadingZerosAfterDecimal"), 0.0d);
assertEquals("Get long of doubleIdentifierWithMultipleLeadingZerosAfterDecimal does not match",
0.0d, jsonObject.getLong("doubleIdentifierWithMultipleLeadingZerosAfterDecimal") , 0.0d);
assertEquals("Get long of doubleIdentifierWithMultipleLeadingZerosAfterDecimal does not match",
0.0d,jsonObject.optLong("doubleIdentifierWithMultipleLeadingZerosAfterDecimal"), 0.0d);
Util.checkJSONObjectMaps(jsonObject);
}
@ -2398,7 +2334,7 @@ public class JSONObjectTest {
}
try {
// test validity of invalid double
JSONObject.testValidity(NaN);
JSONObject.testValidity(Double.NaN);
fail("Expected an exception");
} catch (JSONException e) {
assertTrue("", true);
@ -3802,6 +3738,43 @@ public class JSONObjectTest {
new JSONObject(map1);
}
@Test
public void clarifyCurrentBehavior() {
// Behavior documented in #653 optLong vs getLong inconsistencies
// This problem still exists.
// Internally, both number_1 and number_2 are stored as strings. This is reasonable since they are parsed as strings.
// However, getLong and optLong should return similar results
JSONObject json = new JSONObject("{\"number_1\":\"01234\", \"number_2\": \"332211\"}");
assertEquals(json.getLong("number_1"), 1234L);
assertEquals(json.optLong("number_1"), 0); //THIS VALUE IS NOT RETURNED AS A NUMBER
assertEquals(json.getLong("number_2"), 332211L);
assertEquals(json.optLong("number_2"), 332211L);
// Behavior documented in #826 JSONObject parsing 0-led numeric strings as ints
// After reverting the code, personId is stored as a string, and the behavior is as expected
String personId = "0123";
JSONObject j1 = new JSONObject("{personId: " + personId + "}");
assertEquals(j1.getString("personId"), "0123");
// Also #826. Here is input with missing quotes. Because of the leading zero, it should not be parsed as a number.
// This example was mentioned in the same ticket
// After reverting the code, personId is stored as a string, and the behavior is as expected
JSONObject j2 = new JSONObject("{\"personId\":0123}");
assertEquals(j2.getString("personId"), "0123");
// Behavior uncovered while working on the code
// All of the values are stored as strings except for hex4, which is stored as a number. This is probably incorrect
JSONObject j3 = new JSONObject("{ " +
"\"hex1\": \"010e4\", \"hex2\": \"00f0\", \"hex3\": \"0011\", " +
"\"hex4\": 00e0, \"hex5\": 00f0, \"hex6\": 0011 }");
assertEquals(j3.getString("hex1"), "010e4");
assertEquals(j3.getString("hex2"), "00f0");
assertEquals(j3.getString("hex3"), "0011");
assertEquals(j3.getLong("hex4"), 0, .1);
assertEquals(j3.getString("hex5"), "00f0");
assertEquals(j3.getString("hex6"), "0011");
}
/**
* Method to build nested map of max maxDepth
*

View File

@ -1,55 +0,0 @@
package org.json.junit;
import org.json.JSONObject;
import org.junit.Test;
import java.math.BigDecimal;
import java.math.BigInteger;
import static org.junit.Assert.assertEquals;
public class JsonNumberZeroTest {
@Test
public void shouldParseNegativeZeroValueWithMultipleZeroDigit(){
JSONObject jsonObject = new JSONObject("{value:-0000}");
assertEquals("Float not recognized", -0f, jsonObject.getFloat("value"), 0.0f);
assertEquals("Float not recognized", -0f, jsonObject.optFloat("value"), 0.0f);
assertEquals("Float not recognized", -0f, jsonObject.optFloatObject("value"), 0.0f);
assertEquals("Double not recognized", -0d, jsonObject.optDouble("value"), 0.0f);
assertEquals("Double not recognized", -0.0d, jsonObject.optDoubleObject("value"), 0.0f);
assertEquals("Double not recognized", -0.0d, jsonObject.getDouble("value"), 0.0f);
assertEquals("Long not recognized", 0, jsonObject.optLong("value"), 0);
assertEquals("Long not recognized", 0, jsonObject.getLong("value"), 0);
assertEquals("Long not recognized", 0, jsonObject.optLongObject("value"), 0);
assertEquals("Integer not recognized", 0, jsonObject.optInt("value"), 0);
assertEquals("Integer not recognized", 0, jsonObject.getInt("value"), 0);
assertEquals("Integer not recognized", 0, jsonObject.optIntegerObject("value"), 0);
assertEquals("Number not recognized", 0, jsonObject.getNumber("value").intValue(), 0);
assertEquals("Number not recognized", 0, jsonObject.getNumber("value").longValue(), 0);
assertEquals("BigDecimal not recognized", 0, BigDecimal.valueOf(-0).compareTo(jsonObject.getBigDecimal("value")));
assertEquals("BigInteger not recognized",0, BigInteger.valueOf(0).compareTo(jsonObject.getBigInteger("value")));
}
@Test
public void shouldParseZeroValueWithMultipleZeroDigit(){
JSONObject jsonObject = new JSONObject("{value:0000}");
assertEquals("Float not recognized", 0f, jsonObject.getFloat("value"), 0.0f);
assertEquals("Float not recognized", 0f, jsonObject.optFloat("value"), 0.0f);
assertEquals("Float not recognized", 0f, jsonObject.optFloatObject("value"), 0.0f);
assertEquals("Double not recognized", 0d, jsonObject.optDouble("value"), 0.0f);
assertEquals("Double not recognized", 0.0d, jsonObject.optDoubleObject("value"), 0.0f);
assertEquals("Double not recognized", 0.0d, jsonObject.getDouble("value"), 0.0f);
assertEquals("Long not recognized", 0, jsonObject.optLong("value"), 0);
assertEquals("Long not recognized", 0, jsonObject.getLong("value"), 0);
assertEquals("Long not recognized", 0, jsonObject.optLongObject("value"), 0);
assertEquals("Integer not recognized", 0, jsonObject.optInt("value"), 0);
assertEquals("Integer not recognized", 0, jsonObject.getInt("value"), 0);
assertEquals("Integer not recognized", 0, jsonObject.optIntegerObject("value"), 0);
assertEquals("Number not recognized", 0, jsonObject.getNumber("value").intValue(), 0);
assertEquals("Number not recognized", 0, jsonObject.getNumber("value").longValue(), 0);
assertEquals("BigDecimal not recognized", 0, BigDecimal.valueOf(-0).compareTo(jsonObject.getBigDecimal("value")));
assertEquals("BigInteger not recognized",0, BigInteger.valueOf(0).compareTo(jsonObject.getBigInteger("value")));
}
}

View File

@ -761,7 +761,7 @@ public class XMLConfigurationTest {
@Test
public void testToJSONArray_jsonOutput() {
final String originalXml = "<root><id>01</id><id>1</id><id>00</id><id>0</id><item id=\"01\"/><title>True</title></root>";
final JSONObject expected = new JSONObject("{\"root\":{\"item\":{\"id\":1},\"id\":[1,1,0,0],\"title\":true}}");
final JSONObject expected = new JSONObject("{\"root\":{\"item\":{\"id\":\"01\"},\"id\":[\"01\",1,\"00\",0],\"title\":true}}");
final JSONObject actualJsonOutput = XML.toJSONObject(originalXml,
new XMLParserConfiguration().withKeepStrings(false));
Util.compareActualVsExpectedJsonObjects(actualJsonOutput,expected);

View File

@ -791,7 +791,7 @@ public class XMLTest {
@Test
public void testToJSONArray_jsonOutput() {
final String originalXml = "<root><id>01</id><id>1</id><id>00</id><id>0</id><item id=\"01\"/><title>True</title></root>";
final JSONObject expectedJson = new JSONObject("{\"root\":{\"item\":{\"id\":1},\"id\":[1,1,0,0],\"title\":true}}");
final JSONObject expectedJson = new JSONObject("{\"root\":{\"item\":{\"id\":\"01\"},\"id\":[\"01\",1,\"00\",0],\"title\":true}}");
final JSONObject actualJsonOutput = XML.toJSONObject(originalXml, false);
Util.compareActualVsExpectedJsonObjects(actualJsonOutput,expectedJson);
@ -1397,6 +1397,35 @@ public class XMLTest {
Util.compareActualVsExpectedJsonObjects(actualJson,expectedJson);
}
@Test
public void clarifyCurrentBehavior() {
// Behavior documented in #826
// After reverting the code, amount is stored as numeric, and phone is stored as string
String str1 =
" <datatypes>\n" +
" <telephone>0123456789</telephone>\n" +
" <amount>0.1230</amount>\n" +
" <boolean>true</boolean>\n" +
" </datatypes>";
JSONObject jsonObject1 = XML.toJSONObject(str1,
new XMLParserConfiguration().withKeepStrings(false));
assertEquals(jsonObject1.getJSONObject("datatypes").getFloat("amount"), 0.123, .1);
assertEquals(jsonObject1.getJSONObject("datatypes").getString("telephone"), "0123456789");
// Behavior documented in #852
// After reverting the code, value is still stored as a number. This is due to how XML.isDecimalNotation() works
// and is probably a bug. JSONObject has a similar problem.
String str2 = "<color> <color_type>primary</color_type> <value>008E97</value> </color>";
JSONObject jsonObject2 = XML.toJSONObject(str2);
assertEquals(jsonObject2.getJSONObject("color").getLong("value"), 0e897, .1);
// Workaround for now is to use keepStrings
JSONObject jsonObject3 = XML.toJSONObject(str2, new XMLParserConfiguration().withKeepStrings(true));
assertEquals(jsonObject3.getJSONObject("color").getString("value"), "008E97");
}
}