Jackson 3.2 读取空 Locale 键,在 Java 25 报 Empty subtag
Map 的空字符串键对应 Locale.ROOT,升级 Jackson 后却在 Java 25 解析失败。核对单段 Locale 的读取路径,再采用已包含修正的正式版本。
原来能读取的 Map<Locale, String>,升级 Jackson 3.2.3 后遇到空字符串键就失败,异常包含 IllformedLocaleException 和 Empty subtag。同一输入在 Java 25 与 Java 26 表现不同,应先检查空键是否表达 Locale.ROOT,而不是直接删掉这项数据。
Locale.ROOT 没有语言和地区,空字符串可以是它在这类映射中的既有表示。它与“JSON 字段名不能为 null”不同:这里的键是合法空字符串,不是 null 键。
单段 Locale 被当成严格语言标签读取
受影响路径将单段内容交给 Locale.Builder.setLanguageTag。这一 API 对语言标签的校验,比历史 Locale 构造路径严格;Java 25 相关行为会拒绝空标签。
这也是为什么仅凭 Jackson 异常最外层,容易误认为 JSON 本身坏了。换一台 JDK 后成功,也不能反推原数据不需要处理。应同时记录运行中的 Jackson 版本、JDK 发行版和键的原始表示,不打印整份业务字典。
正式 3.2.4 已经修正这一读取分支
Jackson databind3.2.4 的正式实现明确避开单段值上的 Builder 路径,恢复为 new Locale(fullValue),包含将空字符串映射到 Locale.ROOT 的处理。项目使用 3.2 版本线时,可以按既有依赖管理采用包含该修正的正式版本,而非为此切换 JDK 主版本。
保留项目原有 Jackson 组件对齐规则、模块与 mapper 配置。只在一个直接测试使用 3.2.4,而 HTTP 转换器仍加载 3.2.3,不会改变实际故障。Jackson 3 的 databind 包为 tools.jackson,注解依赖仍有自身版本规则,不应把所有组件机械写成同一个版本号。
暂时不能升级时,只有在协议明确空键就是 ROOT 的情况下,才考虑为该字段使用专门的键转换入口;其他非空键仍按既定 Locale 规则解析。不要把所有解析失败的键都变成 ROOT,那会合并本来不同的配置项。
空键和普通区域键一起往返
核对空键、普通语言键、语言与地区组合及应用真正使用的历史下划线形式,比较读取后的 Locale 以及再输出的键。Map 中两种文本若映射到同一个 Locale,还要检查是否覆盖了配置;解析不报错不代表所有项都保留。
若故障只在格式化价格时出现逗号或句点差异,则应另看数值格式化的 Locale 选择。调整默认区域不是修复空 Map 键解析的必要步骤。


