YAMLMapper 解析带点号(.)的嵌套键路径时的正确用法

yamlmapper 解析带点号(.)的嵌套键路径时的正确用法:jackson 的 yamlmapper 默认不将 yaml 中的点号(如 `formatting.template`)视为嵌套路径分隔符;它严格遵循 yaml 规范,将 `formatting.template` 视为一个完整、扁平的键名。若使用 json pointer `/formatting/template` 去定位该键,会因路径不匹配导致 `mismatchedinputexception`。正确做法是改用 `/formatting.template`(含点号的完整键名)或重构 yaml 为标准嵌套结构。

在使用 Jackson 的 YAMLMapper 手动解析 YAML 配置时,一个常见误区是混淆 YAML 原生语法Spring Boot 的属性映射逻辑。YAML 标准中,点号(.)

不是路径分隔符,而是一个普通字符。例如:

formatting.template:
  fields:
    - name: birthdate
      type: java.lang.String
      subType: java.util.Date
      lenght: 10

这段 YAML 实际定义了一个单层映射键 "formatting.template",其值是一个包含 fields 的对象。它等价于 JSON 中的:

{
  "formatting.template": {
    "fields": [ ... ]
  }
}

因此,若你调用:

mapper.readerFor(FormattingConfigurationProperties.class)
       .at("/formatting/template")  // ❌ 错误:试图访问 nested mapping "formatting" → "template"
       .readValue(inputStream);

YAMLMapper 会在根对象中查找名为 "formatting" 的字段,再在其下找 "template" —— 但实际并不存在该嵌套结构,而是存在一个名为 "formatting.template" 的字段。这会导致解析失败,抛出 MismatchedInputException: No content to map due to end-of-input(因路径未命中,读取器找不到目标节点,输入流已耗尽)。

✅ 正确做法有以下两种:

方案一:使用匹配扁平键的 JSON Pointer(推荐用于兼容现有 YAML)

将 at() 中的路径改为带点号的完整键名:

return mapper.readerFor(FormattingConfigurationProperties.class)
             .at("/formatting.template")  // ✅ 注意:此处是字面量键名,含点号
             .readValue(inputStream);

同时,需确保你的 Java 类能接收该扁平键作为字段名。由于 Jackson 默认按属性名匹配,你需要通过 @JsonProperty 显式绑定:

@Data
public class FormattingConfigurationProperties {

    @JsonProperty("formatting.template")
    private Template template;  // 新增封装类

    @Data
    public static class Template {
        private List fields;
    }

    @Data
    public static class Field {
        private String name;
        private String type;
        private String subType;
        private String lenght;
    }
}

方案二:保持嵌套结构 YAML(语义更清晰,无需额外注解)

即你已验证可行的方式:

formatting:
  template:
    fields:
      - name: birthdate
        type: java.lang.String
        subType: java.util.Date
        lenght: 10

对应 Java 类保持原样(无需 @JsonProperty),路径也恢复为标准嵌套形式:

return mapper.readerFor(FormattingConfigurationProperties.class)
             .at("/formatting/template")  // ✅ 此时 YAML 确实存在 formatting → template 路径
             .readValue(inputStream);

⚠️ 注意事项:

  • Spring Boot 的 @ConfigurationProperties 在加载 YAML 时,内部会将 . 视为嵌套分隔符并自动转换结构,这是 Spring 特有的预处理行为,不适用于 Jackson 直接解析
  • YAMLMapper 不支持“点号自动展开”,也不提供类似 Spring 的 relaxed binding 模式。
  • 若必须使用扁平点号键(如对接遗留配置格式),务必同步更新 JSON Pointer 和 Java 字段映射(通过 @JsonProperty 或 @JsonAlias)。
  • lenght 是拼写错误(应为 length),虽不影响解析,但建议修正以提升可维护性。

总结:YAML 中的 . 是合法键名字符,而非语法符号;Jackson 的 YAMLMapper 严格遵循此规范。选择方案一(适配扁平键)或方案二(采用标准嵌套)均可解决问题,关键在于 JSON Pointer 路径必须与 YAML 实际结构完全一致