You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
If a nested property placeholder (for instance "${${Innter}.Outer}") is referenced twice within a single property string, Spring incorrectly reports a circular placeholder reference. Run the attached code for an example. To run, just throw Spring/log4j/commons-logging on the classpath and execute the main method. Pwd needs to be the root of the unzipped archive (so the res/constants.properties file is properly referenced).
In the attached code, a simple bean has a string field set to ${Top}. The properties file defines Top as ${Child}${Child}. Child is defined as ${${Differentiator}.Grandchild}. Differentiator is equal to First, and First.Grandchild equals ActualValue.
It is clear that this is a directed tree; no circular references in resolving placeholders. The final interpolated value should be "ActualValueActualValue", but an exception is thrown after the first value is resolved.
I believe the root cause is in the inner workings of the parseStringValue method (in PropertyPlaceholderConfigurer). It appears that, on the way in, ${Differentiator}.Grandchild is added to the "visitedPlaceholders" collection. On the way back out (recursively speaking), ${Differentiator} has already been resolved, and an attempt is made to remove (in this case) "First.Grandchild" from the visitedPlaceholders collection (which value has never been in the collection to begin with). Hence the collection is left in a dirty state even after the method has exited all the way back up the chain.
The problem comes during the evaluation of the second occurrence of ${Child}. Because the vistedPlaceholders collection still contains ${Differentiator}.Grandchild, visitedPlaceholders.add(placeholder) returns false while trying to add this placeholder when it is seen a second time (on the way down). So 'throw new BeanDefinitionStoreException("Circular placeholder reference '" + placeholder + "' in property definitions");' is executed.
It is clear that there is no technical reason why this case should not be feasible, so this is filed as a bug. In real-world scenarios, this issue might show up anytime someone wants to repeat a value within a single string. Examples: within an Oracle JdbcUrl, the TNS name appears twice. Or: A command to setup an ssh tunnel from a remote port to the same port on localhost needs to repeat that port number.
The repetition alone is not enough to cause this bug, it is caused by the repetition of a placeholder utilizing nesting.
This workaround is ok, but it is clearer to be able to specifically state only the difference between these two strings (in this case, the TNS Name), so a long-term fix is preferable.
Thanks Jason for the report, and sorry for the very long wait!
And thanks Stevo for the fix.
commit 18006c72b014246946fd487159de7e133d173a17
Author: Stevo Slavic <sslavic@gmail.com>
AuthorDate: Sat Feb 18 17:44:04 2012 +0100
Commit: Chris Beams <cbeams@vmware.com>
CommitDate: Thu May 17 14:48:18 2012 +0300
Fix circular placeholder prevention
A set of resolved placeholder references is used for circular
placeholder prevention. For complex property definitions this mechanism
would put property values with unresolved inner placeholder references
in the set, but would try to remove property values with placeholders
resolved, leaving the set in an invalid state and the mechanism broken.
This fix makes sure that the value that is put in the set is same one
that is removed from it, and by doing so avoids false positives in
reporting circular placeholders.
Issue: SPR-5369
Jason Petersen opened SPR-5369 and commented
If a nested property placeholder (for instance "${${Innter}.Outer}") is referenced twice within a single property string, Spring incorrectly reports a circular placeholder reference. Run the attached code for an example. To run, just throw Spring/log4j/commons-logging on the classpath and execute the main method. Pwd needs to be the root of the unzipped archive (so the res/constants.properties file is properly referenced).
In the attached code, a simple bean has a string field set to ${Top}. The properties file defines Top as ${Child}${Child}. Child is defined as ${${Differentiator}.Grandchild}. Differentiator is equal to First, and First.Grandchild equals ActualValue.
It is clear that this is a directed tree; no circular references in resolving placeholders. The final interpolated value should be "ActualValueActualValue", but an exception is thrown after the first value is resolved.
I believe the root cause is in the inner workings of the parseStringValue method (in PropertyPlaceholderConfigurer). It appears that, on the way in, ${Differentiator}.Grandchild is added to the "visitedPlaceholders" collection. On the way back out (recursively speaking), ${Differentiator} has already been resolved, and an attempt is made to remove (in this case) "First.Grandchild" from the visitedPlaceholders collection (which value has never been in the collection to begin with). Hence the collection is left in a dirty state even after the method has exited all the way back up the chain.
The problem comes during the evaluation of the second occurrence of ${Child}. Because the vistedPlaceholders collection still contains ${Differentiator}.Grandchild, visitedPlaceholders.add(placeholder) returns false while trying to add this placeholder when it is seen a second time (on the way down). So 'throw new BeanDefinitionStoreException("Circular placeholder reference '" + placeholder + "' in property definitions");' is executed.
It is clear that there is no technical reason why this case should not be feasible, so this is filed as a bug. In real-world scenarios, this issue might show up anytime someone wants to repeat a value within a single string. Examples: within an Oracle JdbcUrl, the TNS name appears twice. Or: A command to setup an ssh tunnel from a remote port to the same port on localhost needs to repeat that port number.
The repetition alone is not enough to cause this bug, it is caused by the repetition of a placeholder utilizing nesting.
Affects: 2.5.2, 2.5.3, 2.5.4, 2.5.5, 2.5.6
Attachments:
Referenced from: commits 18006c7, 4169898, 98bf01a
3 votes, 4 watchers
The text was updated successfully, but these errors were encountered: