Spring @Bean and PropertyPlaceHolderConfigurer

I was recently stumped by what I thought was going to be a fairly straightforward implementation – Consider the following Spring Java based bean definition file (
@Configuration):
 
 
 
 
 
 
 
 

package root;

...

@Configuration
@PropertySource("classpath:root/test.props")
public class SampleConfig {

 @Value("${test.prop}")
 private String attr;

 @Bean
 public SampleService sampleService() {
  return new SampleService(attr);
 }
}

Here a bean `sampleService` is being defined, this bean is initialized with an attribute that is populated using a @Value annotation using a property placeholder string ${test.prop}.

The test for this is the following:

@ContextConfiguration(classes=SampleConfig.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class ConfigTest {
 @Autowired
 private SampleService sampleService;
 @Test
 public void testConfig() {
  assertThat(sampleService.aMethod(), is("testproperty"));
 }
}

which with the current implementation of SampleConfig fails, as the place holder ${test.prop} is not resolved at all. The standard fix for this is to register a PropertySourcesPlaceholderConfigurer which is a BeanFactoryPostProcessor responsible for scanning through all the registered bean definitions and injecting in the resolved placeholders. With this change in place the @Configuration file looks like this:

@Configuration
@PropertySource("classpath:root/test.props")
public class SampleConfig { 
 @Value("${test.prop}")
 private String attr;

 @Bean
 public SampleService sampleService() {
  return new SampleService(attr);
 }

 @Bean
 public PropertySourcesPlaceholderConfigurer placeHolderConfigurer() {
  return new PropertySourcesPlaceholderConfigurer();
 }
}

However, after adding in the Property resolver, the test still fails, this time the value returned by the sampleService is null, not even the placeholder value!

The reason for the issue it turns out, is that with @Configuration which internally uses annotations like @Autowired, @Value, and @PostConstruct, any BeanFactoryPostProcessor beans have to be declared with a static, modifier. Otherwise the containing @Configuration class is instantiated very early and the BeanPostProcessors responsible for resolving annotations like @Value, @Autowired etc, cannot act on it.

This fix is well documented in the javadoc of @Bean, further a message is also logged which provides the workaround:

WARN : org.springframework.context.annotation.ConfigurationClassEnhancer - @Bean method RootConfig.placeHolderConfigurer is non-static and returns an object assignable to Spring's BeanFactoryPostProcessor interface. This will result in a failure to process annotations such as @Autowired, @Resource and @PostConstruct within the method's declaring @Configuration class. Add the 'static' modifier to this method to avoid these container lifecycle issues; see @Bean Javadoc for complete details

So with this fix the new working configuration is the following:

@Configuration
@PropertySource("classpath:root/test.props")
public class SampleConfig { 
 @Value("${test.prop}")
 private String attr;

 @Bean
 public SampleService sampleService() {
  return new SampleService(attr);
 }

 @Bean
 public static PropertySourcesPlaceholderConfigurer placeHolderConfigurer() {
  return new PropertySourcesPlaceholderConfigurer();
 }
}

References:

 

Reference: Spring @Bean and PropertyPlaceHolderConfigurer from our JCG partner Biju Kunjummen at the all and sundry blog.
Related Whitepaper:

Functional Programming in Java: Harnessing the Power of Java 8 Lambda Expressions

Get ready to program in a whole new way!

Functional Programming in Java will help you quickly get on top of the new, essential Java 8 language features and the functional style that will change and improve your code. This short, targeted book will help you make the paradigm shift from the old imperative way to a less error-prone, more elegant, and concise coding style that’s also a breeze to parallelize. You’ll explore the syntax and semantics of lambda expressions, method and constructor references, and functional interfaces. You’ll design and write applications better using the new standards in Java 8 and the JDK.

Get it Now!  

One Response to "Spring @Bean and PropertyPlaceHolderConfigurer"

  1. Utku says:

    Cool. Thank you very much for this. Especially for “static” keyword & java annotation config.

Leave a Reply


six − 6 =



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.

Sign up for our Newsletter

15,153 insiders are already enjoying weekly updates and complimentary whitepapers! Join them now to gain exclusive access to the latest news in the Java world, as well as insights about Android, Scala, Groovy and other related technologies.

As an extra bonus, by joining you will get our brand new e-books, published by Java Code Geeks and their JCG partners for your reading pleasure! Enter your info and stay on top of things,

  • Fresh trends
  • Cases and examples
  • Research and insights
  • Two complimentary e-books