【问题标题】:How can JSONObject.toString(int) throw JSONException?JSONObject.toString(int) 如何抛出 JSONException?
【发布时间】:2015-11-11 10:53:47
【问题描述】:

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

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

如果事先进行了 NaN/Infinity 检查(在解析时和在 .put("blah", Double.NAN) 之类的语句中,对象怎么可能包含无效数字? 哪些语句会引发该异常?

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

那么,什么时候应该期望 .toString(int) 抛出异常,应该如何处理呢?

【问题讨论】:

  • 我不确定,但如果indentFactor <= 0 会引发异常
  • 我认为这与parameter 无关,但与您正在调用toString()object 有关。如果 JSONObject 中包含无效数字,那么它会抛出异常......
  • 在 JSONObject 的早​​期版本中,可能会创建一个无效的结构,并且只有在打印出来时才会出错。在较新版本中创建此结构时添加验证后,他们要么忘记从 toString(int) 中删除此 @throws,要么从一开始就忘记添加到 toString()

标签: java json jsonexception


【解决方案1】:

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 cmets)中所说的那样,所有检查都是在创建对象时执行的,那么toString(int) 方法可能永远不会引发异常。

希望对你有帮助,

【讨论】:

    【解决方案2】:

    看看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 子句中释放出来可能会更好。

    【讨论】:

      【解决方案3】:

      我刚遇到这个问题。

      下面是一个示例,它会导致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() 方法抛出,但显然这里没有进行检查...

      【讨论】:

        猜你喜欢
        • 2013-05-09
        • 1970-01-01
        • 2023-01-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多