18

I am working with Spring boot 1.1.8 which uses Spring 4.0.7. I am autowiring the properties in my classes with @Value annotation. I want to have a default value if the property is not present in properties file so, I use ":" to assign default value. Below is the example:

@Value("${custom.data.export:false}")
private boolean exportData = true;

It should assign false to the variable if property is not present in the properties file which is does. However, if property is present in the file, then also it assigns default value and ignores the properties value. E.g. if I have defined the property like the one mentioned above and application properties file has something like this custom.data.export=truethen, the value of exportData will still be false whereas it should be true ideally.

Can anyone please guide me what I am doing wrong here?

Thanks

divibisan
  • 11,659
  • 11
  • 40
  • 58
Darshan Mehta
  • 30,102
  • 11
  • 68
  • 102
  • I have tested, and everything is ok. if propery is missing the default value is taken (false). – Eddú Meléndez Feb 06 '15 at 18:20
  • 3
    it should work. Why is your field initialized with true?! Can you add the actuator and look at the /env endpoint to double check the configuration has been applied as you expect? – Stephane Nicoll Feb 09 '15 at 08:01
  • 5
    Well, deep down in one of the dependencies, the "ignoreUnresolvablePlaceholders" parameter was set to true. Due to this, spring always used the default value and never looked into application.properties file. Managed to resolve it by commenting out that chunk. Thanks. – Darshan Mehta Feb 13 '15 at 11:25
  • @DarshanMehta, how does it set this proerty in application properties ? –  Dec 22 '16 at 08:36
  • I mean how to set ignoreUnresolvablePlaceholders on false in application.propertes. –  Dec 22 '16 at 08:49

4 Answers4

17

We were bitten by the following Spring bug with exactly the same symptom:

[SPR-9989] Using multiple PropertyPlaceholderConfigurer breaks @Value default value behavior

Basically if more than a single PropertyPlaceholderConfigurer is present in the ApplicationContext, only predefined defaults will be resolved and no overrides will take place. Setting a different ignoreUnresolvablePlaceholders value had no impact on the matter, and both values (true/false) worked equally well in that regard once we removed the extra PropertyPlaceholderConfigurer.

Looking into it, each of the defined PropertyPlaceholderConfigurer internally resolved the properties as expected, but Spring couldn't figure out which of them to use in order to inject a value into the @Value annotated fields/params.

Ophir Radnitz
  • 1,783
  • 2
  • 20
  • 18
5

You can do one of the following to overcome this:

  1. Use custom valueSeparator in your configurer

<bean id="customConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
     <property name="location" value="file:${catalina.base}/conf/config2.properties"/>
     <property name="ignoreUnresolvablePlaceholders" value="true"/>
     <property name="valueSeparator" value="-defVal-"/>
</bean>
  1. Increase the preference of the relevant configurer using the order property

<bean id="customConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="location" value="file:${catalina.base}/conf/config2.properties"/>
    <property name="ignoreUnresolvablePlaceholders" value="true"/>
    <property name="order" value="-2147483648"/>
</bean?

I have done some RnD on this issue, available here.

Arpit Jain
  • 61
  • 1
  • 9
2

As @Ophir Radnitz stated, this is a spring bug that happens when there is more than one PropertyPlaceholderConfigurer present in the ApplicationContext.

As a workaround, you can obtain the desired behavior with something like that:

(...)

@Autowired
private Environment environment;

(...)

private Boolean shouldExportData()
{        
    return environment.getProperty( "custom.data.export", Boolean.class, Boolean.FALSE );
}
Lucas Oliveira
  • 3,357
  • 1
  • 16
  • 20
1

Happening this situation, depends on the type of the parameter.

when setting a default value for a String parameter, your sample code as default value (@Value("${custom.string:test}")) works fine, for other types (like boolean, in your question), the default value should be written in this way:

@Value("${custom.data.export:#{true}}")
private boolean exportData = true;

similarly, for Integers:

@Value("${custom.integer:#{20}}")

good luck.

Majid Roustaei
  • 1,556
  • 1
  • 20
  • 39