无JSONSlurper的Groovy JSON与YAML合并:ArrayList处理及引用问题
Jenkins中LinkedHashMap递归合并的原理解析与优化
一、递归合并函数的核心执行逻辑
你用readJSON拿到的LinkedHashMap,本质是Groovy基于Java实现的键值对容器,递归合并函数的核心逻辑是以原JSON的Map为基础,用YAML配置的Map逐层覆盖/补充,执行流程如下:
- 遍历YAML配置Map(override)的每一个键值对
- 检查原JSON Map(base)中是否存在相同的键:
- 如果键对应的值都是Map类型,就递归调用合并函数处理这两个子Map,把返回的新Map存入结果
- 如果是字符串、数字等普通类型,直接用YAML的值覆盖原JSON的值
- 如果是List类型,需要单独做结构保留处理(这也是你原函数出问题的核心点)
你之前疑惑的「传入两个Map后如何循环?结果如何存入result?两个Map如何关联?」,其实是函数先创建一个基于base的结果容器(或直接操作base),然后循环override的所有键,通过相同键关联两个Map的内容,把处理后的键值对逐个放入result中,用override的内容更新base的对应项。
二、原函数ArrayList丢失方括号的问题解析
你遇到的WriteTo后方法括号丢失,本质是原函数没有正确识别List类型,导致List结构被破坏:
- 比如原函数可能没有判断值是否为
ArrayList,直接把YAML中的List元素当成单个值赋值,或者错误地对List执行了Map的遍历操作(List没有键,遍历会直接拆解元素) - 举个例子:如果原JSON中
WriteTo是["file1.txt"],YAML中是["file2.txt"],原函数如果没处理List类型,可能会把值改成file2.txt(去掉方括号,变成字符串类型)
三、引用传递导致原变量被修改的原因及优化方案
Groovy中对象(比如LinkedHashMap、ArrayList)是引用传递,如果你的修改后的函数直接操作base的元素(比如base.put(key, value)),就会直接改变原输入变量的值——因为你操作的是同一个内存地址的对象。
优化后的递归合并函数
下面是避免修改原变量、正确处理List的优化版本:
def mergeMaps(def base, def override) { // 创建新的LinkedHashMap,基于base的副本,彻底隔离原对象 def result = new LinkedHashMap(base) override.each { key, value -> if (result.containsKey(key)) { def baseValue = result.get(key) // 嵌套Map递归合并 if (baseValue instanceof Map && value instanceof Map) { result.put(key, mergeMaps(baseValue, value)) } // List处理:此处为合并两个List元素,若需替换可改为new ArrayList(value) else if (baseValue instanceof List && value instanceof List) { def mergedList = new ArrayList(baseValue) mergedList.addAll(value) result.put(key, mergedList) } // 普通类型直接覆盖 else { result.put(key, value) } } else { // base中没有的键直接添加到结果 result.put(key, value) } } return result }
优化点说明
- 隔离原对象:每次合并都创建新的
LinkedHashMap和ArrayList,所有操作都在新对象上进行,彻底避免修改原输入变量 - 明确List处理策略:根据业务需求选择合并(
addAll)或替换(直接赋值新List),确保List结构不会丢失 - 类型安全校验:通过
instanceof判断值的类型,避免因类型不匹配导致的异常或结构错误 - 无副作用:函数执行后,原base和override变量不会被修改,符合纯函数的设计原则
额外建议
- 如果需要处理空值场景,可以在函数开头添加判断:比如
if (!base) return new LinkedHashMap(override),避免空指针异常 - 若YAML中的List是要完全替换原JSON的List,把List处理部分改成
result.put(key, new ArrayList(value))即可
内容的提问来源于stack exchange,提问作者dejavized
相关产品推荐
相关产品推荐

