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

Posted

技术标签:

【中文标题】将 Yaml 中的列表映射到 Spring Boot 中的对象列表【英文标题】:Mapping list in Yaml to list of objects in Spring Boot 【发布时间】:2015-12-12 02:52:59 【问题描述】:

在我的 Spring Boot 应用程序中,我有 application.yaml 配置文件,其中包含以下内容。我想将其作为带有通道配置列表的配置对象注入:

available-payment-channels-list:
  xyz: "123"
  channelConfigurations:
    -
      name: "Company X"
      companyBankAccount: "1000200030004000"
    -
      name: "Company Y"
      companyBankAccount: "1000200030004000"

我想用 PaymentConfiguration 对象列表填充@Configuration 对象:

    @ConfigurationProperties(prefix = "available-payment-channels-list")
    @Configuration
    @RefreshScope
    public class AvailableChannelsConfiguration 

        private String xyz;

        private List<ChannelConfiguration> channelConfigurations;

        public AvailableChannelsConfiguration(String xyz, List<ChannelConfiguration> channelConfigurations) 
            this.xyz = xyz;
            this.channelConfigurations = channelConfigurations;
        

        public AvailableChannelsConfiguration() 

        

        // getters, setters


        @ConfigurationProperties(prefix = "available-payment-channels-list.channelConfigurations")
        @Configuration
        public static class ChannelConfiguration 
            private String name;
            private String companyBankAccount;

            public ChannelConfiguration(String name, String companyBankAccount) 
                this.name = name;
                this.companyBankAccount = companyBankAccount;
            

            public ChannelConfiguration() 
            

            // getters, setters
        

    

我将其作为带有@Autowired 构造函数的普通bean 注入。 xyz 的值已正确填充,但是当 Spring 尝试将 yaml 解析为对象列表时,我得到了

   nested exception is java.lang.IllegalStateException: 
    Cannot convert value of type [java.lang.String] to required type    
    [io.example.AvailableChannelsConfiguration$ChannelConfiguration] 
    for property 'channelConfigurations[0]': no matching editors or 
    conversion strategy found]

有什么线索吗?

【问题讨论】:

我遇到了完全相同的问题:我尝试了很多东西,但我得到了一个空对象,或者同样的错误Cannot convert value of type ... String .... to MyObject ... no matching editors or conversion strategy found。奇怪的是我没有更改 Spring Boot 中可能影响 SnakeYAML 参数或行为的任何内容......实际上,到底是什么? 我差点忘了,我用的是 Spring Boot 1.2.6 我的猜测是 yaml 中 '-' 字符之后的换行符 【参考方案1】: 您不需要构造函数 您不需要注释内部类 RefreshScope@Configuration 一起使用时会出现一些问题。请看this github issue

像这样改变你的班级:

@ConfigurationProperties(prefix = "available-payment-channels-list")
@Configuration
public class AvailableChannelsConfiguration 

    private String xyz;
    private List<ChannelConfiguration> channelConfigurations;

    // getters, setters

    public static class ChannelConfiguration 
        private String name;
        private String companyBankAccount;

        // getters, setters
    


【讨论】:

同样的东西,通常你的代码只是我的嵌套异常的简化 java.lang.IllegalStateException: Cannot convert value of type [java.lang.String] to required type [io.example.available_channels .AvailableChannelsConfiguration$ChannelConfiguration] for property 'channelConfigurations[0]': no matching editors or conversion strategy found] 我运行了代码并查看了所有分配的值。您是否删除了 RefreshScope 注释 Re Gokhan:- Spring Boot 版本。 1.2.2 - 核心版本。 4.1.6 ,所有其他 spring 库都是 4.1.5 或 4.1.6(均取自 Spring Boot) 尝试将 ChannelConfiguration 导出到它自己的类。用组件注释标记它。它还需要所有字段的 setter 和 getter。 我用那个版本检查过【参考方案2】:

我尝试了 2 个解决方案,都有效。

解决方案_1

.yml

available-users-list:
  configurations:
    -
      username: eXvn817zDinHun2QLQ==
      password: IP2qP+BQfWKJMVeY7Q==
    -
      username: uwJlOl/jP6/fZLMm0w==
      password: IP2qP+BQKJLIMVeY7Q==

LoginInfos.java

@ConfigurationProperties(prefix = "available-users-list")
@Configuration
@Component
@Data
public class LoginInfos 
    private List<LoginInfo> configurations;

    @Data
    public static class LoginInfo 
        private String username;
        private String password;
    


List<LoginInfos.LoginInfo> list = loginInfos.getConfigurations();

解决方案_2

.yml

available-users-list: '["username":"eXvn817zHBVn2QLQ==","password":"IfWKJLIMVeY7Q==", "username":"uwJlOl/g9jP6/0w==","password":"IP2qWKJLIMVeY7Q=="]'

Java

@Value("$available-users-listt")
String testList;

ObjectMapper mapper = new ObjectMapper();
LoginInfos.LoginInfo[] array = mapper.readValue(testList, LoginInfos.LoginInfo[].class);

【讨论】:

【参考方案3】:

对我来说,解决方法是将注入的类作为内部类添加到带有 @ConfigurationProperites 注释的类中,因为我认为您需要 @Component 来注入属性。

【讨论】:

【参考方案4】:

我参考了这篇文章和许多其他文章,但没有找到一个清晰简洁的回复来提供帮助。我在下面提供了我的发现,并参考了该线程的一些参考资料:

Spring-Boot 版本:1.3.5.RELEASE

Spring-Core 版本:4.2.6.RELEASE

依赖管理:Brixton.SR1

以下是相关的yaml摘录:

tools:
  toolList:
    - 
      name: jira
      matchUrl: http://someJiraUrl
    - 
      name: bamboo
      matchUrl: http://someBambooUrl

我创建了一个 Tools.class:

@Component
@ConfigurationProperties(prefix = "tools")
public class Tools
    private List<Tool> toolList = new ArrayList<>();
    public Tools()
      //empty ctor
    

    public List<Tool> getToolList()
        return toolList;
    

    public void setToolList(List<Tool> tools)
       this.toolList = tools;
    

我创建了一个 Tool.class:

@Component
public class Tool
    private String name;
    private String matchUrl;

    public Tool()
      //empty ctor
    

    public String getName()
        return name;
    

    public void setName(String name)
       this.name= name;
    
    public String getMatchUrl()
        return matchUrl;
    

    public void setMatchUrl(String matchUrl)
       this.matchUrl= matchUrl;
    

    @Override
    public String toString()
        StringBuffer sb = new StringBuffer();
        String ls = System.lineSeparator();
        sb.append(ls);
        sb.append("name:  " + name);
        sb.append(ls);
        sb.append("matchUrl:  " + matchUrl);
        sb.append(ls);
    

我通过@Autowired在另一个类中使用了这个组合

@Component
public class SomeOtherClass

   private Logger logger = LoggerFactory.getLogger(SomeOtherClass.class);

   @Autowired
   private Tools tools;

   /* excluded non-related code */

   @PostConstruct
   private void init()
       List<Tool>  toolList = tools.getToolList();
       if(toolList.size() > 0)
           for(Tool t: toolList)
               logger.info(t.toString());
           
       else
           logger.info("*****-----     tool size is zero     -----*****");
         
   

   /* excluded non-related code */


在我的日志中记录了名称和匹配的 url。这是在另一台机器上开发的,因此我不得不重新输入以上所有内容,如果我无意中输入错误,请提前原谅我。

我希望这篇合并评论对许多人有所帮助,我感谢之前对该主题的贡献者!

【讨论】:

Tool类不需要@Component注解 你真的需要一个只是列表包装器的工具类吗? 这为我解决了,尤其是工具类的空构造函数的提示... 我在两个类上都有一个“@AllArgsConstructor”,这就是导致问题的原因。删除它并将“@NorArgsConstructor”留在那里,它就像一个魅力。仅供参考,我在两个类上也都有带有“@Data”的getter和setter。【参考方案5】:

这个我也有很多问题。我终于知道最后的交易是什么了。

参考@Gokhan Oner 的答案,一旦你有了你的服务类和代表你的对象的 POJO,你的 YAML 配置文件又好又瘦,如果你使用注释 @ConfigurationProperties,你必须明确地获取对象能够使用它。喜欢:

@ConfigurationProperties(prefix = "available-payment-channels-list")
//@Configuration  <-  you don't specificly need this, instead you're doing something else
public class AvailableChannelsConfiguration 

    private String xyz;
    //initialize arraylist
    private List<ChannelConfiguration> channelConfigurations = new ArrayList<>();

    public AvailableChannelsConfiguration() 
        for(ChannelConfiguration current : this.getChannelConfigurations()) 
            System.out.println(current.getName()); //TADAAA
        
    

    public List<ChannelConfiguration> getChannelConfigurations() 
        return this.channelConfigurations;
    

    public static class ChannelConfiguration 
        private String name;
        private String companyBankAccount;
    


然后就可以了。这很简单,但我们必须知道我们必须调用对象 getter。我在初始化时等待,希望使用该值构建对象,但没有。希望对你有帮助:)

【讨论】:

没有配置,如何自动装配这个配置对象? 这是我的问题。如果我在没有初始化列表的情况下添加了一个设置器,也可以工作。【参考方案6】:

原因一定是在别的地方。仅使用开箱即用的 Spring Boot 1.2.2,无需配置,Just Works。看看这个 repo - 你能打破它吗?

https://github.com/konrad-garus/so-yaml

您确定 YAML 文件看起来与您粘贴的完全一样吗?没有多余的空格、字符、特殊字符、错误缩进或类似的东西?您是否可能在搜索路径的其他位置使用了另一个文件,而不是您期望的文件?

【讨论】:

我做了同样的事情,并且对于干净的 SpringBoot 项目它可以工作。事实证明,我们为不同环境定制的属性加载行为不正常。 嗨@Konrad Garus,请查看***.com/questions/57409781/…这是一个类似的问题。

以上是关于将 Yaml 中的列表映射到 Spring Boot 中的对象列表的主要内容,如果未能解决你的问题,请参考以下文章

spring boot yaml 自定义配置 映射到 java POJO

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

Yaml 配置对象列表到属性文件

使用 Spring Boot 和 Thymeleaf 将复选框映射到列表

使用 YAML-CPP 将 YAML 值添加到标准映射

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