I have a property set to "true", that I want to bind to my checkStatus field.
#Value("${prop.checkstatus}")
private boolean checkStatus;
I am able to access the value from inside an #Service class. However, if I use #Value inside a class that I instantiate or retrieve using AppliationContext.getBean("classA"), the value is always "false" since it cannot get the correct value from the property file. Please advise as I need to access this value from an instance and from a bean.
In some parts of the code, I create the object using new and try to access #Value. I understand that this is not possible since the new object is not managed by spring. But there are parts of the code where the object is retrieved using applicationcontext. Still I cannot access the #Value. Is there a better approach in retrieving #Value both for objects created using new and applicationcontext.getbean?
Related
I'm trying to initialize Spring bean with request scope, and lazy initialization from another object (attributes) that are not managed by Spring.
Here is the bean definition :
#Component
#Scope(value = "request")
#Lazy
public class LazyClass {
protected String name;
}
How do I init the 'name' attribute at runtime ?
It may not be the best solution but you can set the value of name into a System property and get it where you need it in your class.
Setting the value somewhere in a non-spring class:
// myProperty is the name of the property
// name is the value you want to store
System.setProperty("myProperty",name);
Getting inside your class:
// Caution: the name of the property must be the same as it was when it was set
String name = System.getProperty("myProperty);
The getting method can be called in the constructor of your bean class as it is marked as #Lazy.
EDIT:
Another way is to create a setter for the field name and set its value when you need it.
I'm already familiar with the base behavior of Spring's #Value annotation to set a field to the value of a project property like so:
Project's Property File
foo.bar=value
Project's Configuration Class
#Configuration
public class MyConfig {
#Value("${foo.bar}")
private String myValue;
}
However I'm trying to make a SpringBoot starter project with conditional configuration and would like to standardize the property names to something useful such as "com.mycompany.propertygroup.propertyname", but to ease transition and encourage adoption, I want to support the old property names for a time as well, and was thus wondering if there was some way to allow multiple property names to set the same field? For instance:
My Theoretical Starter's Config
#Configuration
public class MyConfig {
#Value("${com.mycompany.propertygroup.propertyname}" || "${oldconvention.property}")
private String myValue;
}
Project A's Property
oldconvention.property=value
Project B's Property
com.mycompany.propertygroup.propertyname=value
I can't seem to find any documentation or SO answers on whether or not this is possible and how to achieve it if so... So I'm wondering if it is possible, or if it's not, is there an alternative to the #Value annotation that can be used to achieve the same effect?
Edit to Clarify:
I would not want to keep track of multiple values so I do not need instruction on how to get multiple values... the objective is to consolidate into a SINGLE VALUE that which may have multiple names. In practice, it would only ever have one name-value per project that uses the starter... only in rare cases when someone perhaps forgot to delete the old property would each property name be used (and it would probably have the same value anyway). In such cases, the NEW CONVENTION NAME-VALUE WOULD BE THE ONLY ONE USED.
Update
While the SpEL expression answers provided works when both properties are present, the application context cannot load when only one of the property names is present. Example:
Updated Configuration Class
#Value("#{'${com.mycompany.propertygroup.propertyname}' != null ? '${com.mycompany.propertygroup.propertyname}' : '${oldconvention.propertyname}'}"
private String myProperty;
Updated Property File
com.mycompany.propertygroup.propertyname=somevalue
Error
Caused by: java.lang.IllegalArgumentException:
Could not resolve placeholder 'oldconvention.propertyname' in value
"#{'${com.mycompany.propertygroup.propertyname}' != null ? '${com.mycompany.propertygroup.propertyname}' : '${oldconvention.propertyname}'}"
Requiring both property names to be present defeats the purpose, which is to allow an implementing project to configure this starter using EITHER the old convention OR the new convention...
Another Update...
I've been playing around with the SpEL expression a bit, and I've got the conditional check working when the property is present and when it's not, but I'm having trouble with property resolution after the fact. I think the problem is because property defaults and complex SpEL expressions don't play nice together.
#Value("#{${com.mycompany.propertygroup.propertyname:null} != null ? '${com.mycompany.propertygroup.propertyname}' : '${oldconvention.propertyname}'}")
private String myProperty;
When my SpEL is written like the above, I get a cannot resolve property placeholder exception, meaning that both properties have to be present in order for the SpEL expression to evaluate. So I got to thinking, I could use the default property syntax that I've seen for resolving optional properties: #Value("${myoptionalproperty:defaultValue}")
So below is my attempt to combine the default property resolution with the SpEL expression:
#Value("#{${com.mycompany.propertygroup.propertyname:null} != null ? '${com.mycompany.propertygroup.propertyname:}' : '${oldconvention.propertyname:}'}")
private String myProperty;
When using the default property notation, I keep getting this error:
org.springframework.expression.spel.SpelParseException:
EL1041E: After parsing a valid expression, there is still more data in the expression: 'colon(:)'
and when I Googled that error, the popular answer was that properties had to be wrapped in single quotes so that they evaluate to a string... but they're already wrapped (except the first one.. I had to unwrap that one since I wanted that to evaluate to a literal null for the null check). So I'm thinking that defaults can't be used with properties when they're wrapped in a spell expression. In truth, I've only ever seen the default property set when a #Value annotation is set with just a pure property holder, and all properties I've seen used in a SpEL expression never had a default set.
You can use the following #Value annotation:
#Configuration
public class MyConfig {
#Value("#{'${com.mycompany.propertygroup.propertyname:${oldconvention.propertyname:}}'}")
private String myValue;
}
This #Value annotation uses com.mycompany.propertygroup.propertyname if it is provided and defaults to oldconvention.property if com.mycompany.propertygroup.propertyname is not provided. If neither is provided, the property is set to null. You can set this default to another value by replacing null with another desired value.
For more information, see the following:
Spring Expression Language (SpEL)
Spring Expression Language Guide
As an alternative, you can capture both values and do a selection before returning the value:
#Configuration
public class MyConfig {
#Value("${com.mycompany.propertygroup.propertyname:}")
private String newValue;
#Value("${oldconvention.propertyname:}")
private String oldValue;
public String getValue() {
if (newValue != null && !newValue.isEmpty()) {
// New value is provided
System.out.println("New Value: " + newValue);
return newValue;
}
else {
// Default to the old value
return oldValue;
}
}
}
Using SPEL is the best way to solve this. This should work
#Value("#{'${com.mycompany.propertygroup.propertyname}' != null ? '${com.mycompany.propertygroup.propertyname}' : '${oldconvention.property}'}")
private String myValue;
No that's not possible I believe but yes you can define property as comma separated. For example
com.mycompany.propertygroup.propertyname=value1,value2,value3
And instead of receiving a String you can annotate #Value over String[] like this:
#Value("#{'${com.mycompany.propertygroup.propertyname}'.split(',')}")
private String[] propertyNames;
Another way you can also store key and value as a comma-separated string in the property file and use #Value annotation you can map into Map, For example, you want group name as key and value as group details so in the property file you can store string like this
group.details.property= {'group1':'group1.details','group2':'group2.details'}
And you can annotate #Value as
#Value("#{${group.details.property}}")
private Map<String, String> groupMap;
How can I access this value, the max value and message from the controller
I try to access the information schema table, do it via sql and access this variable without writing it directly in the code,
I was trying to access the schema Information table, to get the maximum value from the column but it generates an error that is not mapped
thank you very much and sorry, I'm new to this
There are 2 options to do this.
Since the value is constant, you can declare a static final variable and use it as the class variable.
eg:
static final int MAX_RANGE = 100;
In this case, just use "class_name".MAX_RANGE
You could also specify the value in a property file and use the property file as and when needed.
You can use reflection (which is not the best case)
Class<?> cls = Class.forName(name);
cls.getDeclaredAnnotations(); // get all annotation
(cls.getDeclaredMethods()[0]).getAnnotations(); //get annotation of a method
Annotation ety = cls.getAnnotation(Annotation.class); // get annotation of particular annotation class
In login Action I am checking user authentication, and if it is validated, I am putting the user bean into sessionMap:
public String execute()
{
if(userValid)
sessionMap.put("userBean", userBean); //userBean retrieved from DB
}
Now on the landing jsp, when trying to retrieve the session items:
<s:property value="#session.userBean.name" />
Obviously this would return an Object type, as I am storing it that way, so how can I type caste this to UserBean class.
I was expecting to get a solution for this on Google, but found it nowhere since this seems to be a basic implementation. So please let me know if there is any other way to implement this functionality using Struts2.
This works fine for me...
<sp:property value="#session.usertype"/>
<sp:property value="#session.bean.loginID"/>
This both worked fine for me...
sessionMap.put("bean", loginBean);
sessionMap.put("usertype", loginBean.getUserType());
I declared something like this....
Just make sure that in property tag you you same name you used while setting the bean in sessionMap ....
This should probably work....
Obviously you can't cast it to UserBean class if the object is not the instance of that class. In the value attribute you have put a string "#session.userBean.name". Struts parse this string for OGNL expression and if it's a valid expression that returns a value, it will replace it with that value. The returned type is Object, but this type is determined by ValueStack implementation.
Then property tag writes this object to the out. It uses toString() to convert the object to string. And if your object implements this method, then this value would be written.
Looks like your expression returns an Object, which has instance type String, so it's already implemented this method.
Using seam-gen based code. I have an object "Classroom", which contains an instance of "Location". I want to query for classrooms but specifying a value on the Location object.
Something like 'select from Classroom where Location.State = "NY"'. When I try to bind a selectOneMenu with a list of states to #{ClassroomList.classroom.location.state} I'm getting errors.
Was getting a null pointer exception on Location. I'm assuming I need to instantiate a new "Location" on the Classroom object, but not sure where to do that. On the Classroom entity's constructor? On the ClassroomList backing bean (where the example object is bound to the ClassroomList JSP search fields)?
Yes, you need to instantiate ClassroomList.instance.Location. Because the ClassroomList.instance is not bound to the Database, this is not done automagically
Not sure if this is the best way, but I got it working.
I have a String exposed on my ClassroomList backing bean as "String locationState". My dropdown list of states binds to that
Then that's referenced in my restrictions as:
...
lower(classroom.location.state) like lower(concat(#{classroomList.locationState}, '%'))",
...
--
When I tried to instantiate ClassroomList.instance.Location, I would get:
javax.servlet.ServletException with message: "Id and clazz must not be null"
Not sure what's causing that?