1
0
Fork 0
mirror of https://github.com/ethauvin/JSON-java.git synced 2025-06-17 07:50:52 -07:00

Fix for number output bug.

java.lang.Number is currently output without any validation. For all java.* Numbers, this is fine, but for custom Number implementations like Complex or Fraction, the resulting JSON output may be invalid.

For example: If a Fraction implementation defines its' toString method as `return numerator + "/" + denominator`, then the resulting JSON output would be something like this:

```json
{ "fraction" : 1/2 }
```

This is not valid JSON.

This commit verifies that the string representation of the number is close to a JSON formatted number by use of the BigDecimal constructor. If the constructor throws a NumberFormatException, then the string value is instead quoted as a string. The example above would instead output like the following:

```json
{ "fraction" : "1/2" }
```
This commit is contained in:
John J. Aylward 2016-08-17 12:52:04 -04:00
parent 7232a95c0b
commit 2f2cd4dfc5

View file

@ -838,7 +838,7 @@ public class JSONObject {
}
testValidity(number);
// Shave off trailing zeros and decimal point, if possible.
// Shave off trailing zeros and decimal point, if possible.
String string = number.toString();
if (string.indexOf('.') > 0 && string.indexOf('e') < 0
@ -1693,7 +1693,18 @@ public class JSONObject {
throw new JSONException("Bad value from toJSONString: " + object);
}
if (value instanceof Number) {
return numberToString((Number) value);
// not all Numbers may match actual JSON Numbers. i.e. Fractions or Complex
final String numberAsString = numberToString((Number) value);
try {
// Use the BigDecimal constructor for it's parser to validate the format.
new BigDecimal(numberAsString);
// Close enough to a JSON number that we will return it unquoted
return numberAsString;
} catch (NumberFormatException ex){
// The Number value is not a valid JSON number.
// Instead we will quote it as a string
return quote(numberAsString);
}
}
if (value instanceof Boolean || value instanceof JSONObject
|| value instanceof JSONArray) {
@ -1783,6 +1794,30 @@ public class JSONObject {
int indentFactor, int indent) throws JSONException, IOException {
if (value == null || value.equals(null)) {
writer.write("null");
} else if (value instanceof JSONString) {
Object o;
try {
o = ((JSONString) value).toJSONString();
} catch (Exception e) {
throw new JSONException(e);
}
writer.write(o != null ? o.toString() : quote(value.toString()));
} else if (value instanceof Number) {
// not all Numbers may match actual JSON Numbers. i.e. fractions or Imaginary
final String numberAsString = numberToString((Number) value);
try {
// Use the BigDecimal constructor for it's parser to validate the format.
@SuppressWarnings("unused")
BigDecimal testNum = new BigDecimal(numberAsString);
// Close enough to a JSON number that we will use it unquoted
writer.write(numberAsString);
} catch (NumberFormatException ex){
// The Number value is not a valid JSON number.
// Instead we will quote it as a string
quote(numberAsString, writer);
}
} else if (value instanceof Boolean) {
writer.write(value.toString());
} else if (value instanceof JSONObject) {
((JSONObject) value).write(writer, indentFactor, indent);
} else if (value instanceof JSONArray) {
@ -1795,18 +1830,6 @@ public class JSONObject {
new JSONArray(coll).write(writer, indentFactor, indent);
} else if (value.getClass().isArray()) {
new JSONArray(value).write(writer, indentFactor, indent);
} else if (value instanceof Number) {
writer.write(numberToString((Number) value));
} else if (value instanceof Boolean) {
writer.write(value.toString());
} else if (value instanceof JSONString) {
Object o;
try {
o = ((JSONString) value).toJSONString();
} catch (Exception e) {
throw new JSONException(e);
}
writer.write(o != null ? o.toString() : quote(value.toString()));
} else {
quote(value.toString(), writer);
}