I want to access a property value in my annotation, as an attribute's value.
For ex. in my property file I have an entry expression: 3/10 * * * * ?.
In my Scheduler class I use annotation #Scheduled (cron = "**VALUE**"). I want to read this value from the properties file corresponding to the expression key.
Tried doing this with #Value, but it returns a type of Value which cannot be converted to String.
From spring 3.0.1 you can do it like this
#Scheduled(cron = "${rates.refresh.cron}")
Refer to
http://forum.springsource.org/showthread.php?83053-Feature-Scheduled-with-Value-cron-expression
However, you cannot do this for fixDelay and fixRate due to type casting problem (fixDelay expects value in long, while annotation return String only). Check Mark's comments in https://jira.springsource.org/browse/SPR-6670
You can try to use the APT (annotation processing tool) to replace the value in the annotation with a value from the property file.
Related
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
In application.properties:
comment.length=3000
Now I'd like to use this constant:
#Entity(name="clients_client")
public class Client {
#Column(length="${comment.length}")
private String comment;
}
When compiling, I get this error:
java: incompatible types: java.lang.String cannot be converted to int
This is very close to being a duplicate of How to import value from properties file and use it in annotation?, but I think there is a subtle difference between the questions.
You are trying to refer to a property in the #Column annotation by using ${comment.length}. What is really happening is that you try to assign the String "${comment.length}" to the length attribute of the annotation. This is of course not allowed, it expects an int.
Java, or Spring, can not "magically" replace ${propertyName} with a property. Spring, however, has its own way of injecting property values:
#Value("${value.from.file}")
private String valueFromFile;
Even if your entity was a Spring bean (for example annotated with #Component), and you injected the property with #Value, it cannot be used in the annotation. This is because values in annotations need to be constant, and is explained in more detail in the accepted answer to the near duplicate question.
Now I'd like to use this constant:
It simply is not a constant, it is determined at runtime.
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.
Given a appplication.config which contains fixed values and optional overwrites as for example like this:
timeout.seconds = 30
timeout.seconds=${?SSO_TIMEOUT_SECONDS}
using com.typesafe.config
which function does return the config with fully parsed entries?
e.g
timeout.seconds = 99
if it has been set externally otherwise the default value.
NOT returned should be the config with preset values AND optional replacements.
I tested
ConfigFactory.defaultApplication()
but that does return both. Although the description makes me think it would not.
You can load the default config using
ConfigFactory.load()
This will replace any substitutions with the appropriate values.
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}}")