DEBUG.WIKI
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国
PanstarCloud:部署应用,接入 AI,云服务器与 AI 网关
OnlineSIM:在线接收短信,虚拟号码租用

Spring 展平空 YAML 得到 null 属性名:只过滤空根

Spring 7.0.9 的 YamlProcessor 在 includeEmpty=true 时,把空根映射展平成 null 键;7.0.10 仍有该分支。自有加载器只对空根返回空结果,保留嵌套空节点和多文档语义。

application.yml 只有一个 {} 文档,枚举属性名却得到包含 null 的数组;自定义 YAML 展平器也可能得到 {null=""}。若使用 Spring 的 getFlattenedMap(source, true, emptyValue),应检查“保留空值”分支是否把空根映射也当成了有父路径的节点。

Spring Framework 7.0.9 有这条具体表现,7.0.10 正式实现仍在空映射分支直接以 path 作键。普通 getFlattenedMap(source) 对同一输入返回空 map;不能把它扩大成所有 YAML 文件或所有空值都会产生 null 键。

根没有父路径,嵌套空节点却有名字

该方法从 path 为 null 的根开始递归。includeEmpty 为 true 且 source 为空时,它把 emptyValue 记到当前 path 下;根上于是得到 null 键。嵌套结构则不同,例如 feature: {} 的路径是 feature,记录这个空节点本来可能就是调用方需要的语义。

因此,不能为了消除一个 null 键,就把所有空 map、空字符串、空集合和 YAML null 都删除。它们可能影响配置覆盖或绑定,尤其是在多文档、profile 与外部配置叠加时。

先确认 null 出现在解析后的根展平结果,而非业务代码自己构造的属性源。涉及 Spring Boot 4.1 的配置入口时,还应核对实际使用的 Framework 依赖;文件叫 application.yml,并不代表不同 Boot 代际采用相同的展平方法。

自有展平器只对空根做判断

如果调用点属于应用自己的 YamlProcessor 子类,可以在调用受影响重载前,专门把空根返回为空结果。例如下面位于子类已有解析回调中,source 是这次文档解析得到的根 map:

Map<String, Object> flattened = source.isEmpty()
        ? new LinkedHashMap<>()
        : getFlattenedMap(source, true, "");

片段使用 java.util.Map 与 java.util.LinkedHashMap;后续仍沿用原有属性源构造流程。它没有修改递归方法,因此非空文档中的嵌套空节点继续按原来的 includeEmpty 规则处理。若原来使用不同 emptyValue,也要保留该值。

普通重载不保留相同的空映射语义,只能在业务确实不需要这些信息时评估替换。不能看见它没有 null 键,就对所有自定义加载器批量换方法。

无法控制 Boot 内部调用时,先检查生成配置的环节是否输出了纯空根文档。确认该文档没有配置、激活条件或其他需要保留的用途后,可在生成端避免产出这段 {}。不要顺手删掉同一文件中的其他文档、分隔符及 profile 条件,也不要给属性源伪造一个名为 "null" 的属性。

验收分别覆盖纯空根、正常键值、嵌套空 map、空集合及显式 null,并检查多文档覆盖与实际配置绑定。空根不应贡献 null 属性名,嵌套节点的原有语义也不能丢。后续切换正式框架版本时,仍用这些输入确认行为,不把升级动作本身当作已经消除空键。