Configuration yaml de Spring Boot pour une liste de chaînes

149

J'essaie de charger un tableau de chaînes à partir du fichier application.yml. Voici la configuration:

ignore:
    filenames:
        - .DS_Store
        - .hg

Voici la classe:

@Value("${ignore.filenames}")
private List<String> igonoredFileNames = new ArrayList<>();

Il existe d'autres configurations de la même classe qui se chargent très bien. Il n'y a pas d'onglets dans mon fichier yaml. J'obtiens toujours l'exception suivante:

Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'ignore.filenames' in string value "${ignore.filenames}"
Bahadır Yağan
la source

Réponses:

71

Je suppose que le @Valuene peut pas faire face aux types "complexes". Vous pouvez utiliser une classe d'accessoires comme celle-ci:

@Component
@ConfigurationProperties('ignore')
class IgnoreSettings {
    List<String> filenames
}

Veuillez noter: ce code est Groovy - pas Java - pour garder l'exemple court! Voir les commentaires pour savoir comment adopter.

Voir l'exemple complet https://github.com/christoph-frick/so-springboot-yaml-string-list

cfrick
la source
1
Vous pouvez lier une virgule séparée avec @Value(tant qu'un convertisseur est enregistré, ce qu'il sera dans Spring Boot je pense).
Dave Syer
2
Il récupère les paramètres de chaîne mais pas les paramètres de liste <String>
Bahadır Yağan
1
Je ne pouvais pas le faire fonctionner @Configuration, mais utiliser à la @Componentplace a fait l'affaire.
Stijn Van Bael
1
@cfrick oui c'était le seul changement que j'ai fait. En regardant le but des deux annotations, je dirais que @Componentc'est plus approprié: stackoverflow.com/questions/12229282/…
Stijn Van Bael
2
Cela semble être une limitation avec les processus de démarrage du printemps qui annotent
github.com/spring-projects/spring-boot/issues/501
134

utiliser des valeurs séparées par des virgules dans application.yml

ignoreFilenames: .DS_Store, .hg

code java pour l'accès

@Value("${ignoreFilenames}")    
String[] ignoreFilenames

Ça fonctionne ;)

Ahmet Vehbi Olgaç
la source
J'espérais que cela fonctionnerait aussi dans Dropwizard: '(merci cependant!
RST
1
Cela aurait dû être la meilleure réponse.
Mohamed Elsayed
3
Dans mes propres tests, cela équivaut à ".DS_Store, .hg" mais pas à ".DS_Store", ".hg" - ce dernier échoue avec "org.yaml.snakeyaml.parser.ParserException: lors de l'analyse d'un mappage de bloc". Donc, ce que vous faites ici est de fournir la propriété sous la forme d'une seule chaîne séparée par des virgules (que Spring divise ensuite en un tableau ou une liste) au lieu d'un tableau YAML. Cela "fonctionne" mais ne répond pas à la question initiale. Je n'ai pas encore trouvé de moyen d'analyser un tableau YAML dans une propriété de bean annotée @Value.
Zirzirikos
38

À partir de la documentation de démarrage du printemps https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html

Les listes YAML sont représentées comme des clés de propriété avec des déréférenceurs [index], par exemple ce YAML:

my:
   servers:
       - dev.bar.com
       - foo.bar.com

Serait transformé en ces propriétés:

my.servers[0]=dev.bar.com
my.servers[1]=foo.bar.com

Pour lier à des propriétés comme celle en utilisant les utilitaires Spring DataBinder (ce qui est ce qui @ConfigurationPropertiesfait), vous devez avoir une propriété dans le bean cible de type java.util.Listet vous devez soit fournir un setter, soit l'initialiser avec une valeur mutable, par exemple, cela liera aux propriétés ci-dessus. Voici à quoi ressemblerait le code de la question.

@ConfigurationProperties(prefix="ignore")
public class Filenames {

    private List<String> ignoredFilenames = new ArrayList<String>();

    public List<String> getFilenames() {
        return this.ignoredFilenames;
    }
}
dskow
la source
2
Cela devrait fonctionner, BTW getXxx()est nécessaire pour que cela fonctionne, et doit utiliser un List, non Set.
Eric Wang
Dans le yaml, la liste de valeurs de ArrayList peut être une liste délimitée par des virgules. Dans mon cas, j'ai de nombreuses valeurs, donc une liste compacte est plus propre qu'un élément par ligne. Donc, dans l'exemple, vous pouvez faire des serveurs: dev.bar.com, foo.bar.com
Violaman
Le yaml pourrait-il être chargé à partir d'un fichier de propriétés comme celui-ci servers: ${my.servers}:? Pour obtenir my.servers[0]et my.servers[1]dans le yaml? J'essaie d'avoir des configurations dépendant de la scène
ochs.tobi
25

En plus de la réponse d' Ahmet, vous pouvez ajouter des sauts de ligne à la chaîne séparée par des virgules à l'aide du >symbole.

application.yml :

ignoreFilenames: >
  .DS_Store, 
  .hg

Code Java :

@Value("${ignoreFilenames}")    
String[] ignoreFilenames;
Sasha Shpota
la source
Cela fonctionne bien tant que vous n'avez plus de virgules (,) dans vos chaînes.
Valentin Despa
Cela ne fonctionne pas pour lire les propriétés comme arraylist. Il les lit comme une seule chaîne.
Sree Lakshmi
6

La réponse d'Ahmet explique comment attribuer les valeurs séparées par des virgules au tableau String.

Pour utiliser la configuration ci-dessus dans différentes classes, vous devrez peut-être créer des getters / setters pour cela. Mais si vous souhaitez charger cette configuration une fois et continuer à l'utiliser comme un bean avec l'annotation Autowired, voici comment j'ai accompli:

Dans ConfigProvider.java

@Bean (name = "ignoreFileNames")
@ConfigurationProperties ( prefix = "ignore.filenames" )
public List<String> ignoreFileNames(){
    return new ArrayList<String>();
}

Dans les cours extérieurs:

@Autowired
@Qualifier("ignoreFileNames")
private List<String> ignoreFileNames;

vous pouvez utiliser la même liste partout ailleurs en autowiring.

Deepak
la source
Ça marche. Dans mon cas, l'application a échoué, sauf si j'ajoute @Configurationau début du cours dans ConfigProvider.java. Sinon, la source a exigé un bean de type 'java.util.List' qui n'a pas pu être trouvé.
Diana
3
@Value("#{'${your.elements}'.split(',')}")  
private Set<String> stringSet;

fichier yml:

your:
 elements: element1, element2, element3

Vous pouvez jouer beaucoup plus avec Spring SpEL.

Vivek Swansi
la source
2

Eh bien, la seule chose que je peux faire fonctionner est comme ça:

servers: >
    dev.example.com,
    another.example.com

@Value("${servers}")
private String[] array;

Et n'oubliez pas la @Configuration au-dessus de votre classe ....

Sans la séparation ",", pas de chance ...

Fonctionne aussi (boot 1.5.8 versie)

servers: 
       dev.example.com,
       another.example.com
Roland Roos
la source
-1

Dans mon cas, il s'agissait d'un problème de syntaxe dans le fichier .yml. J'ai eu:

@Value("${spring.kafka.bootstrap-servers}")
public List<String> BOOTSTRAP_SERVERS_LIST;

et la liste dans mon fichier .yml:

bootstrap-servers:
  - s1.company.com:9092
  - s2.company.com:9092
  - s3.company.com:9092

n'a pas lu dans le champ annoté @ Value. Lorsque j'ai changé la syntaxe du fichier .yml en:

bootstrap-servers >
  s1.company.com:9092
  s2.company.com:9092
  s3.company.com:9092

cela a bien fonctionné.

Matt Campbell
la source
Essayer ceci sur spring-boot 1.5 cela ne fonctionne pas. Vous avez besoin d'un deux-points après bootstrap-servers
Taugenichts
-2
@Value("${your.elements}")    
private String[] elements;

fichier yml:

your:
 elements: element1, element2, element3
sashanet buryk
la source
1
En quoi cette réponse d'Ahmet est-elle différente? stackoverflow.com/a/41462567/2065796
Sasha Shpota
1
Réponse déjà fournie. Répondre uniquement pour gagner des points n'ajoute pas de valeur
Deepak