I have following configuration file:
@Configuration public class PropertyPlaceholderConfigurerConfig { @Value("${property:defaultValue}") private String property; @Bean public static PropertyPlaceholderConfigurer ppc() throws IOException { PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer(); ppc.setLocations(new ClassPathResource("properties/" + property + ".properties")); ppc.setIgnoreUnresolvablePlaceholders(true); return ppc; } }
I run my application with following VM option:
-Dproperty=propertyValue
So I'd like my application to load specific property file on startup. But for some reason at this stage @Value
annotations are not processed and property is null
. On the other hand if I have PropertyPlaceholderConfigurer
configured via xml file - everything works perfectly as expected. Xml file example:
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="ignoreResourceNotFound" value="true"/> <property name="location"> <value>classpath:properties/${property:defaultValue}.properties</value> </property> </bean>
If I try to to inject property value in another Spring configuration file - it is properly injected. If I move my PropertyPlaceholderConfigurer
bean creation to that configuration file - field value is null again.
As workaround, I use this line of code:
System.getProperties().getProperty("property", "defaultValue")
Which is also works, but I'd like to know why such behavior is occurs and maybe it is possible to rewrite it in other way but without xml?
From Spring JavaDoc:
In order to resolve ${...} placeholders in definitions or @Value annotations using properties from a PropertySource, one must register a PropertySourcesPlaceholderConfigurer. This happens automatically when using context:property-placeholder in XML, but must be explicitly registered using a static @Bean method when using @Configuration classes. See the "Working with externalized values" section of @Configuration's javadoc and "a note on BeanFactoryPostProcessor-returning @Bean methods" of @Bean's javadoc for details and examples.
So, you are trying to use a placeholder in the code block required to enable placeholder processing.
As @M.Deinum mentioned, you should use a PropertySource (default or custom implementation).
Example below shows how to use properties in a PropertySource annotation as well as how to inject properties from the PropertySource in a field.
@Configuration @PropertySource( value={"classpath:properties/${property:defaultValue}.properties"}, ignoreResourceNotFound = true) public class ConfigExample { @Value("${propertyNameFromFile:defaultValue}") String propertyToBeInjected; /** * Property placeholder configurer needed to process @Value annotations */ @Bean public static PropertySourcesPlaceholderConfigurer propertyConfigurer() { return new PropertySourcesPlaceholderConfigurer(); } }
as Koray mentioned in the comment, the PropertySourcesPlaceholderConfigurer
is not needed anymore since Spring 4.3+ / Spring Boot 1.5+. Dynamic filenames can be used for property files in @PropertySource
and @ConfigurationProperties
annotations without additional configuration.
@Configuration @PropertySource( value={"classpath:properties/${property:defaultValue}.properties"}, ignoreResourceNotFound = true) public class ConfigExample { @Value("${propertyNameFromFile:defaultValue}") String propertyToBeInjected; }
@ConfigurationProperties("properties/${property:defaultValue}.properties") public class ConfigExample { String propertyNameFromFile; }
For any other poor souls who couldn't get this to work in some Configuration classes when they work in others:
Look to see what other beans you have in that class and if any of them get instantiated early in the ApplicationContext. A ConversionService is an example of one. This would instantiate the Configuration class before what is required is registered, thereby making no property injection take place.
I fixed this by moving the ConversionService to another Configuration class that I Imported.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With