web-dev-qa-db-fra.com

Mappage de la liste dans Yaml avec la liste des objets dans Spring Boot

Dans mon application Spring Boot, j'ai le fichier de configuration application.yaml avec le contenu suivant. Je veux l'avoir injecté en tant qu'objet Configuration avec une liste de configurations de canaux:

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

Et l'objet @Configuration que je souhaite renseigner avec la liste des objets 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
        }

    }

Je l'injecte comme un haricot normal avec le constructeur @Autowired. La valeur de xyz est renseignée correctement, mais lorsque Spring essaie d'analyser yaml dans une liste d'objets, je reçois

   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]

Des indices sur ce qui ne va pas ici?

43
Tomasz Dziurko

La raison doit être ailleurs. En utilisant uniquement Spring Boot 1.2.2 prêt à l'emploi, sans configuration, il fonctionne simplement . Jetez un oeil à ce dépôt - pouvez-vous le faire casser?

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

Êtes-vous sûr que le fichier YAML ressemble exactement à celui que vous avez collé? Pas d’espace supplémentaire, de caractères, de caractères spéciaux, d’indentation incorrecte ou quelque chose du genre? Est-il possible que vous ayez un autre fichier ailleurs dans le chemin de recherche qui est utilisé à la place de celui que vous attendez?

13
Konrad Garus
  • Vous n'avez pas besoin de constructeurs
  • Vous n'avez pas besoin d'annoter les classes internes
  • RefreshScope rencontre des problèmes lors de l'utilisation avec @Configuration. S'il vous plaît voir cette question github

Changez votre classe comme ceci:

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

}
13
Gokhan Oner

J'avais fait référence à cet article et à beaucoup d'autres et je n'ai pas trouvé de réponse claire et concise pour vous aider. Je propose ma découverte, arrivée à avec quelques références de ce fil, dans ce qui suit:

Version Spring-Boot: 1.3.5.RELEASE

Version Spring-Core: 4.2.6.RELEASE

Gestion des dépendances: Brixton.SR1

Voici l'extrait pertinent de yaml:

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

J'ai créé un 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;
    }
}

J'ai créé un 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);
    }
}

J'ai utilisé cette combinaison dans une autre classe via @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 */

}

Et dans mes journaux le nom et l'URL correspondant ont été enregistrés. Ceci a été développé sur une autre machine et je devais donc retaper tout ce qui précède alors veuillez me pardonner à l’avance si j’ai fait une faute de frappe par inadvertance.

J'espère que ce commentaire de consolidation sera utile à beaucoup et je remercie les précédents contributeurs à ce fil!

9
JavaJd

J'ai eu beaucoup de problèmes avec celui-ci aussi. J'ai finalement découvert quel était le contrat final.

En vous référant à @Gokhan Oner answer, une fois que vous avez obtenu votre classe de service et le POJO représentant votre objet, votre fichier de configuration YAML agréable et simple, si vous utilisez l'annotation @ConfigurationProperties, vous devez obtenir explicitement l'objet pour pouvoir l'utiliser. il. Comme :

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

}

Et puis voilà. C'est simple, mais il faut savoir qu'il faut appeler l'objet getter. J'attendais à l'initialisation, souhaitant que l'objet soit construit avec la valeur mais non. J'espère que ça aide :)

6
Alex

pour moi, le correctif consistait à ajouter la classe injectée en tant que classe interne dans celle annotée avec @ConfigurationProperites, car je pense que vous avez besoin de @Component pour injecter des propriétés.

0