在 Spring Boot 中的 Yaml 中转义 Map 键中的点

Posted

技术标签:

【中文标题】在 Spring Boot 中的 Yaml 中转义 Map 键中的点【英文标题】:Escaping a dot in a Map key in Yaml in Spring Boot 【发布时间】:2016-03-08 08:40:42 【问题描述】:

我有以下 yml 配置:

foo:
  bar.com:
    a: b
  baz.com:
    a: c

Spring 尝试通过以下类注入带有键 'bar' 和 'baz' 的映射,将点视为分隔符:

public class JavaBean 
    private Map<String, AnotherBean> foo;
(...)

我尝试引用密钥(即“bar.com”或“bar.com”)但无济于事 - 仍然是同样的问题。有没有办法解决这个问题?

【问题讨论】:

引用密钥没有帮助的原因是因为bar.com:"bar.com":'bar.com':(和? bar.com)在 YAML 中都代表相同的完全相同的东西,并且都被反序列化为字符串bar.com。这个点在 YAML 中并不表示任何特殊的东西——你看到的行为是在 YAML 被反序列化后在 Spring 中发生的。 SPring 是在幕后使用 YamlPropertiesFactoryBean 吗?如果是这样,有没有办法让它使用 YamlMapFactoryBean 代替? :) 【参考方案1】:

对@fivetenwill 的回答稍作修改,在 Spring Boot 1.4.3.RELEASE 上对我有用:

foo:
  "[bar.com]":
    a: b
  "[baz.com]":
    a: c

您需要将括号放在引号内,否则 YAML 解析器基本上会在它们到达 Spring 之前将它们丢弃,并且它们不会使其成为属性名称。

【讨论】:

@shivakumar,直到 Spring Boot 2.1.7.RELEASE,这种方法仍然适用于我。除了查看Relaxed Binding 文档之外,不确定要向您建议什么,因为某些规则在 Spring Boot 2 中有所改变。另请参阅:Spring Boot 2 Migration Guide【参考方案2】:

这应该可行:

foo:
  "[bar.com]":
    a: b
  "[baz.com]":
    a: c

灵感来自Spring Boot Configuration Binding Wiki

【讨论】:

【参考方案3】:

如果您想将 yaml 键自动映射到 Java bean 属性,这是不可能的。原因是,Spring 首先将 YAML 转换为属性格式。 请参阅以下链接的第 24.6.1 节:

https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html

所以,你的 YAML 被转换为:

foo.bar.com.a=b
foo.baz.com.a=c

上面的键被解析为标准属性。

作为一种变通方法,您可以使用 Spring 的 YamlMapFactoryBean 按原样创建 Yaml 映射。然后,您可以使用该映射来自己创建 Java bean。

@Configuration
public class Config 

    private Map<String, Object> foo;

    @Bean
    public Map<String, Object> setup() 
        foo = yamlFactory().getObject();
        System.out.println(foo); //Prints foo=bar.com=a=b, baz.com=a=c
        return foo;
    

    @Bean
    public YamlMapFactoryBean yamlFactory() 
        YamlMapFactoryBean factory = new YamlMapFactoryBean();
        factory.setResources(resource());
        return factory;
    

    public Resource resource() 
        return new ClassPathResource("a.yaml"); //a.yaml contains your yaml config in question
    


【讨论】:

有什么方法可以让 YamlMapFactoryBean 返回某个 Bean 实例的映射而不是映射的映射?有什么方法可以从特定配置节点返回地图?我的 yml 更复杂,地图配置只是其中的一部分,我宁愿不将地图配置分开到单独的配置。上面的代码对我来说已经够hackish了:) 我同意你的看法。上面的代码需要解决一些问题。但是为了最大限度地利用 spring 自动配置,我担心你将不得不放弃 yaml 键中的点。否则,在上面的 setup() 方法中,您可以迭代 yaml 对象并手动创建 bean(这可能会导致自动装配问题)。 是的,我明白了。我仍然会尝试查找 Spring 是如何自动装配的,也许有一种方法可以让它从地图而不是属性自动装配:)

以上是关于在 Spring Boot 中的 Yaml 中转义 Map 键中的点的主要内容,如果未能解决你的问题,请参考以下文章

如何在 AWS CloudFormation YAML 模板中转义策略变量

如何在映射到Spring配置类列表中的环境变量中转义逗号

将 YAML 列表映射到 Spring Boot 中的对象列表

Spring Boot2 系列教程理解Spring Boot 配置文件 application.properties

将 Yaml 中的列表映射到 Spring Boot 中的对象列表

Spring Boot 配置文件: application.properties和application.yaml