@@ -1068,7 +1068,11 @@ public BigInteger optBigInteger(String key, BigInteger defaultValue) {
10681068 // jo.optInt("double"); -- will return 1, not an error
10691069 // this conversion to BigDecimal then to BigInteger is to maintain
10701070 // that type cast support that may truncate the decimal.
1071- return new BigDecimal (val .toString ()).toBigInteger ();
1071+ final String valStr = val .toString ();
1072+ if (isDecimalNotation (valStr )) {
1073+ return new BigDecimal (valStr ).toBigInteger ();
1074+ }
1075+ return new BigInteger (valStr );
10721076 } catch (Exception e ) {
10731077 return defaultValue ;
10741078 }
@@ -1759,12 +1763,22 @@ public boolean similar(Object other) {
17591763 return false ;
17601764 }
17611765 }
1762-
1766+
1767+ /**
1768+ * Tests if the value should be tried as a decimal. It makes no test if there are actual digits.
1769+ *
1770+ * @param val value to test
1771+ * @return true if the string is "-0" or if it contains '.', 'e', or 'E', false otherwise.
1772+ */
1773+ protected static boolean isDecimalNotation (final String val ) {
1774+ return val .indexOf ('.' ) > -1 || val .indexOf ('e' ) > -1
1775+ || val .indexOf ('E' ) > -1 || "-0" .equals (val );
1776+ }
1777+
17631778 /**
17641779 * Converts a string to a number using the narrowest possible type. Possible
17651780 * returns for this function are BigDecimal, Double, BigInteger, Long, and Integer.
1766- *
1767- * An Exception is thrown if
1781+ * When a Double is returned, it should always be a valid Double and not NaN or +-infinity.
17681782 *
17691783 * @param val value to convert
17701784 * @return Number representation of the value.
@@ -1775,46 +1789,52 @@ protected static Number stringToNumber(final String val) throws NumberFormatExce
17751789 char initial = val .charAt (0 );
17761790 if ((initial >= '0' && initial <= '9' ) || initial == '-' ) {
17771791 // decimal representation
1778- if (val .indexOf ('.' ) > -1 || val .indexOf ('e' ) > -1
1779- || val .indexOf ('E' ) > -1
1780- || "-0" .equals (val )) {
1792+ if (isDecimalNotation (val )) {
17811793 // quick dirty way to see if we need a BigDecimal instead of a Double
1794+ // this only handles some cases of overflow or underflow
17821795 if (val .length ()>14 ) {
17831796 return new BigDecimal (val );
17841797 }
1785- return Double .valueOf (val );
1798+ final Double d = Double .valueOf (val );
1799+ if (d .isInfinite () || d .isNaN ()) {
1800+ // if we can't parse it as a double, go up to BigDecimal
1801+ // this is probably due to underflow like 4.32e-678
1802+ // or overflow like 4.65e5324. The size of the string is small
1803+ // but can't be held in a Double.
1804+ return new BigDecimal (val );
1805+ }
1806+ return d ;
17861807 }
17871808 // integer representation.
17881809 // This will narrow any values to the smallest reasonable Object representation
17891810 // (Integer, Long, or BigInteger)
1811+
1812+ // string version
17901813 // The compare string length method reduces GC,
17911814 // but leads to smaller integers being placed in larger wrappers even though not
17921815 // needed. i.e. 1,000,000,000 -> Long even though it's an Integer
17931816 // 1,000,000,000,000,000,000 -> BigInteger even though it's a Long
1794-
1795- // string version
1796- if (val .length ()<=9 ){
1797- return Integer .valueOf (val );
1798- }
1799- if (val .length ()<=18 ){
1800- return Long .valueOf (val );
1801- }
1802- return new BigInteger (val );
1817+ //if(val.length()<=9){
1818+ // return Integer.valueOf(val);
1819+ //}
1820+ //if(val.length()<=18){
1821+ // return Long.valueOf(val);
1822+ //}
1823+ //return new BigInteger(val);
18031824
18041825 // BigInteger version: We use a similar bitLenth compare as
18051826 // BigInteger#intValueExact uses. Increases GC, but objects hold
18061827 // only what they need. i.e. Less runtime overhead if the value is
18071828 // long lived. Which is the better tradeoff? This is closer to what's
18081829 // in stringToValue.
1809-
1810- //BigInteger bi = new BigInteger((String)val);
1811- //if(bi.bitLength()<=31){
1812- // return Integer.valueOf(bi.intValue());
1813- //}
1814- //if(bi.bitLength()<=63){
1815- // return Long.valueOf(bi.longValue());
1816- //}
1817- //return bi;
1830+ BigInteger bi = new BigInteger (val );
1831+ if (bi .bitLength ()<=31 ){
1832+ return Integer .valueOf (bi .intValue ());
1833+ }
1834+ if (bi .bitLength ()<=63 ){
1835+ return Long .valueOf (bi .longValue ());
1836+ }
1837+ return bi ;
18181838 }
18191839 throw new NumberFormatException ("val [" +val +"] is not a valid number." );
18201840 }
@@ -1849,9 +1869,9 @@ public static Object stringToValue(String string) {
18491869 char initial = string .charAt (0 );
18501870 if ((initial >= '0' && initial <= '9' ) || initial == '-' ) {
18511871 try {
1852- if ( string . indexOf ( '.' ) > - 1 || string . indexOf ( 'e' ) > - 1
1853- || string . indexOf ( 'E' ) > - 1
1854- || "-0" . equals (string )) {
1872+ // if we want full Big Number support this block can be replaced with:
1873+ // return stringToNumber(string);
1874+ if ( isDecimalNotation (string )) {
18551875 Double d = Double .valueOf (string );
18561876 if (!d .isInfinite () && !d .isNaN ()) {
18571877 return d ;
0 commit comments