You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java XML转JSON时JSONObject类型异常及转JSONArray处理方案

问题根因分析

两个报错的核心原因都是JSON类型判断逻辑不可靠,没有适配XML转JSON的自动类型转换特性:

  • 抛出JSONObject["Root"] is not a JSONObject是因为XML.toJSONObject()的默认转换规则:当Root节点没有属性、没有嵌套子元素、仅包含纯文本内容或者是空节点的特殊场景下,转换后Root对应的值会是字符串类型而非JSONObject,直接调用getJSONObject("Root")就会抛类型不匹配异常。
  • JSONObject转JSONArray报错是因为AmountDtl节点的数量不固定:当查询结果只有1条明细时,AmountDtl会被转成JSONObject类型;有多条明细时才会转成JSONArray类型,原代码直接强转、靠判断toString结果是否包含[识别数组的逻辑完全不可靠——如果字段值本身包含[字符就会误判,直接强转必然报错。
异常处理规范

要避免这类报错,异常捕获和类型处理要遵循以下规则:

  • 不要直接捕获顶层Exception吞掉所有错误,优先捕获JSONException、XML解析相关的特定异常,日志记录要保留完整异常栈,不要只截取异常信息字符串,方便定位根因。
  • 所有从JSON结构中取值的操作,禁止直接调用getJSONObject()/getJSONArray()或者强制类型转换,先取出Object类型的值,用instanceof判断实际类型后再做对应处理。
  • 禁止用字符串包含特殊字符的方式判断JSON类型,这类逻辑会被字段值本身的内容干扰,稳定性极差。
  • 空节点、空值场景提前做判空兜底,不要依赖异常捕获走业务兜底逻辑。
代码修正方案

修正后的完整逻辑如下,核心是补全类型判断,去掉不可靠的字符串识别数组逻辑:

private String getExpenseDtl() {
    CommonDO commonDO = new CommonDO(this.ou);
    HttpServletRequest request = ServletActionContext.getRequest();
    JSONArray headerFormat = null;
    String getData = "~";
    try {
        // 实际场景替换为SQL返回的XML结果
        getData = "<Root></Root>";
        if (!"~".equals(getData) && !"".equals(getData) && !"<Root/>".equals(getData)) {
            JSONObject xmlJSONObj = XML.toJSONObject(getData);
            // 先判断Root节点存在,且值为JSONObject类型
            if (xmlJSONObj.has("Root") && xmlJSONObj.get("Root") instanceof JSONObject) {
                JSONObject rootObj = xmlJSONObj.getJSONObject("Root");
                // 判断AmountDtl节点存在
                if (rootObj.has("AmountDtl")) {
                    Object amountDtlVal = rootObj.get("AmountDtl");
                    // 按实际类型处理,不依赖字符串判断
                    if (amountDtlVal instanceof JSONArray) {
                        headerFormat = (JSONArray) amountDtlVal;
                    } else if (amountDtlVal instanceof JSONObject) {
                        // 单条对象场景,包装为单元素数组
                        headerFormat = new JSONArray();
                        headerFormat.put(amountDtlVal);
                    } else {
                        // 纯值、空值场景,根据业务需求处理,这里按空数组兜底
                        headerFormat = new JSONArray();
                    }
                }
            }
            request.setAttribute("amountDetailsData", headerFormat);
            return "expense";
        }
        // 空结果场景兜底
        request.setAttribute("amountDetailsData", "~");
    } catch (JSONException e) {
        // JSON解析、类型转换异常单独捕获,记录完整日志
        System.out.println("[" + new Date().toString() + "] JSON处理异常: " + e.getMessage());
        String errMsg = e.toString().replaceAll("[^\\w\\s]", "");
        commonDO.insertLogDetails(errMsg);
        request.setAttribute("amountDetailsData", "~");
    } catch (Exception e) {
        // 其他未知异常兜底
        System.out.println("[" + new Date().toString() + "] 系统异常: " + e.getMessage());
        String errMsg = e.toString().replaceAll("[^\\w\\s]", "");
        commonDO.insertLogDetails(errMsg);
        request.setAttribute("amountDetailsData", "~");
    }
    return "expense";
}

补充优化点:如果使用的是org.json 2020版本以上的依赖,可以在调用XML.toJSONObject()前通过配置关闭节点自动转字符串的逻辑,进一步降低类型判断复杂度:

XMLParserConfiguration config = XMLParserConfiguration.KEEP_STRINGS;
JSONObject xmlJSONObj = XML.toJSONObject(getData, config);

内容的提问来源于stack exchange,提问作者RNK

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 04:27:18