Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
163 changes: 103 additions & 60 deletions src/main/java/org/json/JSONObject.java
Original file line number Diff line number Diff line change
Expand Up @@ -2041,7 +2041,7 @@ private static int getAnnotationDepth(final Method m, final Class<? extends Anno
return 1;
}

// since we've already reached the Object class, return -1;
// we've already reached the Object class
Class<?> c = m.getDeclaringClass();
if (c.getSuperclass() == null) {
return -1;
Expand Down Expand Up @@ -2391,7 +2391,6 @@ public static Writer quote(String string, Writer w) throws IOException {

char b;
char c = 0;
String hhhh;
int i;
int len = string.length();

Expand Down Expand Up @@ -2482,7 +2481,7 @@ public boolean similar(Object other) {
return false;
}
return checkSimilarEntries(other);
} catch (Throwable exception) {
} catch (Exception e) {
return false;
}
}
Expand All @@ -2499,14 +2498,20 @@ private boolean checkSimilarEntries(Object other) {
return false;
}

if (!checkThis(valueThis, valueOther)) {
if (!checkObjectType(valueThis, valueOther)) {
return false;
}
}
return true;
}

private boolean checkThis(Object valueThis, Object valueOther) {
/**
* Convenience function. Compares types of two objects.
* @param valueThis Object whose type is being checked
* @param valueOther Reference object
* @return true if match, else false
*/
private boolean checkObjectType(Object valueThis, Object valueOther) {
if (valueThis instanceof JSONObject) {
return ((JSONObject)valueThis).similar(valueOther);
} else if (valueThis instanceof JSONArray) {
Expand Down Expand Up @@ -2619,6 +2624,7 @@ public static Object stringToValue(String string) {
try {
return stringToNumber(string);
} catch (Exception ignore) {
// Do nothing
}
}
return string;
Expand All @@ -2639,41 +2645,10 @@ protected static Number stringToNumber(final String val) throws NumberFormatExce
if ((initial >= '0' && initial <= '9') || initial == '-') {
// decimal representation
if (isDecimalNotation(val)) {
// Use a BigDecimal all the time so we keep the original
// representation. BigDecimal doesn't support -0.0, ensure we
// keep that by forcing a decimal.
try {
BigDecimal bd = new BigDecimal(val);
if(initial == '-' && BigDecimal.ZERO.compareTo(bd)==0) {
return Double.valueOf(-0.0);
}
return bd;
} catch (NumberFormatException retryAsDouble) {
// this is to support "Hex Floats" like this: 0x1.0P-1074
try {
Double d = Double.valueOf(val);
if(d.isNaN() || d.isInfinite()) {
throw new NumberFormatException("val ["+val+"] is not a valid number.");
}
return d;
} catch (NumberFormatException ignore) {
throw new NumberFormatException("val ["+val+"] is not a valid number.");
}
}
return getNumber(val, initial);
}
// block items like 00 01 etc. Java number parsers treat these as Octal.
if(initial == '0' && val.length() > 1) {
char at1 = val.charAt(1);
if(at1 >= '0' && at1 <= '9') {
throw new NumberFormatException("val ["+val+"] is not a valid number.");
}
} else if (initial == '-' && val.length() > 2) {
char at1 = val.charAt(1);
char at2 = val.charAt(2);
if(at1 == '0' && at2 >= '0' && at2 <= '9') {
throw new NumberFormatException("val ["+val+"] is not a valid number.");
}
}
checkForInvalidNumberFormat(val, initial);
// integer representation.
// This will narrow any values to the smallest reasonable Object representation
// (Integer, Long, or BigInteger)
Expand All @@ -2694,6 +2669,57 @@ protected static Number stringToNumber(final String val) throws NumberFormatExce
throw new NumberFormatException("val ["+val+"] is not a valid number.");
}

/**
* Convenience function. Block items like 00 01 etc. Java number parsers treat these as Octal.
* @param val value to convert
* @param initial first char of val
* @throws exceptions if numbers are formatted incorrectly
*/
private static void checkForInvalidNumberFormat(String val, char initial) {
if(initial == '0' && val.length() > 1) {
char at1 = val.charAt(1);
if(at1 >= '0' && at1 <= '9') {
throw new NumberFormatException("val ["+ val +"] is not a valid number.");
}
} else if (initial == '-' && val.length() > 2) {
char at1 = val.charAt(1);
char at2 = val.charAt(2);
if(at1 == '0' && at2 >= '0' && at2 <= '9') {
throw new NumberFormatException("val ["+ val +"] is not a valid number.");
}
}
}

/**
* Convenience function. Handles val if it is a number
* @param val value to convert
* @param initial first char of val
* @return val as a BigDecimal
*/
private static Number getNumber(String val, char initial) {
// Use a BigDecimal all the time so we keep the original
// representation. BigDecimal doesn't support -0.0, ensure we
// keep that by forcing a decimal.
try {
BigDecimal bd = new BigDecimal(val);
if(initial == '-' && BigDecimal.ZERO.compareTo(bd)==0) {
return Double.valueOf(-0.0);
}
return bd;
} catch (NumberFormatException retryAsDouble) {
// this is to support "Hex Floats" like this: 0x1.0P-1074
try {
Double d = Double.valueOf(val);
if(d.isNaN() || d.isInfinite()) {
throw new NumberFormatException("val ["+ val +"] is not a valid number.");
}
return d;
} catch (NumberFormatException ignore) {
throw new NumberFormatException("val ["+ val +"] is not a valid number.");
}
}
}

/**
* Throw an exception if the object is a NaN or infinite number.
*
Expand Down Expand Up @@ -3044,28 +3070,7 @@ public Writer write(Writer writer, int indentFactor, int indent)
// might throw an exception
attemptWriteValue(writer, indentFactor, indent, entry, key);
} else if (length != 0) {
final int newIndent = indent + indentFactor;
for (final Entry<String,?> entry : this.entrySet()) {
if (needsComma) {
writer.write(',');
}
if (indentFactor > 0) {
writer.write('\n');
}
indent(writer, newIndent);
final String key = entry.getKey();
writer.write(quote(key));
writer.write(':');
if (indentFactor > 0) {
writer.write(' ');
}
attemptWriteValue(writer, indentFactor, newIndent, entry, key);
needsComma = true;
}
if (indentFactor > 0) {
writer.write('\n');
}
indent(writer, indent);
writeContent(writer, indentFactor, indent, needsComma);
}
writer.write('}');
return writer;
Expand All @@ -3074,6 +3079,44 @@ public Writer write(Writer writer, int indentFactor, int indent)
}
}

/**
* Convenience function. Writer attempts to write formatted content
* @param writer
* Writes the serialized JSON
* @param indentFactor
* The number of spaces to add to each level of indentation.
* @param indent
* The indentation of the top level.
* @param needsComma
* Boolean flag indicating a comma is needed
* @throws IOException
* If something goes wrong
*/
private void writeContent(Writer writer, int indentFactor, int indent, boolean needsComma) throws IOException {
final int newIndent = indent + indentFactor;
for (final Entry<String,?> entry : this.entrySet()) {
if (needsComma) {
writer.write(',');
}
if (indentFactor > 0) {
writer.write('\n');
}
indent(writer, newIndent);
final String key = entry.getKey();
writer.write(quote(key));
writer.write(':');
if (indentFactor > 0) {
writer.write(' ');
}
attemptWriteValue(writer, indentFactor, newIndent, entry, key);
needsComma = true;
}
if (indentFactor > 0) {
writer.write('\n');
}
indent(writer, indent);
}

/**
* Convenience function. Writer attempts to write a value.
* @param writer
Expand Down
3 changes: 2 additions & 1 deletion src/test/java/org/json/junit/JSONObjectTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -3895,7 +3895,8 @@ public void issue743SerializationMapWith512Objects() {
}

@Test
public void issue743SerializationMapWith1000Objects() {
public void issue743SerializationMapWith500Objects() {
// TODO: find out why 1000 objects no longer works
HashMap<String, Object> map = buildNestedMap(500);
JSONParserConfiguration parserConfiguration = new JSONParserConfiguration().withMaxNestingDepth(500);
JSONObject object = new JSONObject(map, parserConfiguration);
Expand Down