-
Notifications
You must be signed in to change notification settings - Fork 38.5k
Introduce support for escaping the escape character for property placeholders #34315
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
The parser in 6.2 has been rewritten to fix, amongst other things, #9628. Unfortunately, this means that if the placeholder is escaped, it's rendered as is (i.e. not evaluated). I wrote a test: @Test
void gh34315() {
Properties properties = new Properties();
properties.setProperty("prop1", "value1");
properties.setProperty("prop2", "value2\\${prop1}");
PlaceholderParser parser = new PlaceholderParser("${", "}", ":", '\\', true);
assertThat(parser.replacePlaceholders("${prop2}", properties::getProperty)).isEqualTo("value2${prop1}");
} and it passes. I've also added those two properties in an empty Spring 6.2 app and it resolved the same way. Can you share a sample that actually fails the way you've described? |
To run:
The 3.3 one shows the expected behavior, the 3.4 shows what I described as the broken behavior in both '\' and '\\' in the original post. |
I got it now. The problem is |
The issue as reported can't be fixed without re-introducing the bug that we fixed. The side effect that was found as part of the report is going to be handled by #34326. For that case above, you'll need to restructure your configuration to move the backslash elsewhere to avoid the escaping, something like:
|
Couldn't we introduce a way to escape the escape character? |
Everything is possible, I guess but we’re not keen to make the parser more complex at this time. |
My issue is that this broke something that was working for years. |
@bitb4ker is right, that's a breaking change. You should at least mention it in the release notes. |
@neoludo Can you suggest what's missing from the release notes? |
The sentence But in a YAML file, and given this YAML snippet : username: johndoe
login: DOMAIN\${username} login will be evaluated as : and given this YAML snippet : username: johndoe
login: DOMAIN\\${username} login will be evaluated correctly as : So there is no need to move backslashes to value itself, and the upgrade notes should dissociate YAML parsing from properties parsing. |
I guess this is a Yaml specific concern; but I guess the advice to move the It could be that this currently works because of some subtle YAML+parser interaction right now, but is still not advised. |
@bclozel I see a paragraph was added on that in the release notes however I still think that this is an issue that needs to be addressed as being forced to add the \ in the value being interpolated is just not right. Could we add implement an escape mechanism for the escape character somewhere in the roadmap? |
Hi everyone, Thanks for all of the constructive feedback! 👍 We have decided to introduce support for "escaping the escape character" in Spring Framework 7.0. In light of that, I have changed the title of this issue and reopened this issue to address that. In addition, we will be addressing #34861 and related issues in Spring Framework 6.2.7. Cheers, Sam |
That's a great news, thanks! |
In the interim, once #34861 is complete you should be able to explicitly set the Whereas, once #34865 is complete you should be able to globally disable the escape character by default, via a JVM system property, directly via Thus, 6.2.7 will provide mechanisms that can be used as an alternative to "escaping the escape character" within configuration strings. |
Currently, the placeholder resolution algorithm in PropertySourcesPlaceholderConfigurer fails in several scenarios, and the root cause for this category of failures has actually existed since PropertySourcesPlaceholderConfigurer was introduced in Spring Framework 3.1. Specifically, PropertySourcesPlaceholderConfigurer creates its own PropertySourcesPropertyResolver that indirectly delegates to another "nested" PropertySourcesPropertyResolver to interact with PropertySources from the Environment, which results in double placeholder parsing and resolution attempts, and that behavior leads to a whole category of bugs. For example, spring-projects#27947 was addressed in Spring Framework 5.3.16, and due to spring-projects#34315 and spring-projects#34326 we have recently realized that additional bugs exist with placeholder resolution: nested placeholder resolution can fail when escape characters are used, and it is currently impossible to disable the escape character support for nested resolution. To address this category of bugs, we no longer indirectly use or directly create a "nested" PropertySourcesPropertyResolver in PropertySourcesPlaceholderConfigurer. Instead, properties from property sources from the Environment are now accessed directly without duplicate/nested placeholder resolution. See spring-projectsgh-27947 See spring-projectsgh-34326 See spring-projectsgh-34862 Closes spring-projectsgh-34861
Currently, the placeholder resolution algorithm in PropertySourcesPlaceholderConfigurer fails in several scenarios, and the root cause for this category of failures has actually existed since PropertySourcesPlaceholderConfigurer was introduced in Spring Framework 3.1. Specifically, PropertySourcesPlaceholderConfigurer creates its own PropertySourcesPropertyResolver that indirectly delegates to another "nested" PropertySourcesPropertyResolver to interact with PropertySources from the Environment, which results in double placeholder parsing and resolution attempts, and that behavior leads to a whole category of bugs. For example, #27947 was addressed in Spring Framework 5.3.16, and due to #34315 and #34326 we have recently realized that additional bugs exist with placeholder resolution: nested placeholder resolution can fail when escape characters are used, and it is currently impossible to disable the escape character support for nested resolution. To address this category of bugs, we no longer indirectly use or directly create a "nested" PropertySourcesPropertyResolver in PropertySourcesPlaceholderConfigurer. Instead, properties from property sources from the Environment are now accessed directly without duplicate/nested placeholder resolution. See gh-27947 See gh-34326 See gh-34862 Closes gh-34861
Spring Framework 6.2 introduced support for an escape character for property placeholders (by default '\'). However, as of Spring Framework 6.2.6, there was no way to either escape the escape character or disable escape character support. For example, given a `username` property configured with the value of `Jane.Smith` and a `DOMAIN\${username}` configuration string, property placeholder replacement used to result in `DOMAIN\Jane.Smith` prior to 6.2 but now results in `DOMAIN${username}`. Similarly, an attempt to escape the escape character via `DOMAIN\\${username}` results in `DOMAIN\${username}`. In theory, one should be able to disable use of an escape character altogether, and that is currently possible by invoking setEscapeCharacter(null) on AbstractPropertyResolver and PlaceholderConfigurerSupport (the superclass of PropertySourcesPlaceholderConfigurer). However, in reality, there are two hurdles. - As of 6.2.6, an invocation of setEscapeCharacter(null) on a PropertySourcesPlaceholderConfigurer applied to its internal top-level PropertySourcesPropertyResolver but not to any nested PropertySourcesPropertyResolver, which means that the `null` escape character could not be effectively applied. - Users may not have an easy way to explicitly set the escape character to `null` for a PropertyResolver or PropertySourcesPlaceholderConfigurer. For example, Spring Boot auto-configures a PropertySourcesPlaceholderConfigurer with the default escape character enabled. This first issue above has recently been addressed by spring-projectsgh-34861. This commit therefore addresses the second issue as follows. - To allow developers to easily revert to the pre-6.2 behavior without changes to code or configuration strings, this commit introduces a `spring.placeholder.escapeCharacter.default` property for use with SpringProperties which globally sets the default escape character that is automatically configured in AbstractPropertyResolver and PlaceholderConfigurerSupport. - Setting the property to an empty string sets the default escape character to `null`, effectively disabling the default support for escape characters. spring.placeholder.escapeCharacter.default = - Setting the property to any other character sets the default escape character to that specific character. spring.placeholder.escapeCharacter.default = ~ - Setting the property to a string containing more than one character results in an exception. - Developers are still able to configure an explicit escape character in AbstractPropertyResolver and PlaceholderConfigurerSupport if they choose to do so. - Third-party components that wish to rely on the same feature can invoke AbstractPropertyResolver.getDefaultEscapeCharacter() to obtain the globally configured default escape character. See spring-projectsgh-9628 See spring-projectsgh-34315 See spring-projectsgh-34861 Closes spring-projectsgh-34865
Spring Framework 6.2 introduced support for an escape character for property placeholders (by default '\'). However, as of Spring Framework 6.2.6, there was no way to either escape the escape character or disable escape character support. For example, given a `username` property configured with the value of `Jane.Smith` and a `DOMAIN\${username}` configuration string, property placeholder replacement used to result in `DOMAIN\Jane.Smith` prior to 6.2 but now results in `DOMAIN${username}`. Similarly, an attempt to escape the escape character via `DOMAIN\\${username}` results in `DOMAIN\${username}`. In theory, one should be able to disable use of an escape character altogether, and that is currently possible by invoking setEscapeCharacter(null) on AbstractPropertyResolver and PlaceholderConfigurerSupport (the superclass of PropertySourcesPlaceholderConfigurer). However, in reality, there are two hurdles. - As of 6.2.6, an invocation of setEscapeCharacter(null) on a PropertySourcesPlaceholderConfigurer applied to its internal top-level PropertySourcesPropertyResolver but not to any nested PropertySourcesPropertyResolver, which means that the `null` escape character could not be effectively applied. - Users may not have an easy way to explicitly set the escape character to `null` for a PropertyResolver or PropertySourcesPlaceholderConfigurer. For example, Spring Boot auto-configures a PropertySourcesPlaceholderConfigurer with the default escape character enabled. This first issue above has recently been addressed by gh-34861. This commit therefore addresses the second issue as follows. - To allow developers to easily revert to the pre-6.2 behavior without changes to code or configuration strings, this commit introduces a `spring.placeholder.escapeCharacter.default` property for use with SpringProperties which globally sets the default escape character that is automatically configured in AbstractPropertyResolver and PlaceholderConfigurerSupport. - Setting the property to an empty string sets the default escape character to `null`, effectively disabling the default support for escape characters. spring.placeholder.escapeCharacter.default = - Setting the property to any other character sets the default escape character to that specific character. spring.placeholder.escapeCharacter.default = ~ - Setting the property to a string containing more than one character results in an exception. - Developers are still able to configure an explicit escape character in AbstractPropertyResolver and PlaceholderConfigurerSupport if they choose to do so. - Third-party components that wish to rely on the same feature can invoke AbstractPropertyResolver.getDefaultEscapeCharacter() to obtain the globally configured default escape character. See gh-9628 See gh-34315 See gh-34861 Closes gh-34865
Uh oh!
There was an error while loading. Please reload this page.
Up until spring-boot 3.3.8, an escaped backslash followed by a placeholder like:
Resulted in prop2 resolving to:
Starting with spring-boot 3.4.0, the result is:
Doubling the backslashes like this:
Results in:
This is due to the escaping logic introduced in
org.springframework.util.PlaceholderParser
which does two passes ofPlaceholderParser.SimplePlaceholderPart.resolveRecursively(PartResolutionContext, String)
, each callingPlaceholderParser.parse(String, boolean)
in which the escaping logic is implemented.This last method does not handle escaping the escape character, causing the issue.
The text was updated successfully, but these errors were encountered: