Using reflection to get a method; method parameters of interface types aren't found
How do I get a method using reflection based on a parameter value when the parameter type is an interface?
In the following case (based on this example), newValue
would be a List<String>
called foo
. So I would call addModelProperty("Bar", foo);
But this only works for me if I don't use the interface 开发者_运维技巧and only use LinkedList<String> foo
. How do I use an interface for newValue
and get the method from model
that has an interface as the parameter addBar(List<String> a0)
?
public class AbstractController {
private final AbstractModel model;
public setModel(AbstractModel model) {
this.model = model;
}
protected void addModelProperty(String propertyName, Object newValue) {
try {
Method method = getMethod(model.getClass(), "add" + propertyName, newValue);
method.invoke(model, newValue);
} catch (NoSuchMethodException e) {
} catch (InvocationTargetException e) {
} catch (Exception e) {}
}
private Method getMethod(Class clazz, String name, Object parameter) {
return clazz.getMethod(name, parameter.getClass());
}
}
public class AbstractModel {
protected PropertyChangeSupport propertyChangeSupport;
protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) {
propertyChangeSupport.firePropertyChange(propertyName, oldValue, newValue);
}
}
public class Model extends AbstractModel {
public void addList(List<String> list) {
this.list.addAll(list);
}
}
public class Controller extends AbstractController {
public void addList(List<String> list) {
addModelProperty(list);
}
}
public void example() {
Model model = new Model();
Controller controller = new Controller();
List<String> list = new LinkedList<String>();
list.add("example");
// addList in the model is only found if LinkedList is used everywhere instead of List
controller.addList(list);
}
You'll actually have to search through all the methods in your model and find those that are compatible with the arguments you have. It is a bit messy, because, in general, there might be more that one.
If you are interested in just public methods, the getMethods()
method is the easiest to use, because it gives you all accessible methods without walking the class hierarchy.
Collection<Method> candidates = new ArrayList<Method>();
String target = "add" + propertyName;
for (Method m : model.getClass().getMethods()) {
if (target.equals(m.getName())) {
Class<?>[] params = m.getParameterTypes();
if (params.length == 1) {
if (params[0].isInstance(newValue))
candidates.add(m);
}
}
}
/* Now see how many matches you have... if there's exactly one, use it. */
If you don't mind adding a dependency to Apache Commons, you may use MethodUtils.getMatchingAccessibleMethod(Class clazz, String methodName, Class[] parameterTypes)
.
If you mind adding this dependency, you may at least find it useful to take a look at how this method is implemented.
Another answer suggested using Apache Commons to get the Method
object using MethodUtils.getMatchingAccessibleMethod
.
However, it looks like you're not using the Method
object for anything other than immediately invoking it on an instance. This being the case, you can instead use Apache Commons Lang's MethodUtils.invokeMethod(Object object, String methodName, Object... args)
. Rather than just returning the Method
object, this instead invokes the method on the given object.
protected void addModelProperty(String propertyName, Object newValue) {
try {
MethodUtils.invokeMethod(model, "add" + propertyName, newValue);
} catch (ReflectiveOperationException e) {
}
}
精彩评论