JSONObject.toString(int)如何抛出JSONException?

时间:2015-08-18 13:13:16

标签: java json jsonexception

我在JSONObject.toString(int)文档中注意到了这一点

  

抛出:JSONException - 如果对象包含无效的数字。

如果事先完成NaN / Infinity检查(在解析时和.put("blah", Double.NAN)之类的语句中,对象如何包含无效数字? 哪个陈述会抛出该异常?

我还在文档中读到.toString()没有args不会抛出任何东西,所以我认为异常可能与作为参数传递的整数有关;但即使有零,负或Integer.MAX / MIN_VALUE,它仍然有效。

所以当人们期望.toString(int)抛出异常时应该如何处理它?<​​/ p>

3 个答案:

答案 0 :(得分:2)

toString()方法不会抛出异常,因为它必须覆盖public void toString() java.lang.Object方法的签名。在org.json.JSONObject泛型toString()方法实际上无声地失败,因为源代码是:

/**
 * 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;
    }
}

此方法依赖于toString(int)方法,如果它抛出异常,它会捕获它并返回null。

根据toString(int)描述,当org.json.JSONObject在其中一个元素中包含无效数字时,抛出异常;但是查看代码可能会因为其他原因而抛出此异常。

当您使用toString(int)时,堆栈跟踪最终调用write()方法来解析对象本身,对于从json对象到字符串的一些转换,可能抛出异常:

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;
    }

但是,正如您在问题中所说(以及@Carlos Rodriguez评论)所有检查都是在创建对象时执行的,可能toString(int)方法永远不会抛出异常。

希望它有所帮助,

答案 1 :(得分:1)

有助于查看JSONObject.toString(int)JSONObject.toString()的实施情况:

public String toString(int indentFactor) throws JSONException {
    StringWriter w = new StringWriter();
    synchronized (w.getBuffer()) {
        return this.write(w, indentFactor, 0).toString();
    }
} 

write方法写入Writer并将任何IOException重新抛出为JSONException。如果你的分析是正确的,那么这样的IOException永远不会发生,因为StringWriters也不会抛出IOExceptions。所以这似乎只是一个实现决定让这个方法抛出一个JSONException并且文档有误导性。

public String toString() {
    try {
        return this.toString(0);
    } catch (Exception e) {
        return null;
    }
} 

toString()实现证实了这一分析:API设计者决定捕获任何异常,只有在异常永远不会抛出时才会有意义。

try-catch移动到toString(int)以从签名中的throw子句释放两个方法可能会更好。

答案 2 :(得分:0)

我刚遇到这个问题。

以下示例将导致JSONObject.toString(int)方法抛出JSONException

public static void main(String[] args) {
    Map<String, Double> map = new HashMap<>();
    map.put("num", Double.NaN);
    JSONObject obj = new JSONObject();
    obj.put("map", map);
    obj.toString(0);
}

在我看来,JSONObject.put()方法应该抛出异常,但显然没有在这里进行检查......

相关问题