-
Notifications
You must be signed in to change notification settings - Fork 38.6k
Description
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:
- repro_case.zip (1.43 kB)
Referenced from: commits 18006c7, 4169898, 98bf01a
3 votes, 4 watchers