test failed when i use #Value [duplicate] - java

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.

Related

Int from application.properties

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.

#ConfigurationProperties and unresolvable properties

Suppose the following configuration bean:
#ConfigurationProperties(prefix="foo")
private class FooProperties {
private String mystring;
private int myint;
}
and the following application.properties:
foo.mystring = ${bar.mystring}
foo.myint = ${bar.myint}
Notice the two properties are unresolvable since no properties starting with bar are defined. Here is what will happen:
foo.mystring is set to the string "${bar.mystring}" (without resolution)
foo.myint will cause a conversion error since the string "${bar.myint}" cannot be converted into a valid integer.
I would instead expect a kind of Unresolvable Property exception being thrown in this case. Just like what would happen if I had use #Value("${foo.mystring}").
Is that behavior expected?
Is there a way to make SpringBoot throw such exception in this case?
I would instead expect a kind of Unresolvable Property exception being
thrown in this case.
foo.myint is not throwing Unresolvable Property exception as it is getting resolved with ${bar.myint} whereas it fails at next step when Spring try to typecast String to int as every thing you store inside a Properties file is a String value unless you explicitly specified it's type, as:
foo.myint = (java.lang.Integer)${bar.myint}
Is that behaviour expected?
Probably Yes.
Is there a way to make SpringBoot throw such exception in this case?
Yes, for Global level you can use #ControllerAdvice and if you want to have it at Controller level then you can go with #ExceptionHandler

Spring 4 #Value where property default is a java system property

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}}")

Java Hibernate field access property or property based access

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.

#Value annotation type casting to Integer from String

I'm trying to cast the output of a value to an integer:
#Value("${api.orders.pingFrequency}")
private Integer pingFrequency;
The above throws the error
org.springframework.beans.TypeMismatchException:
Failed to convert value of type 'java.lang.String' to required type 'java.lang.Integer';
nested exception is java.lang.NumberFormatException:
For input string: "(java.lang.Integer)${api.orders.pingFrequency}"
I've also tried #Value("(java.lang.Integer)${api.orders.pingFrequency}")
Google doesn't appear to say much on the subject. I'd like to always be dealing with an integer instead of having to parse this value everywhere it's used.
Workaround
I realize a workaround may be to use a setter method to run the conversion for me, but if Spring can do it I'd rather learn something about Spring.
Assuming you have a properties file on your classpath that contains
api.orders.pingFrequency=4
I tried inside a #Controller
#Controller
public class MyController {
#Value("${api.orders.pingFrequency}")
private Integer pingFrequency;
...
}
With my servlet context containing :
<context:property-placeholder location="classpath:myprops.properties" />
It worked perfectly.
So either your property is not an integer type, you don't have the property placeholder configured correctly, or you are using the wrong property key.
I tried running with an invalid property value, 4123;. The exception I got is
java.lang.NumberFormatException: For input string: "4123;"
which makes me think the value of your property is
api.orders.pingFrequency=(java.lang.Integer)${api.orders.pingFrequency}
I was looking for the answer on internet and I found the following
#Value("#{new java.text.SimpleDateFormat('${aDateFormat}').parse('${aDateStr}')}")
Date myDate;
So in your case you could try with this
#Value("#{new Integer('${api.orders.pingFrequency}')}")
private Integer pingFrequency;
I had the exact same situation. It was caused by not having a PropertySourcesPlaceholderConfigurer in the Spring context, which resolves values against the #Value annotation inside of classes.
Include a property placeholder to solve the problem, no need to use Spring expressions for integers (the property file does not have to exist if you use ignore-resource-not-found="true"):
<context:property-placeholder location="/path/to/my/app.properties"
ignore-resource-not-found="true" />
If you want to convert a property to an integer from properties file there are 2 solutions which I found:
Given scenario: customer.properties contains customer.id = 100 as a field and you want to access it in spring configuration file as integer.The property customerId is declared as type int in the Bean Customer
Solution 1:
<property name="customerId" value="#{T(java.lang.Integer).parseInt('${customer.id}')}" />
In the above line, the string value from properties file is converted to int type.
solution 2: Use some other extension inplace of propeties.For Ex.- If your properties file name is
customer.properties then make it customer.details and in the configuration file use the below code
<property name="customerId" value="${customer.id}" />
If you are using #Configuation then instantiate below static bean. If not static #Configutation is instantiated very early and and the BeanPostProcessors responsible for resolving annotations like #Value, #Autowired etc, cannot act on it. Refer here
#Bean
public static PropertySourcesPlaceholderConfigurer propertyConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
I had the same issue I solved using this. Refer this Spring MVC: #Value annotation to get int value defined in *.properties file
#Value(#{propertyfileId.propertyName})
works
when use #Value, you should add #PropertySource annotation on Class, or specify properties holder in spring's xml file.
eg.
#Component
#PropertySource("classpath:config.properties")
public class BusinessClass{
#Value("${user.name}")
private String name;
#Value("${user.age}")
private int age;
#Value("${user.registed:false}")
private boolean registed;
}
config.properties
user.name=test
user.age=20
user.registed=true
this works!
Of course, you can use placeholder xml configuration instead of annotation.
spring.xml
<context:property-placeholder location="classpath:config.properties"/>
This problem also occurs when you have 2 resources with the same file name; say "configurations.properties" within 2 different jar or directory path configured within the classpath. For example:
You have your "configurations.properties" in your process or web application (jar, war or ear). But another dependency (jar) have the same file "configurations.properties" in the same path. Then I suppose that Spring have no idea (#_#?) where to get the property and just sends the property name declared within the #Value annotation.
In my case, the problem was that my POST request was sent to the same url as GET (with get parameters using "?..=..") and that parameters had the same name as form parameters. Probably Spring is merging them into an array and parsing was throwing error.
Since using the #Value("new Long("myconfig")") with cast could throw error on startup if the config is not found or if not in the same expected number format
We used the following approach and is working as expected with fail safe check.
#Configuration()
public class MyConfiguration {
Long DEFAULT_MAX_IDLE_TIMEOUT = 5l;
#Value("db.timeoutInString")
private String timeout;
public Long getTimout() {
final Long timoutVal = StringUtil.parseLong(timeout);
if (null == timoutVal) {
return DEFAULT_MAX_IDLE_TIMEOUT;
}
return timoutVal;
}
}

Categories