Configuración de Spring Boot yaml para una lista de cadenas

149

Estoy tratando de cargar una matriz de cadenas del archivo application.yml. Esta es la configuración:

ignore:
    filenames:
        - .DS_Store
        - .hg

Esta es la clase:

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

Hay otras configuraciones en la misma clase que se cargan bien. No hay pestañas en mi archivo yaml. Todavía recibo la siguiente excepción:

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

Respuestas:

71

Mi conjetura es que @Valueno pueden hacer frente a los tipos "complejos". Puedes ir con una clase de utilería como esta:

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

Tenga en cuenta: ¡ Este código es Groovy , no Java , para abreviar el ejemplo! Vea los comentarios para obtener consejos sobre cómo adoptar.

Vea el ejemplo completo https://github.com/christoph-frick/so-springboot-yaml-string-list

cfrick
fuente
1
Puede vincular un separador de comas con @Value(siempre que se registre un convertidor, que creo que estará en Spring Boot).
Dave Syer
2
Está recogiendo configuraciones de cadena pero no configuraciones de Lista <String>
Bahadır Yağan
1
No pude hacerlo funcionar @Configuration, pero usar en su @Componentlugar hizo el truco.
Stijn Van Bael
1
@cfrick sí, fue el único cambio que hice. Mirando el propósito de ambas anotaciones, diría que @Componentes más apropiado: stackoverflow.com/questions/12229282/…
Stijn Van Bael
2
Parece que es una limitación con los procesos de arranque de primavera que la anotación - github.com/spring-projects/spring-boot/issues/501
wontondon
134

usar valores separados por comas en application.yml

ignoreFilenames: .DS_Store, .hg

código de Java para el acceso

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

Está funcionando ;)

Ahmet Vehbi Olgaç
fuente
Esperaba que esto también funcionara en Dropwizard: '(¡aunque gracias!
RST
1
Esa debería haber sido la mejor respuesta.
Mohamed Elsayed
3
En mis propias pruebas, esto es equivalente a ".DS_Store, .hg" pero no a ".DS_Store", ".hg": este último falla con "org.yaml.snakeyaml.parser.ParserException: al analizar un mapeo de bloques". Entonces, lo que realmente está haciendo aquí es proporcionar la propiedad como una sola cadena separada por comas (que Spring luego divide en una matriz o lista) en lugar de una matriz YAML. Esto "funciona" pero no responde la pregunta original. Todavía tengo que encontrar una manera de analizar una matriz YAML en una propiedad de bean @Value anotada.
Zirzirikos
38

De los documentos de arranque de primavera https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html

Las listas de YAML se representan como claves de propiedad con desreferenciadores [index], por ejemplo, este YAML:

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

Se transformaría en estas propiedades:

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

Para enlazar propiedades como esa usando las utilidades Spring DataBinder (que es lo que @ConfigurationPropertieshace) necesita tener una propiedad en el bean de destino de tipo java.util.Listy debe proporcionar un configurador o inicializarlo con un valor mutable, por ejemplo, esto se enlazará a las propiedades anteriores. Así es como se vería el código de la pregunta.

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

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

    public List<String> getFilenames() {
        return this.ignoredFilenames;
    }
}
dskow
fuente
2
Esto debería estar funcionando, BTW getXxx()es necesario para que funcione, y debe usar un List, no Set.
Eric Wang
En el yaml, la lista de valores para ArrayList puede ser una lista delimitada por comas. En mi caso, tengo muchos valores, por lo que una lista compacta es más limpia que un elemento por línea. Entonces, en el ejemplo, puede hacer servidores: dev.bar.com, foo.bar.com
Violaman
¿Se podría cargar el yaml desde un archivo de propiedades como este servers: ${my.servers}:? Para entrar my.servers[0]y entrar my.servers[1]en el yaml? Estoy tratando de tener configuraciones dependientes de la etapa
ochs.tobi hace
25

Además de la respuesta de Ahmet, puede agregar saltos de línea a la cadena separada por coma mediante el >símbolo.

application.yml :

ignoreFilenames: >
  .DS_Store, 
  .hg

Código Java :

@Value("${ignoreFilenames}")    
String[] ignoreFilenames;
Sasha Shpota
fuente
Esto funciona bien siempre que no tenga más comas (,) en sus cadenas.
Valentin Despa
Esto no funciona para leer propiedades como arraylist. Los lee como una sola cadena.
Sree Lakshmi
6

La respuesta de Ahmet proporciona cómo asignar los valores separados por comas a la matriz de cadenas.

Para usar la configuración anterior en diferentes clases, es posible que necesite crear captadores / establecedores para esto ... Pero si desea cargar esta configuración una vez y seguir usando esto como un bean con anotación Autowired, aquí es cómo lo logré:

En ConfigProvider.java

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

En clases externas:

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

puede usar la misma lista en cualquier otro lugar mediante el cableado automático.

Deepak
fuente
Eso funciona. En mi caso, aunque la aplicación falló, a menos que agregue @Configurational comienzo de la clase en ConfigProvider.java. De lo contrario, obtuve Source requirió un bean del tipo 'java.util.List' que no se pudo encontrar.
Diana
3
@Value("#{'${your.elements}'.split(',')}")  
private Set<String> stringSet;

archivo yml:

your:
 elements: element1, element2, element3

Hay mucho más que puedes jugar con spring spEL.

Vivek Swansi
fuente
2

Bueno, lo único que puedo hacer que funcione es así:

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

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

Y no olvides la @Configuración sobre tu clase ...

Sin la separación ",", no hay suerte ...

También funciona (arranque 1.5.8 versie)

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

En mi caso, se trataba de un problema de sintaxis en el archivo .yml. Yo tenía:

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

y la lista en mi archivo .yml:

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

no estaba leyendo en el campo @ Valor-anotado. Cuando cambié la sintaxis en el archivo .yml a:

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

Funcionó bien.

Matt Campbell
fuente
Intentando esto en spring-boot 1.5 esto no funciona. Necesitas dos puntos después de los servidores de arranque
Taugenichts
-2
@Value("${your.elements}")    
private String[] elements;

archivo yml:

your:
 elements: element1, element2, element3
Sashanet Buryk
fuente
1
¿Cómo es esta forma diferente la respuesta de Ahmet? stackoverflow.com/a/41462567/2065796
Sasha Shpota el
1
Respuesta ya proporcionada. Responder solo por el bien de los puntos no agrega valor
Deepak