Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java—how can I dynamically reference an object's property?

Tags:

java

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]?
    }
}
like image 232
Trevor Dixon Avatar asked Oct 29 '12 19:10

Trevor Dixon


People also ask

How do you access object properties dynamically?

To dynamically access an object's property: Use keyof typeof obj as the type of the dynamic key, e.g. type ObjectKey = keyof typeof obj; . Use bracket notation to access the object's property, e.g. obj[myVar] .

How do I set dynamic properties in Java?

properties file. Instantiate the Properties class. Populate the created Properties object using the put() method. Instantiate the FileOutputStream class by passing the path to store the file, as a parameter.

How do you access objects using variables?

Answer: Use the Square Bracket ( [] ) Notation There are two ways to access or get the value of a property from an object — the dot ( . ) notation, like obj. foo , and the square bracket ( [] ) notation, like obj[foo] .


3 Answers

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+"'");
    }
}
like image 167
Jacob Schoen Avatar answered Oct 18 '22 12:10

Jacob Schoen


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.

like image 35
Alexander Mills Avatar answered Oct 18 '22 11:10

Alexander Mills


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.

like image 25
Joel Westberg Avatar answered Oct 18 '22 10:10

Joel Westberg