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
Comment From: spring-projects-issues
Allen AI HUA commented
Hi @Nicoll
,
I faced the same issue of using spring and apache camel, it can be resolved by below configuration:
dollar=$ value.namePattern=G001.${dollar}{date:now:yyyyMMdd.HHmmss}
Comment From: snicoll
Apologize for the delay. The need here is to be able to escape the placeholder syntax so that the value is evaluated as is. This is what we're investigating as part of #9628.
In practice it would boil down to escape the $
prefix, something like 001.\${date:now:yyyyMMdd.HHmmss}
would evaluate to 001.${date:now:yyyyMMdd.HHmmss}
. I am closing this issue as a duplicate of the one I referenced.