-
Notifications
You must be signed in to change notification settings - Fork 38k
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
Support escaping prefix and separator in property placeholders [SPR-4953] #9628
Comments
Timo Thomas commented Apache Jakarta Commons-Lang has a similar technology known as "StrSubstitutor" (org.apache.commons.lang.text.StrSubstitutor). There, the default escape character is "$", but it is configurable (independently from the prefix and suffix). I'm using StrSubstitutor on expressions in bean properties, and if there is no escaping, the only (ugly) option left for me is to change one of the prefixes. IMHO not having an escape character nowadays should be considered as a production-critical feature (what if changing the prefix is not an option? The workarounds necessary then are even more ugly) - if not as a bug. |
Eric Haszlakiewicz commented It seems that you can work around this by defining a property that has a value of '$'. e.g. and in the xml config to get a value of e.g. '$foo', you'd write '${dollarsign}foo' It's not pretty, but at least it works. |
Jim Utter commented The workaround does not work when the replacement needs the braces passed through. properties: wiring: or even "${var}foo}" or finally "${var}" still results in an error like: Caused by: org.springframework.beans.factory.BeanDefinitionStoreException: Invalid bean definition with name 'id' defined in class path resource [applicationContext.xml]: Could not resolve placeholder 'foo' For me, I'd like to define concatenated strings like "${var1}-${var2}${var3}" etc.. where the variables would be internally replaced by velocity (requiring the braces when concatenated). |
Joshua Caplan commented The following blog post details a workaround that is available starting from Spring 3.0.x (or whenever SpEL was introduced): http://jazzjuice.blogspot.com/2011/06/escaping-property-placeholders-in.html I still agree that native escaping would be useful, though. |
Aleksandr Dubinsky commented Indeed, However, it is too long (5 characters!). It is poorly documented. It exists by sheer accident. It is really shocking that an escape sequence does not exist. Btw, the alternative of defining a different placeholder sequence is a really, really bad idea. That feature should NOT even be there. Allowing users to arbitrarily re-define the basic syntax of a language leads to confusion. |
Michel Nolard commented
Interesting fact: there is a lot advices on the net to use your trick -- often without referencing your post properly, but this does not remove the need for this issue to be solved anyway ! |
Jan Zidek commented In YAML configuration files,
then it is not ignored, but when the parameter is set by |
Bulk closing outdated, unresolved issues. Please, reopen if still relevant. |
I really would welcome a "fix" for this. In my app I externalized config into When I have I worked around this issue by putting @Value("${my.app.var}")
private String var;
public String getVar() {
return fixed(var);
}
private String fixed(String in) {
return in.replace('@', '$');
} |
Interestingly enough, core support for ignoring nested properties appears to have been in place since Spring Framework 3.2 via the However, Here's a JUnit Jupiter based test case for experimentation: package example;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import static org.assertj.core.api.Assertions.assertThat;
@SpringJUnitConfig
// Using the following SpEL hack allows the test to pass.
// @TestPropertySource(properties = "my.app.var = #{'$'}{var}")
@TestPropertySource(properties = "my.app.var = ${var}")
class IgnoredPlaceholderTests {
@Value("${my.app.var}")
String value;
@Test
void test() {
assertThat(value).isEqualTo("${var}");
}
@Configuration
static class Config {
@Bean
static PropertySourcesPlaceholderConfigurer pspc() {
PropertySourcesPlaceholderConfigurer pspc = new PropertySourcesPlaceholderConfigurer();
pspc.setIgnoreUnresolvablePlaceholders(true);
return pspc;
}
}
} @jhoeller, what do you think about either introducing support for escaping placeholders or providing a mechanism for configuring the |
it's amazing the issue lasts for more than ten years. When I use sharding-jdbc which configuration also need '${xxx}', I faced this problem. |
Will it be fixed at all? |
Any progress? Any comment? :) |
This commit allows to escape property placeholders to later processed by user. PropertyPlaceholderHelper allows to set custom escape character. "\" is used as the default one. Closes spring-projectsgh-9628 Signed-off-by: Dmitrii Bocharov <[email protected]>
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
@snicoll : my frustration stems mostly from the feeling that the team waste their valuable time with destructive changes which nobody wants, instead of addressing the actual issues or even bugs, reported and complained about for 10+ years. The recent "trailing slash upgrade" broke literally thousands of enterprise applications. You should not be surprised that someone may be frustrated. |
This commit provides a rewrite of the parser for properties containing potentially placeholders. Assuming a source where `firstName` = `John` and `lastName` = `Smith`, the "${firstName}-${lastName}" property is evaluated as "John-Smith". Compared with the existing implementation in PropertyPlaceholderHelper, the new implementation offers the following extra features: 1. Placeholder can be escaped using a configurable escape character. When a placeholder is escaped it is rendered as is. This does apply to any nested placeholder that wouldn't be escaped. For instance, "\${firstName}" is evaluated as "${firstName}". 2. The default separator can also be escaped the same way. When the separator is escaped, the left and right parts are not considered as the key and the default value respectively. Rather the two parts combined, including the separator (but not the escape separator) are used for resolution. For instance, ${java\:comp/env/test} is looking for a "java:comp/env/test" property. 3. Placeholders are resolved lazily. Previously, all nested placeholders were resolved before considering if a separator was present. This implementation only attempts the resolution of the default value if the key does not provide a value. 4. Failure to resolve a placeholder are more rich, with a dedicated PlaceholderResolutionException that contains the resolution chain. See spring-projectsgh-9628 See spring-projectsgh-26268
This commit removes the previous implementation in favor of the new PlaceholderParser. The only noticeable side effect is that the exception is no longer an IllegalArgumentException, but rather the dedicated PlaceholderResolutionException. See spring-projectsgh-9628
This commit provides a rewrite of the parser for properties containing potentially placeholders. Assuming a source where `firstName` = `John` and `lastName` = `Smith`, the "${firstName}-${lastName}" property is evaluated as "John-Smith". Compared with the existing implementation in PropertyPlaceholderHelper, the new implementation offers the following extra features: 1. Placeholder can be escaped using a configurable escape character. When a placeholder is escaped it is rendered as is. This does apply to any nested placeholder that wouldn't be escaped. For instance, "\${firstName}" is evaluated as "${firstName}". 2. The default separator can also be escaped the same way. When the separator is escaped, the left and right parts are not considered as the key and the default value respectively. Rather the two parts combined, including the separator (but not the escape separator) are used for resolution. For instance, ${java\:comp/env/test} is looking for a "java:comp/env/test" property. 3. Placeholders are resolved lazily. Previously, all nested placeholders were resolved before considering if a separator was present. This implementation only attempts the resolution of the default value if the key does not provide a value. 4. Failure to resolve a placeholder are more rich, with a dedicated PlaceholderResolutionException that contains the resolution chain. See gh-9628 See gh-26268
This commit removes the previous implementation in favor of the new PlaceholderParser. The only noticeable side effect is that the exception is no longer an IllegalArgumentException, but rather the dedicated PlaceholderResolutionException. See gh-9628
To smooth upgrade from 6.1.x, this commit makes sure that code that used to catch an IAE to ignore a faulty placeholder resolution still works. See gh-9628
Chris Lee opened SPR-4953 and commented
There is presently no way to inject a placeholder expression (
${...}
) that won't be picked up byPropertyPlaceholderConfigurer
. Ideally we should be able to inject a string that contains${...}
for later use in its target bean without involvement fromPropertyPlaceholderConfigurer
.Perhaps a simple escape mechanism using the conventional backslash, such as
"The current value is \\${...}"
would suffice.Affects: 2.5.4, 2.5.5
11 votes, 5 watchers
The text was updated successfully, but these errors were encountered: