IllegalAccessException when using call dynamic methods
I am trying to use Reflection in Java but I am getting a weird error. What are the possible issues when I get an error that says:
java.lang.IllegalAccessException: Class com.myapp.core.utils.EventDispatcher can not access a member of class appApp$1 with modifiers "public"
at sun.reflect.Reflection.ensureMemberAccess(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
I just trying to create my own EventDispatcher class and inside it, the part that I used reflection, which is also the line of code that causes the problem is:
public void dispatchEvent(Event e, String callMethName) {
IEventListener list = ((IEventListener)listeners[i]);
list.getClass().getMethod(callMethName, Event.class).invoke(list, e);
}
On my main class, I have something that calls addListener which will just add the listener into a list in the EventDispatcher class this way:
try {
obj.addListener("onTestHandler", new MyTestEventListener(){
@Override
public void onTestHandler(Event e) {
System.out.println("hello!");
}
});
} catch (SecurityException e) {
e.printStackTrace();
}
So the first parameter that says "onTestHandler" will pass into the EventDispatcher class and eventually as part of the parameter callMethName in the dispatchEvent method, which will call the method dynamically.
The passing of methods and everything is correct. It is the part that has the reflection somehow has problems. 开发者_如何学运维It seems to be able to find the method. But for some reason, throws an IllegalAccessException and cannot call the method.
Why is it like this?
Thanks.
I suspect that the anonymous class (appApp$1
) that implements MyTestEventListener
has package visibility and that the reflection code is in another package.
For this code:
package foo.p1;
public class Target {
public static interface Foo {
public void bar();
}
public static Foo newFoo() {
return new Foo() {
@Override
public void bar() {
}
};
}
}
This code will fail because the runtime type returned by newFoo()
is not a public class:
package foo.p2;
import foo.p1.Target;
public class Main {
public static void main(String[] args) throws Exception {
Target.Foo foo = Target.newFoo();
foo.getClass()
.getMethod("bar")
.invoke(foo);
}
}
This can be overcome by setting the method as accessible:
Target.Foo foo = Target.newFoo();
Method m = foo.getClass()
.getMethod("bar");
m.setAccessible(true);
m.invoke(foo);
Or by using the method from the public interface:
Target.Foo foo = Target.newFoo();
Target.Foo.class.getMethod("bar")
.invoke(foo);
Access to anonymous classes is very restrictive.. Instead of simply using list.getClass()
, you should try to find a non-anonymous super-class or interface of the object which has the method you want, and then invoke the Method from that Class instead of the anonymous one..
I'd also suggest you do this search at the time of adding the listener and store the result. It's fairly expensive to use reflection, so stuff will run faster. Just as important, if you make a typo in the method name, you'll get the error at the time you add the listener, not at some random time in the future.. It will be much easier to find the problem this way :)
精彩评论