Spring R
added a comment - 14/Apr/10 1:44 AM I searched for this issue and I found people are using ignore-unresolvable property as true so that the first PropertyPlaceholderConfigurer does not throw an exception

I tried changing the order of my PropertyPlaceHolderConfigurers, and confirmed that it is always the one with the highest "order" value that is not found. A little debugging told me that they are both registered as BeanFactoryPostProcessors, but the exception is thrown while trying to resolve a property from the second one. This causes the BeanDefinitionStoreException, which aborts initialization before the second one gets to try to resolve the property.

I was able to get this working by adding ignoreUnresolvablePlaceholders="true", but I had to add it to ALL the PropertyPlaceHolderConfigurers in my application. If even one of them does not ignoreUnresolvablePlaceholders, you will get the BeanDefinitionStoreException.

Ryan Hoegg
added a comment - 11/Jun/10 4:02 AM I tried changing the order of my PropertyPlaceHolderConfigurers, and confirmed that it is always the one with the highest "order" value that is not found. A little debugging told me that they are both registered as BeanFactoryPostProcessors, but the exception is thrown while trying to resolve a property from the second one. This causes the BeanDefinitionStoreException, which aborts initialization before the second one gets to try to resolve the property.
I was able to get this working by adding ignoreUnresolvablePlaceholders="true", but I had to add it to ALL the PropertyPlaceHolderConfigurers in my application. If even one of them does not ignoreUnresolvablePlaceholders, you will get the BeanDefinitionStoreException.

Indeed the configuration described here does cause the reported exception, however I'm resolving this as "Works as Designed" for reasons explained below. Please note that if you read all the way, you'll find my recommendations as to how to eliminate this problem using Spring 3.1.

To recap the issue, consider two PropertyPlaceholderConfigurer beans P and Q configured in the same context where "Q" has a $

{...} placeholder that depends on "P" for replacement. In such a case, the placeholder replacement for "Q" will fail every time.

The reason for this can be understood by studying the way AbstractApplicationContext collects, sorts and executes BeanFactoryPostProcessor instances. It begins with a call to beanFactory.getBeansOfType(). This call requires that all such beans (of type BFPP) be fully instantiated and returned. This means that all the property values will be evaluated and injected into each new BFPP instance, and immediately so. This is done before any one BFPP has a chance to visit other beans. This means that the "Q" bean instance will end up retaining its original, un-replaced ${...}

placeholder – there was never a chance for "P" to replace it.

Even though "P" does eventually visit the BeanDefinition of "Q", this does not matter because the "Q" bean instance has already been created. Changing the BeanDefinition metadata is moot at that point.

The question then arises, how shall we fix this problem? It is certainly possible, given enough careful effort and testing to refactor BFPP handling such that earlier BFPPs are capable of modifying subsequent BFPPs at the level of bean definition metadata.

However, given the critical and non-trivial nature of the code in question, it is not likely worth the risk to "fix" this issue. Fix is quoted here, because while the behavior described by this issue is unituitive, it is not a bug per se. It might better be termed an 'undocumented limitation': BFPPs cannot modify other BFPPs bean definition metadata.

With all that said, the good news is that for Spring 3.1 users there is an alternative approach that might even be considered a superior solution.

The alternative is to (a) use the new PropertySourcesPlaceholderConfigurer instead of the traditional PropertyPlaceholderConfigurer; (b) eliminate the first PPC; (c) register a PropertySource with the ApplicationContext's Environment that contains the properties for the placeholders that need replacement in the PropertySourcesPlaceholderConfigurer, such as $

{resourceDirPlaceHolder}

from your original example.

To demonstrate this, I've added a new "SPR-6428" directory to the spring-framework-issues repository at Github.

You're welcome to check this repository out and build the SPR-6428 project with Maven / import it into your IDE to see a working example of the workaround to this issue.

Chris Beams
added a comment - 02/Jul/11 1:41 AM - edited Gisbert, all,
Indeed the configuration described here does cause the reported exception, however I'm resolving this as "Works as Designed" for reasons explained below. Please note that if you read all the way, you'll find my recommendations as to how to eliminate this problem using Spring 3.1.
To recap the issue, consider two PropertyPlaceholderConfigurer beans P and Q configured in the same context where "Q" has a $
{...} placeholder that depends on "P" for replacement. In such a case, the placeholder replacement for "Q" will fail every time.
The reason for this can be understood by studying the way AbstractApplicationContext collects, sorts and executes BeanFactoryPostProcessor instances. It begins with a call to beanFactory.getBeansOfType() . This call requires that all such beans (of type BFPP ) be fully instantiated and returned. This means that all the property values will be evaluated and injected into each new BFPP instance, and immediately so. This is done before any one BFPP has a chance to visit other beans. This means that the "Q" bean instance will end up retaining its original, un-replaced ${...}
placeholder – there was never a chance for "P" to replace it.
Even though "P" does eventually visit the BeanDefinition of "Q", this does not matter because the "Q" bean instance has already been created. Changing the BeanDefinition metadata is moot at that point.
The question then arises, how shall we fix this problem? It is certainly possible, given enough careful effort and testing to refactor BFPP handling such that earlier BFPPs are capable of modifying subsequent BFPPs at the level of bean definition metadata.
However, given the critical and non-trivial nature of the code in question, it is not likely worth the risk to "fix" this issue. Fix is quoted here, because while the behavior described by this issue is unituitive, it is not a bug per se. It might better be termed an 'undocumented limitation': BFPPs cannot modify other BFPPs bean definition metadata.
With all that said, the good news is that for Spring 3.1 users there is an alternative approach that might even be considered a superior solution.
The alternative is to (a) use the new PropertySourcesPlaceholderConfigurer instead of the traditional PropertyPlaceholderConfigurer ; (b) eliminate the first PPC; (c) register a PropertySource with the ApplicationContext 's Environment that contains the properties for the placeholders that need replacement in the PropertySourcesPlaceholderConfigurer , such as $
{resourceDirPlaceHolder}
from your original example.
To demonstrate this, I've added a new " SPR-6428 " directory to the spring-framework-issues repository at Github.
You're welcome to check this repository out and build the SPR-6428 project with Maven / import it into your IDE to see a working example of the workaround to this issue.
See https://github.com/SpringSource/spring-framework-issues#readme for instructions.
Thanks,
Chris