Search code examples
javajsonjsonexception

How can JSONObject.toString(int) throw JSONException?


I noticed this in the JSONObject.toString(int) documentation

Throws: JSONException - If the object contains an invalid number.

How could the object contain an invalid number if the NaN/Infinity check is done beforehand (either at parsing and in statements like .put("blah", Double.NAN) ? Which statements would throw that exception?

I also read in the docs that .toString() without args doesn't throw anything, so I thought that the exception could be related to the integer passed as parameter; but even with zero, negative or Integer.MAX/MIN_VALUE it still works.

So when one should expect .toString(int) to throw an exception and how should one handle that?


Solution

  • toString() method not throws an exception because it has to override a signature of public void toString() method of java.lang.Object. In org.json.JSONObject generic toString() method actually fails silently since the source code is:

    /**
     * Make a JSON text of this JSONObject. For compactness, no whitespace is
     * added. If this would not result in a syntactically correct JSON text,
     * then null will be returned instead.
     * <p>
     * Warning: This method assumes that the data structure is acyclical.
     *
     * @return a printable, displayable, portable, transmittable representation
     *         of the object, beginning with <code>{</code>&nbsp;<small>(left
     *         brace)</small> and ending with <code>}</code>&nbsp;<small>(right
     *         brace)</small>.
     */
    public String toString() {
        try {
            return this.toString(0);
        } catch (Exception e) {
            return null;
        }
    }
    

    This method relies on toString(int) method, and in case that it throws the exception, it catch it and returns null.

    According to the toString(int) description, the exception is thrown when org.json.JSONObject has an invalid number inside one of its elements; but looking at code could be possible that this exception is thrown for other reasons.

    When you use toString(int) the stack trace finally calls write() method to parse the object itself, the exception could be thrown for some of transformations from json objects to string:

    static final Writer writeValue(Writer writer, Object value,
                int indentFactor, int indent) throws JSONException, IOException {
            if (value == null || value.equals(null)) {
                writer.write("null");
            } else if (value instanceof JSONObject) {
                ((JSONObject) value).write(writer, indentFactor, indent);
            } else if (value instanceof JSONArray) {
                ((JSONArray) value).write(writer, indentFactor, indent);
            } else if (value instanceof Map) {
                new JSONObject((Map<String, Object>) value).write(writer, indentFactor, indent);
            } else if (value instanceof Collection) {
                new JSONArray((Collection<Object>) value).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);
            }
            return writer;
        }
    

    However if as you said in your question (and @Carlos Rodriguez comments) all the checks are performed when the object is created, probably toString(int) method never thrown an exception.

    Hope it helps,