I'm trying to save a parameter as a property, the parameter is : testSpeed ( = "20" ), and I have a method :
saveProperty(String Parameter)
which will save the value of Parameter to a file, something like this :
saveProperty(testSpeed);
My property file looks like this :
testSpeed : 20
testHeight : 300
My question is : In Java is it possible to get the name of the parameter, in this case the parameter passed to saveProperty() is testSpeed, and it's name is "testSpeed", how to get this string from inside of saveProperty(), so I don't have to do the following to save it :
saveProperty(String Name,String Value);
and call it like this :
saveProperty("testSpeed",testSpeed)
Also, when I need to get it out from the property file, I can call :
getProperty(testSpeed)
I know how to use a property file, I'm just using it as an example, maybe it caused some confusion when I mentioned property file.
The essence of the question is : how to get the name of a parameter passed into a method.
void someMethod(String Parameter_XYZ)
{
// In here if I call someMethod(testSpeed), how to get the string "testSpeed",
// not it's value, but it's name,
// exactly spelled as "testSpeed" ?
}
Is this doable in Java ?
First of all correct format of property file is this:
testSpeed=20
testHeight=300
Now to pull any property from this you need to pass key name, which you're already doing in saveProperty(String name, String value) method. However if I understood your question correctly then you want to avoid passing property name. You can have some custom methods like this:
void saveTestSpeed(String value) {
saveProperty("testSpeed", value);
}
Strig getTestSpeed() {
getProperty("testSpeed");
}
EDIT: Based on your edited question.
No it is not possible in Java.
Please remember that Java is strictly pass-by-value that makes it impossible to figure out the name of actual variable name at callee's end. Inside the saveProperty method we can only get the value of the arguments since in Java Object references are passed by value not by name.
This is not practical also since there is nothing that stops method being called like:
savePropery( "20" );
In the case what should be the name of the property?
Use Properties:
public class Util
{
private static final Properties prop = new Properties();
static
{
try
{
prop.load(new FileReader(new File("prop.txt")));
}
catch(IOException e)
{
e.printStackTrace();
}
}
public static void setProperty(String key, String value)
{
prop.setProperty(key, value);
persistCurrentProperites();
}
public static String getProperty(String key)
{
return prop.getProperty(key);
}
private static void persistCurrentProperites()
{
try
{
prop.store(new FileWriter(new File("prop.txt")), null);
}
catch(IOException e)
{
e.printStackTrace();
}
}
}
I suggest maintaining the key-value pairs to acheive a more generic solution. You can use Properties
void saveProperty(String key, String value) {
properties.setProperty(key, value);
}
use getProperty to retrieve
properties.getProperty(key)
Related
How can I inject a map into an object using only Core Java?
I have a map with 4 key-value(String, Object) pairs and a class with 3 fields, I want to invoke the setter method based on the key name and set them.
{
"variableA": "A",
"variableB": true,
"variableC": 1,
"variableD": "DONT USE"
}
public Class Example {
public void setVaraibleA(String variableA);
public void setVaraibleB(Boolean variableB);
public void setVaraibleC(Integer variableC);
}
Example example = new Example();
// Do something to map it
assert(example.getVariableA.equals("A"));
assert(example.getVariableB.equals(true));
assert(example.getVariableC.equals(1));
you can use Java Reflection to get a method (given its name) and invoke it with a given parameter.
Example example = new Example();
Method method = Example.class.getMethod("setVariableA", String.class);
method.invoke(example, "parameter-value1");
Alternatively to #BeppeC's answer, if you can't easily determine the type of the object that you're injecting at runtime, and assuming that you don't have duplicate property names, I would use Class's getMethods() method and Method's getName() method.
Basically, I would write some code like the following:
Method[] exampleMethods = Example.class.getMethods();
Map<String, Method> setterMethodsByPropertyName = new HashMap<>(exampleMethods.length);
for (Method exampleMethod : exampleMethods) {
String methodName = exampleMethod.getName();
if (!methodName.startsWith("set")) {
continue;
}
// substring starting right after "set"
String variableName = methodName.substring(3);
// use lowercase here because:
// 1. JSON property starts with lower case but setter name after "set" starts with upper case
// 2. property names should all be different so no name conflict (assumption)
String lcVariableNmae = variableName.toLowerCase();
setterMethodsByPropertyName.put(lcVariableName, exampleMethod);
}
// later in the code, and assuming that your JSON map is accessible via a Java Map
for (Map.Entry<String, ?> entry : jsonMap.entrySet()) {
String propertyName = entry.getKey();
String lcPropertyName = propertyName.toLowerCase();
if(!setterMethodsByPropertyName.containsKey(lcPropertyName)) {
// do something for this error condition where the property setter can't be found
}
Object propertyValue = entry.getValue();
Method setter = setterMethodsByPropertyName.get(lcPropertyName);
setter.invoke(myExampleInstance, propertyValue);
}
I have situation where I have a list(required items) that holds a table column result like:
NAME
ADDRESS
AGE
.
.
etc
In my method I get a User object that contains values for user.getName(), user.getAge() etc. I want to know the best way to ensure that every item in the list is present in the user object. The no of items in the list are variable.
public boolean isUserInfoComplete(User user, ArrayList list){
//so, if the list has AGE, the user.getAge() must have some value
}
One way I thought of is maintaining another list that holds values of every user info and checking that against my db list but that is not scalable.
It's not possible to dynamically match your method names with the list contents without reflection (which can be expensive and fragile). You may want to consider keeping your User values in a central Map cache. Here's one way to do that:
public class User {
private enum Field {
NAME,
AGE
//...
}
private Map<String, Object> values = new HashMap<>();
private void putValue(Field field, Object value) {
values.put(field.name(), value);
}
private Object getValue(Field field) {
return values.get(field.name());
}
public void setName(String name) {
putValue(Field.NAME, name);
}
public String getName() {
return (String)getValue(Field.NAME);
}
public void setAge(int age) {
putValue(Field.AGE, age);
}
public Integer getAge() {
return (Integer)getValue(Field.AGE);
}
//...
public boolean isUserInfoComplete(List<String> fields) {
return values.keySet().containsAll(fields);
}
}
You could use reflection to solve this problem if the items in the list match the getters in your User object.
For example, if AGE is in the list, you could use reflection to look for the getAge() method on the User class, call it on the object, and then check the result for null (or switch on the method return type to perform other types of checks).
Here's a starting point for you to experiment with (I haven't compiled or tested it):
public boolean isUserInfoComplete(User user, ArrayList list){
for(String attribute : list) {
String methodName = "get" + attribute.substring(0, 1).toUpperCase() + attribute.substring(1).toLowerCase();
Method method = User.class.getMethod(methodName, null);
if(method != null) {
Object result = method.invoke(user);
if(result == null) {
return false;
}
}
}
return true;
}
This seems like a case where you need reflection. This gives you the opportunity to inspect methods and field from your objects at runtime.
If you know your User-objects etc will follow a java bean standard then you will be able to use the getters for checking, though I see now problem in making your fields public final and checking directly on the fields themselves.
Take a look at https://docs.oracle.com/javase/tutorial/reflect/
You can check it using contains() while looping. This process will be very resource-consuming.
Maybe you can redesign something and simply compare two User objects? Will be faster. You can do it by providing your own implementation of equals and hashcode methods.
What happens if I annotate a constructor parameter using #JsonProperty but the Json doesn't specify that property. What value does the constructor get?
How do I differentiate between a property having a null value versus a property that is not present in the JSON?
Summarizing excellent answers by Programmer Bruce and StaxMan:
Missing properties referenced by the constructor are assigned a default value as defined by Java.
You can use setter methods to differentiate between properties that are implicitly or explicitly set. Setter methods are only invoked for properties with explicit values. Setter methods can keep track of whether a property was explicitly set using a boolean flag (e.g. isValueSet).
What happens if I annotate a constructor parameter using #JsonProperty but the Json doesn't specify that property. What value does the constructor get?
For questions such as this, I like to just write a sample program and see what happens.
Following is such a sample program.
import org.codehaus.jackson.annotate.JsonProperty;
import org.codehaus.jackson.map.ObjectMapper;
public class JacksonFoo
{
public static void main(String[] args) throws Exception
{
ObjectMapper mapper = new ObjectMapper();
// {"name":"Fred","id":42}
String jsonInput1 = "{\"name\":\"Fred\",\"id\":42}";
Bar bar1 = mapper.readValue(jsonInput1, Bar.class);
System.out.println(bar1);
// output:
// Bar: name=Fred, id=42
// {"name":"James"}
String jsonInput2 = "{\"name\":\"James\"}";
Bar bar2 = mapper.readValue(jsonInput2, Bar.class);
System.out.println(bar2);
// output:
// Bar: name=James, id=0
// {"id":7}
String jsonInput3 = "{\"id\":7}";
Bar bar3 = mapper.readValue(jsonInput3, Bar.class);
System.out.println(bar3);
// output:
// Bar: name=null, id=7
}
}
class Bar
{
private String name = "BLANK";
private int id = -1;
Bar(#JsonProperty("name") String n, #JsonProperty("id") int i)
{
name = n;
id = i;
}
#Override
public String toString()
{
return String.format("Bar: name=%s, id=%d", name, id);
}
}
The result is that the constructor is passed the default value for the data type.
How do I differentiate between a property having a null value versus a property that is not present in the JSON?
One simple approach would be to check for a default value post deserialization processing, since if the element were present in the JSON but had a null value, then the null value would be used to replace any default value given the corresponding Java field. For example:
import org.codehaus.jackson.annotate.JsonAutoDetect.Visibility;
import org.codehaus.jackson.annotate.JsonMethod;
import org.codehaus.jackson.map.ObjectMapper;
public class JacksonFooToo
{
public static void main(String[] args) throws Exception
{
ObjectMapper mapper = new ObjectMapper().setVisibility(JsonMethod.FIELD, Visibility.ANY);
// {"name":null,"id":99}
String jsonInput1 = "{\"name\":null,\"id\":99}";
BarToo barToo1 = mapper.readValue(jsonInput1, BarToo.class);
System.out.println(barToo1);
// output:
// BarToo: name=null, id=99
// {"id":99}
String jsonInput2 = "{\"id\":99}";
BarToo barToo2 = mapper.readValue(jsonInput2, BarToo.class);
System.out.println(barToo2);
// output:
// BarToo: name=BLANK, id=99
// Interrogate barToo1 and barToo2 for
// the current value of the name field.
// If it's null, then it was null in the JSON.
// If it's BLANK, then it was missing in the JSON.
}
}
class BarToo
{
String name = "BLANK";
int id = -1;
#Override
public String toString()
{
return String.format("BarToo: name=%s, id=%d", name, id);
}
}
Another approach would be to implement a custom deserializer that checks for the required JSON elements. And yet another approach would be to log an enhancement request with the Jackson project at http://jira.codehaus.org/browse/JACKSON
In addition to constructor behavior explained in #Programmer_Bruce's answer, one way to differentiate between null value and missing value is to define a setter: setter is only called with explicit null value.
Custom setter can then set a private boolean flag ("isValueSet" or whatever) if you want to keep track of values set.
Setters have precedence over fields, in case both field and setter exist, so you can "override" behavior this way as well.
I'm thinking of using something in the style of an Option class, where a Nothing object would tell me if there is such a value or not. Has anyone done something like this with Jackson (in Java, not Scala, et al)?
(My answer might be useful to some people finding this thread via google, even if it doesn't answer OPs question)
If you are dealing with primitive types which are omittable, and you do not want to use a setter like described in the other answers (for example if you want your field to be final), you can use box objects:
public class Foo {
private final int number;
public Foo(#JsonProperty Integer number) {
if (number == null) {
this.number = 42; // some default value
} else {
this.number = number;
}
}
}
this doesn't work if the JSON actually contains null, but it can be sufficient if you know it will only contain primitives or be absent
another option is to validate the object after deserialization either manually or via frameworks such java bean validation or, if you are using spring, the spring validation support.
java.lang.NoSuchFieldException: id
The below line is creating the exception.
String fieldValue =String.valueOf(studyplanCategory.getClass().getField(filterProperty).get(studyplanCategory));
studyplanCategory is a valid object and has got actual values. Beacuse of this exception the load method and the search function in the LazyLoading DataTable of my JSF webapp is not working.
From the Javadoc for Class.getField(...):
Returns a Field object that reflects the specified public member field
of the class or interface represented by this Class object. The name
parameter is a String specifying the simple name of the desired field.
The field to be reflected is determined by the algorithm that follows.
Let C be the class represented by this object:
If C declares a public field with the name specified, that is the
field to be reflected. If no field was found in step 1 above, this
algorithm is applied recursively to each direct superinterface of C.
The direct superinterfaces are searched in the order they were
declared. If no field was found in steps 1 and 2 above, and C has a
superclass S, then this algorithm is invoked recursively upon S. If C
has no superclass, then a NoSuchFieldException is thrown. See The Java
Language Specification, sections 8.2 and 8.3.
If the field you are trying to retrieve via:
studyplanCategory.getClass().getField(filterProperty)
is private, then you will get a NoSuchFieldException. For private fields, try this instead:
studyplanCategory.getClass().getDeclaredField(filterProperty)
And to get around potential illegal access exceptions when setting values via a field this way:
Field field = studyplanCategory.getClass().getDeclaredField(filterProperty);
field.setAccessible(true);
field.get(studyplanCategory);
App fires up this exception because its doesn't see attribudes your want to give back.
Method getField() return non-private attribudes so if your attribudes are private, method doesn't see them. You can check http://docs.oracle.com/javase/tutorial/reflect/member/fieldTrouble.html
So you can do that your attribudes will change on protected or public and then should work it right. But this way (its same like example on primefaces) simulate real database.
public List<Car> load(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String,String> filters) {
List<Car> data = new ArrayList<Car>();
//filter
for(Car car : datasource) {
boolean match = true;
for(Iterator<String> it = filters.keySet().iterator(); it.hasNext();) {
try {
String filterProperty = it.next();
String filterValue = filters.get(filterProperty);
String fieldValue = String.valueOf(car.getClass().getField(filterProperty).get(car));
...
So this list simulate real database only for example. If you want to use it. so you shoud do it on backing bean class and there do it. You open connection already with some filter or don't and then return data from database.
//EDIT: Man wrote that you should use getDeclaredField() but i did try this and it didn't work well, and throws up IlegalAccessException. When a pretype attribudes to protected, it works fine. I don't know why.
Best solutions for getClass().getField() problem are:
Use getDeclaredField() instead of getField()
1)
String propertyName = "test";<br/>
Class.forName(this.getClass().getName()).getDeclaredField(propertyName);
2)
String propertyName = "name";<br/>
Replace **"HelloWorld"** with your class name<br/>
HelloWorld.class.getDeclaredField(propertyName)
I had faced the same problem. My issue was my variables are not public . Make sure your class variables are public
private Object getVariableValue(Object clazz, String variableName) {
try {
Field field = clazz.getClass().getField(variableName);
return field.get(clazz);
} catch (NoSuchFieldException e) {
return "";
} catch (IllegalAccessException e) {
return "";
}
}
I agree that we should Use getDeclaredField() instead of getField()
private Field getOwnProperty(Object clazz, String propertyName) {
try {
return clazz.getClass().getDeclaredField(propertyName);
} catch (NoSuchFieldException e) {
log.warn( "Object has no property : " + propertyName );
return null;
}
}
How to know whether a property exists or not in a property file in java?
According to http://java.sun.com/javase/6/docs/api/java/util/Properties.html, getProperty() returns null if the property was not found. You could also call propertyNames() or stringPropertyNames() and look to see whether the property name of interest is in the returned set.
Yet another alternative is to exploit the fact the Properties extends Hashtable<Object,Object> and use containsKey.
Just load the properties file and then try to get the desired property.
public String getProperty(String key)
Searches for the property with the specified key in this property list. If the key is not found in this property list, the default property list, and its defaults, recursively, are then checked. The method returns null if the property is not found.
http://java.sun.com/j2se/1.5.0/docs/api/java/util/Properties.html#getProperty(java.lang.String)
You can also call getProperty(String key, String defaultValue) and check if the return value is the defaultValue.
See https://docs.oracle.com/javase/8/docs/api/java/util/Properties.html#getProperty-java.lang.String-java.lang.String-
You can use hasProperty
AllValues.hasProperty("childList")
If you want to check that at the start of program you can do the following:
Create a class VerifiedProperties that extends Properties
Add all properties as fields of this class as public final int/String/boolean/etc...
Add private final String propertyNotValid="Property not valid" String to this class
Add private final String propertyNotFound="Property not found" String to this class
Override getProperty() method from Properties class.
You can add #Deprecated tag to suggest usage of the fields. It is impossible to hide this method because it is public in Properties class.
Initialize all fields in the constructor using getProperty() method or dedicated for type (look examples below)
Example methods that takes care of different property types:
#Override
#Deprecated
/*
Deprecated annotation added to suggest usage of the fields.
*/
public final String getProperty(String key)
{
String propertyValue = super.getProperty(key);
if (propertyValue != null)
{
return propertyValue;
}
else
{
throw new NoSuchFieldError(this.propertyNotFound + " " + key);
}
}
private int getIntegerProperty(String key)
{
String propertyValue = this.getProperty(key);
try
{
int propertyIntValue = Integer.parseInt(propertyValue);
return propertyIntValue;
}
catch (NumberFormatException e)
{
throw new NumberFormatException(this.propertyNotValid + " " + key);
}
}
private boolean getBooleanProperty(String key)
{
String propertyValue = this.getProperty(key);
try
{
boolean propertyBooleanValue = Boolean.parseBoolean(propertyValue);
return propertyBooleanValue;
}
catch (NumberFormatException e)
{
throw new NumberFormatException(this.propertyNotValid + " " + key);
}
}
private long getLongProperty(String key)
{
String propertyValue = this.getProperty(key);
try
{
long propertyLongValue = Long.parseLong(propertyValue);
return propertyLongValue;
}
catch (NumberFormatException e)
{
throw new NumberFormatException(this.propertyNotValid + " " + key);
}
}
Then you can create somewhere:
public static VerifiedProperties properties;
and use the properties that you need as properties.myProperty
Advantages:
you have full control over properties which includes exception handling and null checking
If property does not exist or is in incorrect format, you will have the information at the initialization of the program
You don't need to worry about parsing properties to different types than String in your code.
You can add validators to your String properties
You can easily refactor property name
If you are using external property file that can be modified by the user outside of your application, if provided change is incorrect or there are fields missing your program will not start.
Disadvantages:
For each property besides adding value to *.properties file you need to create field and assign value in the constructor. If you have a lot of properties then this file can look unpleasant.
Hints:
it is easier to mantain the file if you keep the same name for the field as in properties file.
(Netbeans) you can Toggle Rectangular Selection to add public final String and similar to many lines at once.
(Netbeans) to keep *.properties file clean you can use this solution.
The answer by crazyscot is now outdated. According to the new javadoc, the property will just get created if it doesn't exist,
"If there is no current set of system properties, a set of system properties is first created and initialized in the same manner as for the getProperties method".
Here is some trick how to find out is some file (not mandatory property file) exists in class path
public class FileUtil {
public static boolean isFileExists(String fileName){
return null != FileUtil.class.getResourceAsStream(fileName);
}
}
Sure it not always works as long it depends on class loading aspects