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

时间:2015-09-15 18:21:46

标签: java spring spring-boot yaml

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

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

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

    @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]

这里有什么问题吗?

6 个答案:

答案 0 :(得分:13)

原因必须是其他地方。仅使用Spring Boot 1.2.2开箱即用而没有配置,它 Just Works 。看看这个回购 - 你可以让它破解吗?

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

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

答案 1 :(得分:12)

  • 您不需要构造函数
  • 您不需要注释内部类
  • 使用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
}

}

答案 2 :(得分:9)

我引用了这篇文章以及其他许多文章并没有找到明确的简洁回应来帮助。我提供了我的发现,并通过以下内容获得了该线程的一些参考资料:

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 */

}

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

我希望这个整合评论对很多人有所帮助,我感谢此主题的前任贡献者!

答案 3 :(得分:6)

我也遇到过这个问题。我终于找到了最后的交易。

参考@Gokhan Oner的回答,一旦你得到了你的Service类和代表你对象的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。我正在等待初始化,希望对象是用值而不是构建的。希望它有所帮助:)

答案 4 :(得分: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);

答案 5 :(得分:0)

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