Skip to content

Commit f939389

Browse files
hansonrhansonr
authored andcommitted
org.json.JSON fixing Java error in writer for BigDecimal, BigInteger
1 parent 978b65f commit f939389

File tree

2 files changed

+82
-73
lines changed

2 files changed

+82
-73
lines changed

sources/net.sf.j2s.java.core/src/org/json/JSONObject.java

Lines changed: 36 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1408,7 +1408,8 @@ private boolean isValidMethodName(String name) {
14081408
}
14091409

14101410
private String getKeyNameFromMethod(Method method) {
1411-
final int ignoreDepth = -1;// getAnnotationDepth(method, JSONPropertyIgnore.class);
1411+
// SwingJS - no annotations
1412+
// final int ignoreDepth = -1;// getAnnotationDepth(method, JSONPropertyIgnore.class);
14121413
// if (ignoreDepth > 0) {
14131414
// final int forcedNameDepth = getAnnotationDepth(method, JSONPropertyName.class);
14141415
// if (forcedNameDepth < 0 || ignoreDepth <= forcedNameDepth) {
@@ -1959,20 +1960,15 @@ protected static Number stringToNumber(final String val) throws NumberFormatExce
19591960
if ((initial >= '0' && initial <= '9') || initial == '-') {
19601961
// decimal representation
19611962
if (isDecimalNotation(val)) {
1963+
Double d;
19621964
// quick dirty way to see if we need a BigDecimal instead of a Double
19631965
// this only handles some cases of overflow or underflow
1964-
if (val.length() > 14) {
1965-
return new BigDecimal(val);
1966-
}
1967-
final Double d = Double.valueOf(val);
1968-
if (d.isInfinite() || d.isNaN()) {
1969-
// if we can't parse it as a double, go up to BigDecimal
1970-
// this is probably due to underflow like 4.32e-678
1971-
// or overflow like 4.65e5324. The size of the string is small
1972-
// but can't be held in a Double.
1973-
return new BigDecimal(val);
1974-
}
1975-
return d;
1966+
// if we can't parse it as a double, go up to BigDecimal
1967+
// this is probably due to underflow like 4.32e-678
1968+
// or overflow like 4.65e5324. The size of the string is small
1969+
// but can't be held in a Double.
1970+
return (val.length() <= 14 && !(d = Double.valueOf(val)).isInfinite() && !d.isNaN() ? d
1971+
: new BigDecimal(val));
19761972
}
19771973
// integer representation.
19781974
// This will narrow any values to the smallest reasonable Object representation
@@ -1983,27 +1979,31 @@ protected static Number stringToNumber(final String val) throws NumberFormatExce
19831979
// but leads to smaller integers being placed in larger wrappers even though not
19841980
// needed. i.e. 1,000,000,000 -> Long even though it's an Integer
19851981
// 1,000,000,000,000,000,000 -> BigInteger even though it's a Long
1986-
// if(val.length()<=9){
1987-
// return Integer.valueOf(val);
1988-
// }
1989-
// if(val.length()<=18){
1990-
// return Long.valueOf(val);
1991-
// }
1992-
// return new BigInteger(val);
1993-
1994-
// BigInteger version: We use a similar bitLenth compare as
1995-
// BigInteger#intValueExact uses. Increases GC, but objects hold
1996-
// only what they need. i.e. Less runtime overhead if the value is
1997-
// long lived. Which is the better tradeoff? This is closer to what's
1998-
// in stringToValue.
1999-
BigInteger bi = new BigInteger(val);
2000-
if (bi.bitLength() <= 31) {
2001-
return Integer.valueOf(bi.intValue());
1982+
int n = (/** @j2sNative 1 ? parseInt(val) : */
1983+
0);
1984+
if (n >= Integer.MIN_VALUE && n <= Integer.MAX_VALUE) {
1985+
// if(val.length()<=9){
1986+
return Integer.valueOf(val);
20021987
}
2003-
if (bi.bitLength() <= 63) {
2004-
return Long.valueOf(bi.longValue());
1988+
if (val.equals("" + n)) {
1989+
// if(val.length()<=18){
1990+
return Long.valueOf(val);
20051991
}
2006-
return bi;
1992+
return new BigInteger(val);
1993+
//
1994+
// // BigInteger version: We use a similar bitLenth compare as
1995+
// // BigInteger#intValueExact uses. Increases GC, but objects hold
1996+
// // only what they need. i.e. Less runtime overhead if the value is
1997+
// // long lived. Which is the better tradeoff? This is closer to what's
1998+
// // in stringToValue.
1999+
// BigInteger bi = new BigInteger(val);
2000+
// if (bi.bitLength() <= 31) {
2001+
// return Integer.valueOf(bi.intValue());
2002+
// }
2003+
// if (bi.bitLength() <= 63) {
2004+
// return Long.valueOf(bi.longValue());
2005+
// }
2006+
// return bi;
20072007
}
20082008
throw new NumberFormatException("val [" + val + "] is not a valid number.");
20092009
}
@@ -2223,8 +2223,9 @@ public static Object wrap(Object object) {
22232223
return new JSONObject(map);
22242224
}
22252225
// SwingJS does not implement java.lang.Package class
2226-
//Package objectPackage = (Package) object.getClass().getPackage();
2227-
//String objectPackageName = //objectPackage != null ? objectPackage.getName() : "";
2226+
// Package objectPackage = (Package) object.getClass().getPackage();
2227+
// String objectPackageName = //objectPackage != null ? objectPackage.getName()
2228+
// : "";
22282229
// if (objectPackageName.startsWith("java.") || objectPackageName.startsWith("javax.")
22292230
// || object.getClass().getClassLoader() == null) {
22302231
String className = object.getClass().getName();
@@ -2254,32 +2255,6 @@ static final Writer writeValue(Writer writer, Object value, int indentFactor, in
22542255
throws JSONException, IOException {
22552256
if (value == null || value.equals(null)) {
22562257
writer.write("null");
2257-
} else if (value instanceof JSONString) {
2258-
Object o;
2259-
try {
2260-
o = ((JSONString) value).toJSONString();
2261-
} catch (Exception e) {
2262-
throw new JSONException(e);
2263-
}
2264-
writer.write(o != null ? o.toString() : quote(value.toString()));
2265-
} else if (value instanceof Number) {
2266-
// not all Numbers may match actual JSON Numbers. i.e. fractions or Imaginary
2267-
final String numberAsString = numberToString((Number) value);
2268-
try {
2269-
// Use the BigDecimal constructor for its parser to validate the format.
2270-
@SuppressWarnings("unused")
2271-
BigDecimal testNum = new BigDecimal(numberAsString);
2272-
// Close enough to a JSON number that we will use it unquoted
2273-
writer.write(numberAsString);
2274-
} catch (NumberFormatException ex) {
2275-
// The Number value is not a valid JSON number.
2276-
// Instead we will quote it as a string
2277-
quote(numberAsString, writer);
2278-
}
2279-
} else if (value instanceof Boolean) {
2280-
writer.write(value.toString());
2281-
} else if (value instanceof Enum<?>) {
2282-
writer.write(quote(((Enum<?>) value).name()));
22832258
} else if (value instanceof JSONObject) {
22842259
((JSONObject) value).write(writer, indentFactor, indent);
22852260
} else if (value instanceof JSONArray) {
@@ -2293,7 +2268,7 @@ static final Writer writeValue(Writer writer, Object value, int indentFactor, in
22932268
} else if (value.getClass().isArray()) {
22942269
new JSONArray(value).write(writer, indentFactor, indent);
22952270
} else {
2296-
quote(value.toString(), writer);
2271+
writer.write(JSONWriter.valueToString(value));
22972272
}
22982273
return writer;
22992274
}

sources/net.sf.j2s.java.core/src/org/json/JSONWriter.java

Lines changed: 46 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import java.io.IOException;
44
import java.math.BigDecimal;
5+
import java.math.BigInteger;
56
import java.util.Collection;
67
import java.util.Map;
78

@@ -339,18 +340,9 @@ public static String valueToString(Object value) throws JSONException {
339340
}
340341
if (value instanceof Number) {
341342
// not all Numbers may match actual JSON Numbers. i.e. Fractions or Complex
342-
final String numberAsString = JSONObject.numberToString((Number) value);
343-
try {
344-
// Use the BigDecimal constructor for it's parser to validate the format.
345-
@SuppressWarnings("unused")
346-
BigDecimal unused = new BigDecimal(numberAsString);
347-
// Close enough to a JSON number that we will return it unquoted
348-
return numberAsString;
349-
} catch (NumberFormatException ex){
350-
// The Number value is not a valid JSON number.
351-
// Instead we will quote it as a string
352-
return JSONObject.quote(numberAsString);
353-
}
343+
// this next call throws an error for nonfinite or isNaN Double or Float
344+
final String s = JSONObject.numberToString((Number) value);
345+
return (JSONWriter.isNumberOK(value, s) ? s : JSONObject.quote(s));
354346
}
355347
if (value instanceof Boolean || value instanceof JSONObject
356348
|| value instanceof JSONArray) {
@@ -415,4 +407,46 @@ public JSONWriter value(long l) throws JSONException {
415407
public JSONWriter value(Object object) throws JSONException {
416408
return this.append(valueToString(object));
417409
}
410+
411+
/**
412+
* Added for SwingJS
413+
*
414+
* @param value
415+
* @param s
416+
* @return
417+
* @author hansonr@stolaf.edu Bob Hanson
418+
*/
419+
public static boolean isNumberOK(Object value, String s) {
420+
if (value instanceof BigInteger) {
421+
try {
422+
long l = Long.parseLong(s);
423+
return (l <= 9007199254740991L && l >= -9007199254740991L);
424+
// JavaScript Number.MAX_SAFE_INTEGER and JavaScript.Number.MIN_SAFE_INTEGER
425+
} catch (NumberFormatException e) {
426+
}
427+
return false;
428+
}
429+
if (value instanceof BigDecimal) {
430+
double d = Double.parseDouble(s);
431+
return Double.isFinite(d) && (s.indexOf("E-") < 0 || d != 0);
432+
433+
// SwingJS No! This is a huge performance hit, and it is wrong.
434+
// It makes no sense to take an Integer, Long, BigDecimal or BigInteger and just
435+
// turn it back into
436+
// BigDecimal to see if it parses. We already know it is finite. Why would it
437+
// not parse?
438+
// try {
439+
// // Use the BigDecimal constructor for its parser to validate the format.
440+
// @SuppressWarnings("unused")
441+
// BigDecimal testNum = new BigDecimal(numberAsString);
442+
// // Close enough to a JSON number that we will use it unquoted
443+
// writer.write(numberAsString);
444+
// } catch (NumberFormatException ex) {
445+
// // The Number value is not a valid JSON number.
446+
// // Instead we will quote it as a string
447+
// quote(numberAsString, writer);
448+
// }
449+
}
450+
return true;
451+
}
418452
}

0 commit comments

Comments
 (0)