Skip to content

Commit

Permalink
correct error in converting doubles to big decimals
Browse files Browse the repository at this point in the history
  • Loading branch information
johnjaylward committed Jul 23, 2021
1 parent c03054b commit 781af8e
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 6 deletions.
25 changes: 22 additions & 3 deletions src/main/java/org/json/JSONObject.java
Original file line number Diff line number Diff line change
Expand Up @@ -1159,6 +1159,18 @@ public BigDecimal optBigDecimal(String key, BigDecimal defaultValue) {
* to convert.
*/
static BigDecimal objectToBigDecimal(Object val, BigDecimal defaultValue) {
return objectToBigDecimal(val, defaultValue, true);
}

/**
* @param val value to convert
* @param defaultValue default value to return is the conversion doesn't work or is null.
* @param exact When <code>true</code>, then {@link Double} and {@link Float} values will be converted exactly.
* When <code>false</code>, they will be converted to {@link String} values before converting to {@link BigDecimal}.
* @return BigDecimal conversion of the original value, or the defaultValue if unable
* to convert.
*/
static BigDecimal objectToBigDecimal(Object val, BigDecimal defaultValue, boolean exact) {
if (NULL.equals(val)) {
return defaultValue;
}
Expand All @@ -1172,7 +1184,14 @@ static BigDecimal objectToBigDecimal(Object val, BigDecimal defaultValue) {
if (!numberIsFinite((Number)val)) {
return defaultValue;
}
return new BigDecimal(((Number) val).doubleValue());
if (exact) {
return new BigDecimal(((Number)val).doubleValue());
}else {
// use the string constructor so that we maintain "nice" values for doubles and floats
// the double constructor will translate doubles to "exact" values instead of the likely
// intended representation
return new BigDecimal(val.toString());
}
}
if (val instanceof Long || val instanceof Integer
|| val instanceof Short || val instanceof Byte){
Expand Down Expand Up @@ -2132,8 +2151,8 @@ static boolean isNumberSimilar(Number l, Number r) {
// BigDecimal should be able to handle all of our number types that we support through
// documentation. Convert to BigDecimal first, then use the Compare method to
// decide equality.
final BigDecimal lBigDecimal = objectToBigDecimal(l, null);
final BigDecimal rBigDecimal = objectToBigDecimal(r, null);
final BigDecimal lBigDecimal = objectToBigDecimal(l, null, false);
final BigDecimal rBigDecimal = objectToBigDecimal(r, null, false);
if (lBigDecimal == null || rBigDecimal == null) {
return false;
}
Expand Down
7 changes: 4 additions & 3 deletions src/test/java/org/json/junit/JSONObjectTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ public void verifySimilar() {

assertTrue("Should eval to true", obj1.similar(obj4));

// verify that a double and big decimal are "similar"
assertTrue("should eval to true",new JSONObject().put("a",1.1d).similar(new JSONObject("{\"a\":1.1}")));

}
Expand Down Expand Up @@ -942,7 +943,7 @@ public void stringToValueNumbersTest() {
assertTrue("-0 Should be a Double!",JSONObject.stringToValue("-0") instanceof Double);
assertTrue("-0.0 Should be a Double!",JSONObject.stringToValue("-0.0") instanceof Double);
assertTrue("'-' Should be a String!",JSONObject.stringToValue("-") instanceof String);
assertTrue( "0.2 should be a Double!",
assertTrue( "0.2 should be a BigDecimal!",
JSONObject.stringToValue( "0.2" ) instanceof BigDecimal );
assertTrue( "Doubles should be BigDecimal, even when incorrectly converting floats!",
JSONObject.stringToValue( new Double( "0.2f" ).toString() ) instanceof BigDecimal );
Expand Down Expand Up @@ -2521,8 +2522,8 @@ public void jsonObjectOptBigDecimal() {

assertEquals(new BigDecimal("123"),jo.optBigDecimal("int", null));
assertEquals(new BigDecimal("654"),jo.optBigDecimal("long", null));
assertEquals(new BigDecimal(1.234f),jo.optBigDecimal("float", null));
assertEquals(new BigDecimal(2.345d),jo.optBigDecimal("double", null));
assertEquals(new BigDecimal("1.234"),jo.optBigDecimal("float", null));
assertEquals(new BigDecimal("2.345"),jo.optBigDecimal("double", null));
assertEquals(new BigDecimal("1234"),jo.optBigDecimal("bigInteger", null));
assertEquals(new BigDecimal("1234.56789"),jo.optBigDecimal("bigDecimal", null));
assertNull(jo.optBigDecimal("nullVal", null));
Expand Down

0 comments on commit 781af8e

Please sign in to comment.