Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 518
Umesh K Avatar asked Mar 03 '11 17:03

Umesh K


3 Answers

You need to suppress Java language access checking in order to reflectively invoke a private method in another class, with setAccessible(true):

Method mtd= itr.getClass().getMethod("hasNext");
  if(!mtd.isAccessible()) {
      mtd.setAccessible(true);
 }

Furthermore, when a SecurityManager is enable, we need extra permissions to call setAccessible(true). Otherwise, we get:

C:\ReflectionTest>java -Djava.security.manager CallFoo
Exception in thread "main" java.security.AccessControlException: access denied (java.lang.reflect.ReflectPermission suppressAccessChecks)
    at java.security.AccessControlContext.checkPermission(AccessControlContext.java:264)
    at java.security.AccessController.checkPermission(AccessController.java:427)
    at java.lang.SecurityManager.checkPermission(SecurityManager.java:532)
    at java.lang.reflect.AccessibleObject.setAccessible(AccessibleObject.java:107)
    at CallFoo.main(CallFoo.java:8)

We only want to grant this suppressAccessChecks permission to trusted code source, definitely not to all classes in the call stack. So we would modify CallFoo.java:

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;

public class CallFoo {
  public static void main(String args[]) throws Exception {
     doCallFoo();
  }

 public static void doCallFoo() throws IllegalAccessException, ClassNotFoundException, NoSuchMethodException, 
         InvocationTargetException, InstantiationException, PrivilegedActionException {
       Class fooClass = Class.forName("Foo");
     final Foo foo = (Foo) fooClass.newInstance();
     final Method helloMethod = fooClass.getDeclaredMethod("hello");

     AccessController.doPrivileged(new PrivilegedExceptionAction() {
         public Object run() throws Exception {
             if(!helloMethod.isAccessible()) {
                 helloMethod.setAccessible(true);
             }
             helloMethod.invoke(foo);
           return null;
         }
     });
 }
 }
like image 99
Piyush Mattoo Avatar answered Nov 09 '22 00:11

Piyush Mattoo


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.)

like image 21
Tom Hawtin - tackline Avatar answered Nov 09 '22 01:11

Tom Hawtin - tackline


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

like image 2
Zsolt Avatar answered Nov 09 '22 01:11

Zsolt