271

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

13 Answers 13

230

Use comma-separated values in application.yml

ignoreFilenames: .DS_Store, .hg

Java code for access:

@Value("${ignoreFilenames}")    
String[] ignoreFilenames
Sign up to request clarification or add additional context in comments.

4 Comments

I was hoping this would work in Dropwizard too :'( thanks though!
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.
List<String> rather than String[] works as well
Create separate property config class and use List<String> instead of String[]. And in yml file configure like ignore: filenames: - .DS_Store - .hg
122

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

9 Comments

You can bind a comma-separated with @Value (as long as a converter is registered, which it will be in Spring Boot I think).
@Bahadır i tried this code here and it works. @ComponentScan and friends picks this up?
It is picking up string settings but not List<String> settings
There must also be a getter defined for the property.
This looks like it is a limitation with the spring boot processes that annotation - github.com/spring-projects/spring-boot/issues/501
|
75

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

4 Comments

This should be working, BTW getXxx() is necessary for it to work, and must use a List, not Set.
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
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
Combination of ConfigurationProperties and Component is faced with error: Annotated with ConstructorBinding but defined as Spring component
57

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;

2 Comments

This works well as long as you don't have any more commas (,) in your strings.
This doesn't work to read properties as arraylist. It reads them as single String.
53

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.

4 Comments

Trying this on spring-boot 1.5 this does not work. You need a colon after bootstrap-servers
Using spring boot 2.x, the list has a single element of all the values with space separated.
@Taugenichts You're correct a colon is missing. bootstrap-servers: >
I wouldn't call it a "syntax issue in the YAML file" – the syntax in the YAML is correct for a list of strings, just @Value can't cope with complex types.
20

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

1 Comment

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).
15
@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.

1 Comment

Unnecessary because Spring already does this split by comma by default!
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.

1 Comment

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.
3

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.

Comments

0

@Value("${coupon.update.fieldsToIgnore}") private List fieldsToIgnore;

coupon:
  update:
    fieldsToIgnore: dbVersion, createdAt, updatedAt

simply use this

Comments

0

I don't know from which version comme this feature, but I am using currently spring-boot 3.3.4 and it works yet simple with List and comma separated value:

ignore.filenames: name1, name2

    @Value("${ignore.filenames}")
    private List<String> sampleListValues;

Comments

0

This one works for me.

servers:
  server1,
  server2,
  server3

Comments

-3
@Value("${your.elements}")    
private String[] elements;

yml file:

your:
 elements: element1, element2, element3

2 Comments

How is this different form Ahmet's answer? stackoverflow.com/a/41462567/2065796
Answer already provided. Answering just for the sake of points doesn't add value

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.