开发者

IllegalAccessException on using reflection

I was trying to learn reflection and I came across this IllegalAccessException. Please see the following code:

public class ReflectionTest
{
      public static void main(String[] args)
      {
           Set<String> myStr = new HashSet<String>();
           myStr.add("obj1");
           Iterator itr = myStr.iterator();
           Method mtd = itr.getClass().getMethod("hasNext");
           System.out.println开发者_如何学编程(m.invoke(it));
      }
} 

When I tried to run this program, I got the following:

Exception in thread "main" IllegalAccessException

I don't understand what's going on. Any ideas? Thanks in advance.


The troublesome piece of code is this:

itr.getClass().getMethod

You probably wanted hasNext on the Iterator class. What you have written is the HashMap.KeyIterator class, which according the Java language access specifiers (or at least the rough interpretation of JDK 1.0 used by reflection) is not available to your code.

Use instead:

Iterator.class.getMethod

(And if it wasn't for learning purposes, stay away from reflection.)


You cannot access it, because the Iterator is a private inner class. More explanation can be found here.


It's apparent that your currently executing method does not have access to the method named hasNext, e.g., by it being private or protected. You could try to enable access to it using method.setAccessible(true);

It might also be that you have some restrictions defined in your security manager (which, if you use e.g., linux, might have been included default from the distributions java package).

[EDIT] As it turns out, Tom Hawtin identified the correct root cause. You are indeed operating on HashMap.KeyIterator. Although the solution would be to use Iterator.class instead of itr.getClass() you could still enable access to it using setAccessible(true).


I suspect you should use getDeclaredMethod (among other issues). I don't bother to remember Reflection API details (they're for the compiler!), but in your case compare your code with that produced by dp4j:

$ javac -Averbose=true -All -cp dp4j-1.2-SNAPSHOT-jar-with-dependencies.jar ReflectionTest.java 
ReflectionTest.java:6: Note: 
import java.util.*;

public class ReflectionTest {

public ReflectionTest() {
    super();
}

@com.dp4j.Reflect()
public static void main(String[] args) throws java.lang.ClassNotFoundException, java.lang.NoSuchFieldException, java.lang.IllegalAccessException, java.lang.NoSuchMethodException, java.lang.reflect.InvocationTargetException, java.lang.InstantiationException, java.lang.IllegalArgumentException {
    final java.lang.reflect.Constructor hashSetConstructor = Class.forName("java.util.HashSet").getDeclaredConstructor();
    hashSetConstructor.setAccessible(true);
    Set<String> myStr = (.java.util.Set<.java.lang.String>)hashSetConstructor.newInstance();
    final java.lang.reflect.Method addWithEMethod = Class.forName("java.util.Set").getDeclaredMethod("add", .java.lang.Object.class);
    addWithEMethod.setAccessible(true);
    addWithEMethod.invoke(myStr, new .java.lang.Object[1][]{"obj1"});
    final java.lang.reflect.Method iteratorMethod = Class.forName("java.util.Set").getDeclaredMethod("iterator");
    iteratorMethod.setAccessible(true);
    Iterator itr = (.java.util.Iterator)iteratorMethod.invoke(myStr);
    final java.lang.reflect.Method hasNextMethod = Class.forName("java.util.Iterator").getDeclaredMethod("hasNext");
    hasNextMethod.setAccessible(true);
    final java.lang.reflect.Method printlnWithbooleanMethod = Class.forName("java.io.PrintStream").getDeclaredMethod("println", .java.lang.Boolean.TYPE);
    printlnWithbooleanMethod.setAccessible(true);
    printlnWithbooleanMethod.invoke(System.out, new .java.lang.Object[1][]{hasNextMethod.invoke(itr)});
}

}

    public static void main(String[] args)
                       ^
...

$ java ReflectionTest
true

The only change you need to do is annotate your main method with @com.dp4j.Reflect:

$ vim ReflectionTest.java
import java.util.*;

public class ReflectionTest
{
        @com.dp4j.Reflect
        public static void main(String[] args)
        {
                Set<String> myStr = new HashSet<String>();
                myStr.add("obj1");
                Iterator itr = myStr.iterator();
                // Method mtd = itr.getClass().getMethod("hasNext");
                System.out.println(itr.hasNext());
        }
}

NB: this works only with dp4j-1.2-SNAPSHOT (I've just added suport for it). If you don't use Maven, download the jar from here. You find the test case with your problem here.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜