alessfg
alessfg

Reputation: 47

Calling a method with an argument trough reflection

I have the following code which allows me to input in the scanner the Employee getter method that I want to call and it will do it using reflection (the name of the method should not appear anywhere in the code). This works for getter methods but I now need to modify the code to do something similar for setter methods. I have been trying to figure how to do it for the past week but I have been unable. Any help would be appreciated.

Thanks.

public static void main(String[] args) {
    Employee e = Employee.testEmployee();                // a sample employee
    Class cls = e.getClass();
    Scanner scanner = new Scanner (System.in);           // to parse data the user types in
    String nextCommand;

    // until the user enters "quit", get the next input from the user, and if it matches
    // a given command, get the desired information from the employee object
    do {
      System.out.print("Enter command >> ");
      nextCommand = scanner.next();
      Method method = null;
      try{
        method = cls.getMethod(nextCommand);
      }
      catch(NoSuchMethodException x) {
      }
      try{
        System.out.println(method.invoke(e));
      }
      catch(IllegalAccessException x) {
      }
      catch(java.lang.reflect.InvocationTargetException x) {
      }
      catch(NullPointerException x) {
      }
    } while (! nextCommand.equals("quit"));
  }

Upvotes: 1

Views: 228

Answers (3)

Jeroen Vannevel
Jeroen Vannevel

Reputation: 44439

Here's a code sample that does what you want to achieve:

public class Test {
    private static HashSet<Class<?>> classes = new HashSet<>();

    static {
        classes.add(String.class);
        classes.add(Integer.class);
        classes.add(GregorianCalendar.class);
    }

    public static void main(String[] args) throws NoSuchMethodException,
            SecurityException, IllegalAccessException,
            IllegalArgumentException, InvocationTargetException {
        X obj = new X();
        obj.setField("lala");
        Method method = obj.getClass().getMethod("getField", null);
        System.out.println(method.invoke(obj, null));

        Method setMethod = getWorkingMethod(obj);
        setMethod.invoke(obj, "who let the dogs out");
        System.out.println(obj.getField());
    }

    private static Method getWorkingMethod(Object obj) {
        Method method = null;
        for (Class<?> c : classes) {
            try {
                method = obj.getClass().getMethod("setField", c);
            } catch (NoSuchMethodException | SecurityException e) {
                continue;
            }
            if(method != null){
                return method;
            }
        }

        throw new IllegalArgumentException("No such method found!");
    }
}

class X {
    private String stringField;

    public void setField(String s) {
        stringField = s;
    }

    public String getField() {
        return stringField;
    }
}

Output:

lala
who let the dogs out

Notes:

  • Create a collection (I used a HashSet) that stores Class<?> objects. You will use these to iterate over the possibilities and see if a method with that argument exists.

  • Use a try-catch to see if the method exists (an exception is thrown when it can't find it).

  • This will not work for overloaded methods. If this is your scenario, you'll have to make adjustments. I expect it to be no problem though, since you said this was meant for setters (which typically don't have overloads).

Upvotes: 2

Amit Sharma
Amit Sharma

Reputation: 6154

Resolution (method or field resolution) in java slows down you execution time by 'orders of 10 or 100', hence not a smart design decision. So, resolve once at start time, cache method instance, and execute it from cache. Avoid frequent lookups using reflection.

Upvotes: 0

Kevin Bowersox
Kevin Bowersox

Reputation: 94429

You can avoid calling the getter and setter methods by directly accessing the Field through reflection.

The Field object has various get and set methods that can be used to manipulate field values.

See: http://docs.oracle.com/javase/7/docs/api/java/lang/Class.html#getField%28java.lang.String%29

EXAMPLE

import java.lang.reflect.Field;


public class MyObject {

    private String fieldA;


    public String getFieldA() {
        return fieldA;
    }


    public void setFieldA(String fieldA) {
        this.fieldA = fieldA;
    }


    public static void main(String[] args) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {

        MyObject myObject = new MyObject();
        myObject.setFieldA("Test");

        Class clazz = myObject.getClass();

        Field field = clazz.getDeclaredField("fieldA");
        field.setAccessible(true);

        String fieldA = (String) field.get(myObject);
        System.out.println(fieldA);

        field.set(myObject, "Test2");
        fieldA = (String) field.get(myObject);

        System.out.println(fieldA);
        field.setAccessible(false); //be sure to return field to private
    }
}

Upvotes: 0

Related Questions