1. ホーム
  2. java

[解決済み] リフレクション使用時にIllegalAccessExceptionが発生する。

2022-02-18 14:27:56

質問

リフレクションを学ぼうとしていたところ、このIllegalAccessExceptionに遭遇しました。以下のコードをご覧ください。

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));
      }
} 

このプログラムを実行しようとすると、次のようになりました。

Exception in thread "main" IllegalAccessException

何が起こっているのか理解できない。何かアイデアはありますか?よろしくお願いします。

解決方法は?

setAccessible(true)を指定して、他のクラスのプライベートメソッドを反射的に呼び出すには、Java言語によるアクセスチェックを抑制する必要があります。

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

さらに、SecurityManagerがenableの場合、setAccessible(true)を呼び出すために特別なパーミッションが必要です。 そうでなければ、我々は得る。

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)

この suppressAccessChecks 権限は、信頼できるコードソースにのみ与えたいのであって、コールスタック内のすべてのクラスには絶対に与えないでください。 そこで、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;
         }
     });
 }
 }