【问题标题】:Mapping list in Yaml to list of objects in Spring Boot将 Yaml 中的列表映射到 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 中 '-' 字符之后的换行符

标签: java spring spring-boot 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,请查看stackoverflow.com/questions/57409781/…这是一个类似的问题。
      猜你喜欢
      • 2016-07-13
      • 2019-07-25
      • 1970-01-01
      • 2018-11-23
      • 2017-02-17
      • 2019-07-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多