Reputation: 12922
I have an API that takes in a Method
and stores it to call later. In order to invoke it I have to do setAccessible(true)
. Before I do that, I'd like to make a defensive copy. But how?
I thought of
method.getDeclaringClass()
.getDeclaredMethod(method.getName(), method.getParameterTypes());
but that won't necessarily give me the same method back in the presence of bridge methods (or other cases where two methods have the same name/parameter types but different return types).
I could loop over method.getDeclaringClass().getDeclaredMethod()
and look for an exact match, but that seems inefficient.
An example that illustrates why a defensive copy might be nice:
Method method = ...;
// Does setAccessible(true)
MyInvoker invoker = new MyInvoker(method);
// Sometime later, the user uses the same Method rather than re-retrieving it
method.setAccessible(true);
method.invoke(...);
method.setAccessible(false);
// Oops, now MyInvoker is broken
An example where getDeclaredMethod()
returns a different method:
interface Iface {
Object get();
}
class Impl implements Iface {
@Override
public String get() {
return "foo";
}
}
for (Method method : Impl.class.getDeclaredMethods()) {
System.out.println(method);
System.out.println(copy(method));
System.out.println();
}
private Method copy(Method method) {
try {
return method.getDeclaringClass()
.getDeclaredMethod(method.getName(), method.getParameterTypes());
} catch (ReflectiveOperationException e) {
throw new RuntimeException(e);
}
}
For me, this prints:
public java.lang.String com.maluuba.api.Impl.get() public java.lang.String com.maluuba.api.Impl.get() public java.lang.Object com.maluuba.api.Impl.get() public java.lang.String com.maluuba.api.Impl.get()
Upvotes: 1
Views: 277
Reputation: 279940
You'll have to do what you originally suggested and rely on the contract of Method#equals(Object)
which states
Compares this
Method
against the specified object. Returnstrue
if the objects are the same. TwoMethod
s are the same if they were declared by the same class and have the same name and formal parameter types and return type.
So you won't be able to use the getDeclaredMethod(String, Object...)
method. You'll have to do an array lookup on the Method[]
returned by getDeclaredMethods()
. For example,
private Method copy(Method method) {
Class<?> clazz = method.getDeclaringClass();
for (Method declaredMethod : clazz.getDeclaredMethods()) {
if (declaredMethod.equals(method)) {
return declaredMethod; // return the new one
}
}
throw new RuntimeException("This should not happen.");
}
Upvotes: 1