Question

I have an existing xml-based spring configuration using a PropertyPlaceholderConfigurer as follows:

  <context:property-placeholder location="classpath:my.properties" />

  <bean id="myBean" class="com.whatever.TestBean">
    <property name="someValue" value="${myProps.value}" />
  </bean>

Where myprops.value=classpath:configFile.xml and the setter for 'someValue' property accepts a org.springframework.core.io.Resource.

This works fine - the PPC will convert between the String value and the Resource automatically.

I'm now trying to use Java Config and the @PropertySource annotation as follows:

@Configuration
@PropertySource("classpath:my.properties")
public class TestConfig {

    @Autowired Environment environment;

    @Bean
    public TestBean testBean() throws Exception {
        TestBean testBean = new TestBean();
        testBean.setSomeValue(environment.getProperty("myProps.value", Resource.class));
        return testBean;
    }

}

The getProperty() method of the Spring Environment class provides an overload to support conversion to different types, which I've used, however this doesn't by default support converting the property to a Resource:

Caused by: java.lang.IllegalArgumentException: Cannot convert value [classpath:configFile.xml] from source type [String] to target type [Resource]
    at org.springframework.core.env.PropertySourcesPropertyResolver.getProperty(PropertySourcesPropertyResolver.java:81)
    at org.springframework.core.env.AbstractEnvironment.getProperty(AbstractEnvironment.java:370)
    at config.TestConfig.testBean(TestConfig.java:19)

Looking at the underlying source code, the Environment implementation uses a PropertySourcesPropertyResolver, which in turn uses a DefaultConversionService and this only registers very basic converters.

So I have two questions:
1) How can I get this to support the conversion to Resource?
2) Why should I need to when the original PPC does this for me?

Was it helpful?

Solution

I've solved this as follows.

I've realised that there is a distinction between getting the property from the resource bundle and then setting the property on the bean - Spring will do the conversion while setting the property using the relevant PropertyEditor (ResourceEditor). So we have to do this step manually:

@Configuration
@PropertySource("classpath:my.properties")
public class TestConfig {

    @Autowired Environment environment;

    @Bean
    public TestBean testBean() throws Exception {
        ResourceEditor editor = new ResourceEditor();
        editor.setAsText(environment.getProperty("myProps.value"));
        TestBean testBean = new TestBean();
        testBean.setSomeValue((Resource)editor.getValue());
        return testBean;
    }

}

However this does leave the outstanding question of why the DefaultConversionService used internally by the Environment will not pick up the PropertyEditor automatically. This could be to do with:

https://jira.springsource.org/browse/SPR-6564

OTHER TIPS

I was facing the same issue, and it turned out, that context:property-placeholder not only loads properties files, but it also declares special bean org.springframework.context.support.PropertySourcesPlaceholderConfigurer which processes all files, e.g. resolves ${...} properties and replaces them.

For fixing it you simply need to create its instance:

@Configuration
public class TestConfig {

    @Autowired Environment environment;

    @Bean 
    public static PropertySourcesPlaceholderConfigurer configurer (){ 
         PropertySourcesPlaceholderConfigurer postProcessor = new PropertySourcesPlaceholderConfigurer();
         postProcessor.setLocation(new ClassPathResource("my.properties"));
         return postProcessor; 
    } 

...

Note, that you need to remove @PropertySource("classpath:my.properties") annotation.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top