Mapping list in Yaml to list of objects in Spring Boot

后端 未结 6 783
暖寄归人
暖寄归人 2020-11-29 03:52

In my Spring Boot app I have application.yaml configuration file with following content. I want to have it injected as a Configuration object with list of channel configurat

相关标签:
6条回答
  • 2020-11-29 04:14

    The reason must be somewhere else. Using only Spring Boot 1.2.2 out of the box with no configuration, it Just Works. Have a look at this repo - can you get it to break?

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

    Are you sure the YAML file looks exactly the way you pasted? No extra whitespace, characters, special characters, mis-indentation or something of that sort? Is it possible you have another file elsewhere in the search path that is used instead of the one you're expecting?

    0 讨论(0)
  • 2020-11-29 04:20

    I tried 2 solutions, both work.

    Solution_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();
    

    Solution_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);
    
    
    0 讨论(0)
  • 2020-11-29 04:20

    for me the fix was to add the injected class as inner class in the one annotated with @ConfigurationProperites, because I think you need @Component to inject properties.

    0 讨论(0)
  • 2020-11-29 04:24

    I had much issues with this one too. I finally found out what's the final deal.

    Referring to @Gokhan Oner answer, once you've got your Service class and the POJO representing your object, your YAML config file nice and lean, if you use the annotation @ConfigurationProperties, you have to explicitly get the object for being able to use it. Like :

    @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;
        }
    
    }
    

    And then here you go. It's simple as hell, but we have to know that we must call the object getter. I was waiting at initialization, wishing the object was being built with the value but no. Hope it helps :)

    0 讨论(0)
  • 2020-11-29 04:28
    • You don't need constructors
    • You don't need to annotate inner classes
    • RefreshScope have some problems when using with @Configuration. Please see this github issue

    Change your class like this:

    @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
        }
    
    }
    
    0 讨论(0)
  • 2020-11-29 04:31

    I had referenced this article and many others and did not find a clear cut concise response to help. I am offering my discovery, arrived at with some references from this thread, in the following:

    Spring-Boot version: 1.3.5.RELEASE

    Spring-Core version: 4.2.6.RELEASE

    Dependency Management: Brixton.SR1

    The following is the pertinent yaml excerpt:

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

    I created a 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;
        }
    }
    

    I created a 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);
        }
    }
    

    I used this combination in another class through @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 */
    
    }
    

    And in my logs the name and matching url's were logged. This was developed on another machine and thus I had to retype all of the above so please forgive me in advance if I inadvertently mistyped.

    I hope this consolidation comment is helpful to many and I thank the previous contributors to this thread!

    0 讨论(0)
提交回复
热议问题