Reputation: 24342
In javascript, I can do this:
function MyObject(obj) {
for (var property in obj) {
this[property] = obj[property];
}
}
Can I do anything close in Java?
class MyObject {
String myProperty;
public MyObject(HashMap<String, String> props) {
// for each key in props where the key is also the name of
// a property in MyObject, can I assign the value to this.[key]?
}
}
Upvotes: 10
Views: 17639
Reputation: 99960
First, I would use a map if at all possible:
class MyObject {
// String myProperty; // ! not this
HashMap<String,String> myProperties; // use this instead
}
but let's say you wanted to set the fields dynamically.
public MyObject(HashMap<String, String> props) {
for (Map.Entry<String,String> entry : props.entrySet()) {
Field field = this.getClass().getField(entry.getKey());
field.set(this, entry.getValue());
}
}
of course, you will want to use a try/catch in the above constructor.
Upvotes: 4
Reputation: 38122
Well, if you really want to go down the reflection raod, then I suggest to have a look at the Introspector class and get the list of PropertyDescriptors from the BeanInfo.
Upvotes: 2
Reputation: 2736
Yes, you can do it by reflection with something along the following lines:
/**
* Returns a list of all Fields in this object, including inherited fields.
*/
private List<Field> getFields() {
List<Field> list = new ArrayList<Field>();
getFields(list, getClass());
return list;
}
/**
* Adds the fields of the provided class to the List of Fields.
* Recursively adds Fields also from super classes.
*/
private List<Field> getFields(List<Field> list, Class<?> startClass) {
for (Field field : startClass.getDeclaredFields()) {
list.add(field);
}
Class<?> superClass = startClass.getSuperclass();
if(!superClass.equals(Object.class)) {
getFields(list, superClass);
}
}
public void setParameters(Map<String, String> props) throws IllegalArgumentException, IllegalAccessException {
for(Field field : getFields()) {
if (props.containsKey(field.getName())) {
boolean prevAccessible = field.isAccessible();
if (!prevAccessible) {
/*
* You're not allowed to modify this field.
* So first, you modify it to make it modifiable.
*/
field.setAccessible(true);
}
field.set(this, props.get(field.getName()));
/* Restore the mess you made */
field.setAccessible(prevAccessible);
}
}
}
However, if you are not very familiar with Java, this approach should be avoided if at all possible, as it is somewhat dangerous and error prone. For instance, there is no guarantee that the Field
you are attempting to set are actually expecting a String. If it is the case that they are not, your program will crash and burn.
Upvotes: 4
Reputation: 14192
Not that I disagree with Joel's answer, but I do not think it is not quite that difficult, if you essentially just want a best effort. Essentially check if it is there, and if it is try to set. If it works great if not, oh well we tried. For example:
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
public class MyObject {
protected String lorem;
protected String ipsum;
protected int integer;
public MyObject(Map<String, Object> valueMap){
for (String key : valueMap.keySet()){
setField(key, valueMap.get(key));
}
}
private void setField(String fieldName, Object value) {
Field field;
try {
field = getClass().getDeclaredField(fieldName);
field.set(this, value);
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Map<String, Object> valueMap = new HashMap<String, Object>();
valueMap.put("lorem", "lorem Value");
valueMap.put("ipsum", "ipsum Value");
valueMap.put("integer", 100);
valueMap.put("notThere", "Nope");
MyObject f = new MyObject(valueMap);
System.out.println("lorem => '"+f.lorem+"'");
System.out.println("ipsum => '"+f.ipsum+"'");
System.out.println("integer => '"+f.integer+"'");
}
}
Upvotes: 8