@@ -1161,8 +1161,7 @@ static BigDecimal objectToBigDecimal(Object val, BigDecimal defaultValue) {
11611161 return new BigDecimal ((BigInteger ) val );
11621162 }
11631163 if (val instanceof Double || val instanceof Float ){
1164- final double d = ((Number ) val ).doubleValue ();
1165- if (Double .isNaN (d )) {
1164+ if (!numberIsFinite ((Number )val )) {
11661165 return defaultValue ;
11671166 }
11681167 return new BigDecimal (((Number ) val ).doubleValue ());
@@ -1212,11 +1211,10 @@ static BigInteger objectToBigInteger(Object val, BigInteger defaultValue) {
12121211 return ((BigDecimal ) val ).toBigInteger ();
12131212 }
12141213 if (val instanceof Double || val instanceof Float ){
1215- final double d = ((Number ) val ).doubleValue ();
1216- if (Double .isNaN (d )) {
1214+ if (!numberIsFinite ((Number )val )) {
12171215 return defaultValue ;
12181216 }
1219- return new BigDecimal (d ).toBigInteger ();
1217+ return new BigDecimal ((( Number ) val ). doubleValue () ).toBigInteger ();
12201218 }
12211219 if (val instanceof Long || val instanceof Integer
12221220 || val instanceof Short || val instanceof Byte ){
@@ -2073,6 +2071,8 @@ public boolean similar(Object other) {
20732071 if (!((JSONArray )valueThis ).similar (valueOther )) {
20742072 return false ;
20752073 }
2074+ } else if (valueThis instanceof Number && valueOther instanceof Number ) {
2075+ return isNumberSimilar ((Number )valueThis , (Number )valueOther );
20762076 } else if (!valueThis .equals (valueOther )) {
20772077 return false ;
20782078 }
@@ -2083,6 +2083,55 @@ public boolean similar(Object other) {
20832083 }
20842084 }
20852085
2086+ /**
2087+ * Compares two numbers to see if they are similar.
2088+ *
2089+ * If either of the numbers are Double or Float instances, then they are checked to have
2090+ * a finite value. If either value is not finite (NaN or ±infinity), then this
2091+ * function will always return false. If both numbers are finite, they are first checked
2092+ * to be the same type and implement {@link Comparable}. If they do, then the actual
2093+ * {@link Comparable#compareTo(Object)} is called. If they are not the same type, or don't
2094+ * implement Comparable, then they are converted to {@link BigDecimal}s. Finally the
2095+ * BigDecimal values are compared using {@link BigDecimal#compareTo(BigDecimal)}.
2096+ *
2097+ * @param l the Left value to compare. Can not be <code>null</code>.
2098+ * @param r the right value to compare. Can not be <code>null</code>.
2099+ * @return true if the numbers are similar, false otherwise.
2100+ */
2101+ static boolean isNumberSimilar (Number l , Number r ) {
2102+ if (!numberIsFinite (l ) || !numberIsFinite (r )) {
2103+ // non-finite numbers are never similar
2104+ return false ;
2105+ }
2106+
2107+ // if the classes are the same and implement Comparable
2108+ // then use the built in compare first.
2109+ if (l .getClass ().equals (r .getClass ()) && l instanceof Comparable ) {
2110+ @ SuppressWarnings ({ "rawtypes" , "unchecked" })
2111+ int compareTo = ((Comparable )l ).compareTo (r );
2112+ return compareTo ==0 ;
2113+ }
2114+
2115+ // BigDecimal should be able to handle all of our number types that we support through
2116+ // documentation. Convert to BigDecimal first, then use the Compare method to
2117+ // decide equality.
2118+ final BigDecimal lBigDecimal = objectToBigDecimal (l , null );
2119+ final BigDecimal rBigDecimal = objectToBigDecimal (r , null );
2120+ if (lBigDecimal == null || rBigDecimal == null ) {
2121+ return false ;
2122+ }
2123+ return lBigDecimal .compareTo (rBigDecimal ) == 0 ;
2124+ }
2125+
2126+ private static boolean numberIsFinite (Number n ) {
2127+ if (n instanceof Double && (((Double ) n ).isInfinite () || ((Double ) n ).isNaN ())) {
2128+ return false ;
2129+ } else if (n instanceof Float && (((Float ) n ).isInfinite () || ((Float ) n ).isNaN ())) {
2130+ return false ;
2131+ }
2132+ return true ;
2133+ }
2134+
20862135 /**
20872136 * Tests if the value should be tried as a decimal. It makes no test if there are actual digits.
20882137 *
@@ -2216,18 +2265,8 @@ public static Object stringToValue(String string) {
22162265 * If o is a non-finite number.
22172266 */
22182267 public static void testValidity (Object o ) throws JSONException {
2219- if (o != null ) {
2220- if (o instanceof Double ) {
2221- if (((Double ) o ).isInfinite () || ((Double ) o ).isNaN ()) {
2222- throw new JSONException (
2223- "JSON does not allow non-finite numbers." );
2224- }
2225- } else if (o instanceof Float ) {
2226- if (((Float ) o ).isInfinite () || ((Float ) o ).isNaN ()) {
2227- throw new JSONException (
2228- "JSON does not allow non-finite numbers." );
2229- }
2230- }
2268+ if (o instanceof Number && !numberIsFinite ((Number ) o )) {
2269+ throw new JSONException ("JSON does not allow non-finite numbers." );
22312270 }
22322271 }
22332272
@@ -2354,7 +2393,7 @@ public static String valueToString(Object value) throws JSONException {
23542393 */
23552394 public static Object wrap (Object object ) {
23562395 try {
2357- if (object == null ) {
2396+ if (NULL . equals ( object ) ) {
23582397 return NULL ;
23592398 }
23602399 if (object instanceof JSONObject || object instanceof JSONArray
0 commit comments