Description
Dan Dowma opened SPR-14375 and commented
Here's the scenario - I'm using Spring's configuration system to load my beans. The actual value that I want to load into my bean is this:
G001.${date:now:yyyyMMdd.HHmmss}
That value will be used in a camel application, and passed into a simple string, which camel will evaluate at runtime. This link shows how I'm trying to use this string value (search for "date")
http://camel.apache.org/simple.html
So I have this class:
@Component
@ConfigurationProperties(prefix="configurationProperties")
public class NameConfigurationProperties {
private String namePattern;
public String getNamePattern() { return namePattern; }
public void setNamePattern(String namePattern) { this.namePattern = namePattern; }
}
The problem is how do I structure a value in a properties file such that I can get the value that I'm looking for.
Obviously this won't work:
configurationProperties.namePattern=G001.${date:now:yyyyMMdd.HHmmss}
^^ evaluates to...:
G001.now:yyyyMMdd.HHmmss
... because the ${} syntax is reserved for variable replacement. In the specific case of the string that I'm trying to load, the date portion evaluates to null (since it is an undefined value), so the now:yyyyMMdd.HHmmss is returned as the default option.
I found a work-around that gives me what I want:
configurationProperties.namePattern=G001.${dollar_sign:$}{date:now:yyyyMMdd.HHmmss}
This works for 2 reasons:
- The ${dollar_sign:$} evaluates to $ because there is no defined value for dollar_sign
- No secondary evaluation occurs for the ${} syntax when using the
@ConfigurationProperties
Different behavior using @Value
I prefer to use @ConfigurationProperties
over @Value
because I generally load alot of properties into beans, and it requires less code rather than annotating every property in the bean with @Value
However, @Value
works differently than @ConfigurationProperties
in a couple of cases.
Consider the scenario when I use @Value
.
@Component
public class NameValues {
@Value("${value.namePattern}")
private String namePattern;
public String getNamePattern() { return namePattern; }
public void setNamePattern(String namePattern) { this.namePattern = namePattern; }
}
Using the work-around from above does not work:
value.namePattern=G001.${dollar_sign:$}{date:now:yyyyMMdd.HHmmss}
Yields:
G001.now:yyyyMMdd.HHmmss
... because @Value
performs another round of variable replacement.
However, this input does give the correct desired output:
value.namePattern=G001.${dollar_sign:$}{dollar_sign:$}{date:now:yyyyMMdd.HHmmss}
... because it looks like @Value
does not perform a third round of variable replacement.
I can use SpEL syntax to create a work-around that works for @Value
, as such:
value.namePattern=G001.#{'$'}{date:now:yyyyMMdd.HHmmss}
Conclusion
I'm a bit surprised that details behind @ConfigurationProperties
and @Value
work differently. Maybe that is by design, and there is likely more to the story than I understand, but regardless, I feel that I need to know the tricks behind either to make my seemingly straight forward scenario work.
Can you design a simpler way to escape the variable replacement mechanism to address this scenario?
Affects: 4.2.6