Reputation: 19916
In a Spring YAML configuration file, I need to have a parameter like
csv:
file:
pattern: /some/path/${app-name}.csv
where the ${app-name}
is dynamically replaced in run time by the Java code, and I do not want Spring to replace it at the startup.
To achieve this, I need to escape the $
character so Spring does not interpret it as SpEL.
The following answers do not work in YAML:
I tried all the combinations, like
pattern: /some/path/\${app-name}.csv
pattern: "/some/path/\${app-name}.csv"
pattern: /some/path/#{'$'}{app-name}.csv
pattern: "/some/path/#{'$'}{app-name}.csv"
and none of them produces the variable containing the requested string, with the dollar sign but without the escape characters.
Please notice that it is YAML configuration. In YAML files, #
is the line comment character, everything from this character on is ignored. And if I use \#
, the \
is then passed to the string.
ADDED: There has been an Spring project open issue 9628 open since 25.06.2008:
There is presently no way to inject a ${...} expression that won't be picked up by PropertyPlaceholderConfigurer. Ideally we should be able to inject a string that contains ${...} for later use in its target bean without involvement from PropertyPlaceholderConfigurer.
Upvotes: 16
Views: 19218
Reputation: 3878
Use a combination of empty key and dollar sign $
as default value:
csv:
file:
pattern: /some/path/${:$}{app-name}.csv
TIP: If you want to escape a Simple Expression in Apache Camel:
"You can also use the alternative syntax which uses
$simple{ }
as placeholders. This can be used in situations to avoid clashes when using, for example, Spring property placeholder together with Camel."
Upvotes: 6
Reputation: 39638
Spring currently does not offer an escaping mechanism for property placeholders, there is an open issue (opened on 25.06.2008):
There is presently no way to inject a placeholder expression (
${...}
)
In the comments, this workaround is mentioned (I am not sure whether it works with YAML):
csv:
file:
pattern: /some/path/#{'$'}{app-name}.csv
Note that when used after whitespace or at the beginning of a line, #
in YAML starts a comment.
Upvotes: 3
Reputation: 9
You need to use #{'$'}
and as you use yaml you need to surround the value with double quotes:
csv:
file:
pattern: "/some/path/#{'$'}{app-name}.csv"
Upvotes: 0
Reputation: 2027
I've encountered a same problem. So you can resolve this by using yaml literal style symbol "|
" , or by using literal_strip "|-
" like following example.
application.yml
csv:
file:
pattern: |-
/some/path/${app-name}.csv
Actually My problem is config a formula in yml and then dynamic resolve the expression in java. Sharing the solution here.
I choose spring el solution and use spring version 5.0.9.RELEASE
.
I define a formular in yml,
score:
formula: |-
10 * #x + #y
Then in a spring component bean,
@Value("${score.formula}")
String scoreFormula;
At last by using spring el,
ExpressionParser parser = new SpelExpressionParser();
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
context.setVariable("x", 1);
context.setVariable("y", 1);
Integer score = parser.parseExpression(scoreFormula).getValue(context,Integer.class);
reference
Upvotes: 4
Reputation: 353
Actually none of the answers worked for me. However, adding a double dollar sign worked for me fine:
csv:
file:
pattern: /some/path/$${app-name}.csv
Upvotes: 0
Reputation: 9
Why not try using ${sys:$}
which is ugly but effective. I think no one will use $
as the key.
Upvotes: 0
Reputation: 163
I had the same problem, i just found dumb clever solution
define a property named dollarSign or ds for short.
ds: "$"
then use it like so, ${ds}
will be replace by $
at runtime.
csv:
file:
pattern: /some/path/${ds}{app-name}.csv
it was kind of funny when it worked.
Upvotes: 7
Reputation: 2371
The answer really depends on how exactly you inject values into your code. Since you haven't provided it yet, I'll just list the various working techniques.
@Value
annotation to inject your property. Since, unlike @ConfigurationProperties
, @Value
does SpEL evaluation, you have to escape your value.application.yml:
csv:
file:
pattern: /some/path/#{'$'}{app-name}.csv
TestController.java:
@RestController
public class TestController {
@Value("${csv.file.pattern}") private String pattern;
@GetMapping("pattern") public ResponseEntity<String> getPattern() {
return ResponseEntity.ok(pattern);
}
}
A GET to /pattern
would result in an output /some/path/#{app-name}.csv
, just as you needed
@ConfigurationProperties
, and here it really depends on how you structure your configuration objects. Generally, though, @ConfigurationProperties
should require no escaping, as they don't support SpEL by default. The following works, though, so if your setup is different, modify it:application.yml:
csv:
file:
pattern: /some/path/#{app-name}.csv
Config.java:
@ConfigurationProperties(prefix = "csv.file")
public class Config {
private String pattern;
public String getPattern() { return pattern; }
public void setPattern(String pattern) { this.pattern = pattern; }
}
TestController.java:
@RestController
public class TestController {
@Autowired private Config config;
@GetMapping("pattern") public ResponseEntity<String> getPattern() {
return ResponseEntity.ok(config.getPattern());
}
}
Again, a GET to /pattern
would result in an output /some/path/#{app-name}.csv
What you most likely have is some different structure in your Config.java (post the relevant code, maybe?), and this could cause the property to not be processed properly.
Upvotes: 0