Reputation: 47
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
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
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
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