Groovy解析嵌套JSON遍历后仅返回最后一个对象问题排查
问题描述
- 场景:使用Groovy脚本解析嵌套JSON数据,源JSON顶层包含
merchant_id字段,以及两个同名update_product_request数组节点:第一个节点store_id值为Store_ID1,第二个节点store_id值为Store_ID2;每个update_product_request节点下嵌套update_product_request_list商品数组,数组元素包含quantity、bar_code、product_identifier、original_price、sale_price、uom、currency、size、weight_type等商品属性字段。 - 原实现逻辑:遵循SAP CPI自定义脚本规范编写处理代码,引入
JsonSlurper解析JSON文本、JsonOutput序列化输出处理结果;原计划通过两层each嵌套循环遍历所有update_product_request下的商品条目,对quantity、original_price、sale_price三个字段做空值判断、格式清洗与数值类型转换。 - 异常现象:脚本执行后输出结果仅保留
store_id为Store_ID2的update_product_request节点,Store_ID1对应节点完全丢失,不符合保留两个update_product_request节点的预期;多次调整循环写法均未解决问题,初步判断遍历逻辑存在错误,未正确覆盖所有集合元素。
故障根因
该问题90%以上的诱因是遍历过程中错误覆盖了顶层update_product_request的数组引用:
- 编写循环时如果在
each遍历块内直接执行jsonMap.update_product_request = 当前遍历到的单个requestNode这类赋值操作,会把原本是数组类型的顶层字段直接覆盖为单个节点对象,循环执行完后字段值就只剩最后一次遍历到的Store_ID2节点。 - 另一类常见错误是新建临时存储集合时作用域错误,把集合初始化写在了循环内部,导致每次遍历都会重置集合,最终也只会存入最后一次遍历的节点数据。
修复代码(适配SAP CPI自定义脚本规范)
import com.sap.gateway.ip.core.customdev.util.Message import groovy.json.JsonSlurper import groovy.json.JsonOutput def Message processData(Message message) { // 读取报文体并解析为Map结构 String rawBody = message.getBody(String) def rootJson = new JsonSlurper().parseText(rawBody) // 关键:先获取完整的update_product_request数组,不要在遍历中覆盖该引用 List updateRequestNodes = rootJson.update_product_request as List // 遍历所有门店请求节点 updateRequestNodes.each { currentRequest -> // 获取当前节点下的商品列表 List productList = currentRequest.update_product_request_list as List productList.each { currentProduct -> // 数值字段空值兜底+格式清洗+类型转换 currentProduct.quantity = currentProduct.quantity?.toString()?.isBigDecimal() ? currentProduct.quantity.toString().toBigDecimal() : BigDecimal.ZERO currentProduct.original_price = currentProduct.original_price?.toString()?.isBigDecimal() ? currentProduct.original_price.toString().toBigDecimal() : BigDecimal.ZERO currentProduct.sale_price = currentProduct.sale_price?.toString()?.isBigDecimal() ? currentProduct.sale_price.toString().toBigDecimal() : BigDecimal.ZERO } } // 序列化处理后的结构写回报文 message.setBody(JsonOutput.toJson(rootJson)) return message }
编写注意事项
- 遍历数组节点前统一强转为
List类型,避免JsonSlurper在数组只有单个元素时自动解析为Object类型,导致后续遍历逻辑失效 - 所有字段修改直接在解析得到的原Map结构对应节点上操作,不要在循环过程中反复给顶层数组字段赋值单个节点对象
- 如果需要做节点过滤,必须在循环外部初始化结果List,遍历过程中将处理完成的节点逐个add进结果集,循环结束后再一次性赋值给顶层字段
- 涉及数值转换优先使用
BigDecimal类型,避免SAP CPI后续处理金额、库存字段时出现浮点数精度问题
内容的提问来源于stack exchange,提问作者AKASH SHRIVASTAVA
相关产品推荐
相关产品推荐

