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
相关产品推荐
相关产品推荐

