241

I am trying to load an array of strings from the application.yml file. This is the config:

ignore:
    filenames:
        - .DS_Store
        - .hg

This is the class fragment:

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

There are other configurations in the same class that loads just fine. There are no tabs in my YAML file. Still, I get the following exception:

Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'ignore.filenames' in string value "${ignore.filenames}"
Prectron
  • 282
  • 2
  • 11
Bahadır Yağan
  • 5,577
  • 3
  • 35
  • 39

10 Answers10

210

use comma separated values in application.yml

ignoreFilenames: .DS_Store, .hg

java code for access

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

It is working ;)

Ahmet Vehbi Olgaç
  • 2,725
  • 1
  • 14
  • 12
  • I was hoping this would work in Dropwizard too :'( thanks though! – RST May 16 '18 at 18:33
  • 10
    In my own tests, this is equivalent to ".DS_Store, .hg" but not ".DS_Store", ".hg" - the latter fails with "org.yaml.snakeyaml.parser.ParserException: while parsing a block mapping". So what you're actually doing here is providing the property as a single comma-separated string (which Spring then splits into an array or list) instead of a YAML array. This "works" but doesn't answer the original question. I have yet to find a way to parse a YAML array in a @Value annotated bean property. – Sonafets Mar 13 '19 at 12:42
  • `List` rather than `String[]` works as well – Prectron Dec 09 '22 at 20:06
  • Create separate property config class and use List instead of String[]. And in yml file configure like ignore: filenames: - .DS_Store - .hg – Pankaj Singh Jul 14 '23 at 12:00
112

My guess is, that the @Value can not cope with "complex" types. You can go with a prop class like this:

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

Please note: This code is Groovy - not Java - to keep the example short! See the comments for tips how to adopt.

See the complete example https://github.com/christoph-frick/so-springboot-yaml-string-list

cfrick
  • 35,203
  • 6
  • 56
  • 68
  • 4
    You can bind a comma-separated with `@Value` (as long as a converter is registered, which it will be in Spring Boot I think). – Dave Syer Nov 03 '14 at 08:29
  • @Bahadır i tried this code here and it works. `@ComponentScan` and friends picks this up? – cfrick Nov 04 '14 at 22:45
  • 2
    It is picking up string settings but not List settings – Bahadır Yağan Nov 05 '14 at 12:05
  • you are sure, that `@ConfigProperties('NAME')` is the root in your config.yaml, that your `List LIST` is the same name as the key in the config.yaml and there is a valid list of strings in the yaml? as i said: i tried above code with SB 1.1.8 and it worked. i will later put this on a gist – cfrick Nov 05 '14 at 12:09
  • Even with an example that simple, it does not retrieve a String list from my YAML config file. it's a bit omg and driving me crazy. (SpringBoot 1.2.6) – Alex Jan 19 '16 at 10:25
  • @StijnVanBael are you sure, that this was the only change? From the `@Configuration` docs: > {@code @Configuration} is meta-annotated with {@link Component @Component}, therefore {@code @Configuration} classes are candidates for component scanning ... – cfrick Jan 25 '16 at 14:23
  • 3
    There must also be a getter defined for the property. – OrangeDog Feb 10 '16 at 17:56
  • 2
    This looks like it is a limitation with the spring boot processes that annotation - https://github.com/spring-projects/spring-boot/issues/501 – wontondon Sep 19 '16 at 15:39
  • This approach seems to have broken for me starting with dependencies on Spring Cloud Dependencies Hoxton SR5 vs SR4. I had to initialize the list now. – Spork Jun 03 '20 at 12:23
70

From the Spring Boot docs:

YAML lists are represented as property keys with [index] dereferencers, for example this YAML:

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

Would be transformed into these properties:

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

To bind to properties like that using the Spring DataBinder utilities (which is what @ConfigurationProperties does) you need to have a property in the target bean of type java.util.List and you either need to provide a setter, or initialize it with a mutable value, e.g. this will bind to the properties above. Here is what the question's code would look like.

(Note: The example below only works on Spring Boot 3.0 and greater. Previous versions require the @ConstructorBinding annotation to be present to not throw exceptions when this object is being constructed.)

@ConfigurationProperties(prefix="ignore")
//@ConstructorBinding // uncomment if using Spring Boot 2.x.
public class Filenames {

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

    public List<String> getFilenames() {
        return this.ignoredFilenames;
    }
}
Per Lundberg
  • 3,837
  • 1
  • 36
  • 46
dskow
  • 924
  • 6
  • 9
  • 4
    This should be working, BTW `getXxx()` is necessary for it to work, and must use a `List`, not `Set`. – Eric Nov 28 '17 at 03:15
  • In the yaml, the list of values for the ArrayList can be a comma delimited list. In my case, I have many values, so a compact list is cleaner than an item per line. So in the example, you can do servers: dev.bar.com, foo.bar.com – Mr. Lee Jul 29 '19 at 21:08
  • 1
    Could the yaml be loaded from a properties file like this: `servers: ${my.servers}`? To get `my.servers[0]` and `my.servers[1]` into the yaml? I'm trying to have stage dependent configurations – ochs.tobi Jul 28 '20 at 07:58
49

In addition to Ahmet's answer you can add line breaks to the coma separated string using > symbol.

application.yml:

ignoreFilenames: >
  .DS_Store, 
  .hg

Java code:

@Value("${ignoreFilenames}")    
String[] ignoreFilenames;
Sasha Shpota
  • 9,436
  • 14
  • 75
  • 148
30

In my case, this was a syntax issue in the .yml file. I had:

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

and the list in my .yml file:

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

was not reading into the @Value-annotated field. When I changed the syntax in the .yml file to:

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

it worked fine.

Prectron
  • 282
  • 2
  • 11
Matt Campbell
  • 1,967
  • 1
  • 22
  • 34
18

Well, the only thing I can make it work is like so:

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

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

And dont forget the @Configuration above your class....

Without the "," separation, no such luck...

Works too (boot 1.5.8 versie)

servers: 
       dev.example.com,
       another.example.com
Roland Roos
  • 1,003
  • 10
  • 4
  • I prefer the first version with > though. If you put comment (e.g. after every line) IDE (IntelliJ) won't highlight the comment it in the first case but highlights it in the second case. It seems like it is supported to put the comment in the second case but it is not. The parser fails in both cases if the comment is there (spring-boot 2.2.10). – Jan Tomášek May 06 '21 at 20:01
14
@Value("#{'${your.elements}'.split(',')}")  
private Set<String> stringSet;

yml file:

your:
 elements: element1, element2, element3

There is lot more you can play with spring spEL.

Vivek Swansi
  • 409
  • 1
  • 4
  • 13
11

Ahmet's answer provides on how to assign the comma separated values to String array.

To use the above configuration in different classes you might need to create getters/setters for this.. But if you would like to load this configuration once and keep using this as a bean with Autowired annotation, here is the how I accomplished:

In ConfigProvider.java

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

In outside classes:

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

you can use the same list everywhere else by autowiring.

Deepak
  • 962
  • 4
  • 17
  • 38
  • 1
    That works. In my case though the application failed, unless I add `@Configuration` at the beginning of the class in `ConfigProvider.java`. Otherwise i got **Source required a bean of type 'java.util.List' that could not be found.** – Diana Jun 24 '19 at 12:27
2

Configuration in yaml file:

ignore:
    filenames: >
        .DS_Store
        .hg

In spring component:

@Value("#{'${gnore.filenames}'.split(' ')}")
private List<String> igonoredFileNames;

This worked fine for me.

Paramesh Korrakuti
  • 1,997
  • 4
  • 27
  • 39
-3
@Value("${your.elements}")    
private String[] elements;

yml file:

your:
 elements: element1, element2, element3
Suraj Rao
  • 29,388
  • 11
  • 94
  • 103