In Spring 4, using the #Value annotation, what is the right way to specify a system property as a default if a specified property does not exists?
Whereas this works for the no-default case:
#Value("${myapp.temp}")
private String tempDirectory;
This doesn't work when I need a default:
#Value("#{myapp.temp ?: systemProperties.java.io.tmpdir}")
private String tempDirectory;
Nor does this:
#Value("#{myapp.temp ?: systemProperties(java.io.tmpdir)}")
private String tempDirectory;
Both of these give me an exception at the time Spring is trying to create the bean:
org.springframework.beans.factory.BeanCreationException: Error creating bean
with name 'configurationService': Invocation of init method failed;
nested exception is java.lang.NullPointerException
Can this be done?
I tried the following and it worked for me:
#Value("${myapp.temp:#{systemProperties['java.io.tmpdir']}}")
private String tempDirectory;
The missing parts for you I believe was not using ?: and needing the #{}. According to this answer:
${...} is the property placeholder syntax. It can only be used to dereference properties.
#{...} is SpEL syntax, which is far more capable and complex. It can also handle property placeholders, and a lot more besides.
So basically what is happening is we are telling Spring to first interpret myapp.temp as property placeholder syntax by using the ${} syntax. We then use : instead of ?: (which is called the Elvis operator) since the elvis operator only applies to Spring Expression Language expressions, not property placeholder syntax. The third part of our statement is #{systemProperties['java.io.tmpdir']} which is telling Spring to interpret the next expression as a Spring Expression and allows us to get system properties.
Try systemProperties['java.io.tmpdir'].
It's a map, so if the key has a dot in the name, you should use [..]
For me it only works with different property-names (being property.name.a a key with a value in my application.properties and property.name.b a Environment-Variable) like:
#Value("${property.name.a:${property.name.b}}")
The same names didn´t work for me like expected (loading the default, when the first property isn´t present), e.g.:
#Value("${property.name.a:${property.name.a}}")
Related
I tried the approach mentioned on How get property name in a validation message, but cannot apply it to the following situation.
#Data
public class CompanyRequest {
#PositiveOrZero(message = "validation.amount.positiveOrZero")
int quantity;
// code omitted for brevity
}
Here is my *.properties file having message:
validation.amount.positiveOrZero=The ${fieldName} value must be positive or zero
So, how can I use the property name in the validation message?
${fieldName} could not be retrieved easily inside the annotation without major modifications inside the core mechanism that makes the evaluation.
An easier way to achieve what you want, considering that for each field the name would be different, is the following.
Inside properties file put the property
validation.amount.positiveOrZero= value must be positive or zero
And then define the annotation in the code as
#PositiveOrZero(message = "The quantity {validation.amount.positiveOrZero}")
int quantity;
Edit:
It seems that the property should not be defined in a simple application.properties file but in another file named ValidationMessages.properties in the classpath.
As documented here
setValidationMessageSource(MessageSource messageSource) Specify a
custom Spring MessageSource for resolving validation messages, instead
of relying on JSR-303's default "ValidationMessages.properties" bundle
in the classpath.
I am trying to create custom annotation for one of my use case.
#MyAnnotation(key = "constantString-${os.version}-{ #userId }"
public void methodName(String userId)
I am trying to SpEL parser to parse key field of the annotation. I want to support constant strings, application properties and method properties as a part of the key field.
So in above example, I am expecting evaluated key field will be
constantString-1.10-abc ("abc" is the value of the user argument while calling method)
But I am getting an error
EL1008E: Property or field 'constantString' cannot be found on object of type 'java.lang.reflect.Method' - maybe not public or not valid?
I am struggling to get SpEL honor constant string as a part of expression, as it keeps complaining while evaluating expression.
Is there a way in SpEL we can have constant string, property and method arguments supported?
Thanks
I am using sprin version 4.3.8.RELEASE. also i am using #Value to inject values from property file, if the properties are string that no problem, but if the property is Integer that is a problem (i know there is many questions about this i tried all the answers but the issue still exist)
The property is
CONNECTION.TIME.OUT=100000
First solution
#Value("${CONNECTION.TIME.OUT}")
protected Integer connectionTimeOut;
Ecxeption
Failed to convert value of type 'java.lang.String' to required type 'java.lang.Integer'; nested exception is java.lang.NumberFormatException: For input string: "${CONNECTION.TIME.OUT}"
Second solution
#Value("#{new Integer('${CONNECTION.TIME.OUT}')}")
protected Integer connectionTimeOut;
Exception
EL1003E: A problem occurred whilst attempting to construct an object of type 'Integer' using arguments '(java.lang.String)'
Third solution
#Value("#{new Integer.parseInteger('${CONNECTION.TIME.OUT}')}")
protected Integer connectionTimeOut;
Exception
EL1003E: A problem occurred whilst attempting to construct an object of type 'Integer' using arguments '(java.lang.String)'
any ideas why is that
To avoid such type of situation where the exception occurs due to un-availibilty of the property, Add default value in the tag. If property is not available then it will populate the default value
#Value("${CONNECTION.TIME.OUT:10}")
Your property file is probably not loaded properly.
When provided with no valid value for a property placeholder, Spring will automatically try to assign this value to the name of the #Value annotation. In your case, this:
#Value("#{new Integer('${CONNECTION.TIME.OUT}')}")
protected Integer connectionTimeOut;
Is interpreted as:
protected Integer connectionTimeOut = new Integer("${CONNECTION.TIME.OUT}");
Which, indeed, brings an error.
Try to either configure a PropertyPlaceholderConfigurer in your beans, or make sure that your property file is loaded properly in your classpath by your configuration. Something among the lines of:
<context:property-placeholder
ignore-unresolvable="true"
location="classpath:yourfile.properties" />
In your configuration file will help, in this case.
For #Value("${CONNECTION.TIME.OUT}") your error is java.lang.NumberFormatException: For input string: "${CONNECTION.TIME.OUT}". This means that expression was not processed resulting in Integer.parseInt("${CONNECTION.TIME.OUT}") which thrown the NumberFormatException.
Either there is no PropertyPlaceholderConfigurer bean registered in the Spring context and #Value annotations are not processed or there is no property CONNECTION.TIME.OUT defined.
Try removing single quotes worked ''. It worked for me.
#Value("#{new Integer(${CONNECTION.TIME.OUT})}")
Don't forget the "${}" around it! I kept looking at what should have been obvious and missing it.
I have following code in my tml file:
<t:loop source="navItem.subPages" value="var:subPage">
<t:any element="li" class="prop:classForPageName">
<t:pagelink page="var:subPage">${getMenuPageName(var:subPage)}</t:pagelink>
</t:any>
</t:loop>
I have a problem to pass a variable var:subPage to method ${getMenuPageName(var:subPage)}, as this throws an exception:
Could not convert 'getMenuPageName(var:subPage)' into a component parameter binding: Error parsing property expression 'getMenuPageName(var:subPage)': line 1:15 no viable alternative at input '('.
You can't use binding prefixes (like var:) inside property expressions.
You may only use prefix in front of the expression to let Tapestry know how it should interpret the remainder (the part after the colon).
Refer to NBF grammar for property expressions to see what's allowed inside:
Tapestry Documentation > User Guide > Property Expressions.
Property expressions were created to support just very basic constructs. If you need more complex expressions you should create corresponding methods in your java class and refer to them using the prop: binding prefix.
Template expansions you've mentioned (${...}) work the same as parameter bindings:
Under the covers, expansions are the same as parameter bindings. The
default binding prefix for expansions is "prop:" (that is, the name of
a property or a property expression), but other binding prefixes are
useful, especially "message:" (to access a localized message from the
component's message catalog).
i am developing some improvements over a legacy system have some quite time
i have a class like this
class MyPersistentClazz
{
private String aTPlace;
public void setATPlace(.......){......}//yes mistyping
#Column(name="atPlaceOrder")
public String getATPlace(){return aTPlace;}
}
they usually load this class using this methods
final MyPersistentClazz clazz = (MyPersistentClazz)session.createCriteria(MyPersistentClazz.class).add(idEq(id)).uniqueResult();
and using load and get methods and works OK.
but the problem arise when i use projections.
final Projection p=Projections.projectionList().add(Projections.property("d.aTPlace"),"aTPlace");
throws
Exception in thread "main" org.hibernate.QueryException: could not resolve property:
my question is...
when using projections i think Hibernate is calling the setter of each property is this assertion OK?
when using criteria.uniqueResult or load or get Hibernate use individual field property access?
or why works with some and not work with others with the same setter?
we are using only annotations not XML.
thanks a lot.
How Hibernate works with your bean depends on how you annotated it. If you annotate instance variables then Hibernate will use direct injection and bypass your Set methods. Otherwise, it will use your Set methods.
Could it be that it is incorrectly converting your property name to a Set method name? Try changing the property name to something simpler (without that series of capital letters), and ensure that the case of the property in your projection is correct.