reflexion reflect method example ejemplos java reflection

method - reflection java stack overflow



IllegalAccessException en el uso de la reflexión (5)

Debe suprimir la verificación de acceso al lenguaje Java para invocar de manera reflexiva un método privado en otra clase, con setAccessible (verdadero):

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

Además, cuando un SecurityManager está habilitado, necesitamos permisos adicionales para llamar a setAccessible (verdadero). De lo contrario, obtenemos:

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)

Solo queremos otorgar este permiso suprimirAccessChecks al código fuente confiable, definitivamente no a todas las clases en la pila de llamadas. Entonces modificaríamos 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; } }); } }

Estaba tratando de aprender a reflexionar y me encontré con esta IllegalAccessException. Por favor mira el siguiente código:

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

Cuando intenté ejecutar este programa, obtuve lo siguiente:

Exception in thread "main" IllegalAccessException

No entiendo lo que está pasando. ¿Algunas ideas? Gracias por adelantado.


Es evidente que el método que está ejecutando actualmente no tiene acceso al método denominado hasNext , por ejemplo, al ser private o estar protected . Podría tratar de habilitar el acceso utilizando method.setAccessible(true);

También podría ser que tenga algunas restricciones definidas en su security manager (que, si utiliza, por ejemplo, linux , podría haberse incluido por defecto del paquete java de distribuciones).

[EDIT] Como resultado, Tom Hawtin identificó la causa raíz correcta. De hecho, estás operando en HashMap.KeyIterator . Aunque la solución sería usar itr.getClass() lugar de itr.getClass() aún podría habilitar el acceso a él usando setAccessible(true) .


La parte problemática del código es esta:

itr.getClass().getMethod

Probablemente querías hasNext en la clase hasNext . Lo que ha escrito es la clase HashMap.KeyIterator , que según los especificadores de acceso al lenguaje Java (o al menos la interpretación aproximada de JDK 1.0 utilizada por la reflexión) no está disponible para su código.

Use en su lugar:

Iterator.class.getMethod

(Y si no fuera por propósitos de aprendizaje, manténgase alejado de la reflexión).


Sospecho que deberías usar getDeclaredMethod (entre otros temas). No me molesto en recordar los detalles de Reflection API (¡son para el compilador!), Pero en su caso compare su código con el producido por 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

El único cambio que necesita hacer es anotar su método principal con @ 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: esto solo funciona con dp4j-1.2-SNAPSHOT (acabo de agregar soporte para ello). Si no usa Maven, descargue el archivo desde aquí . Aquí encuentra el caso de prueba con su problema.


No puede acceder a él, porque el iterador es una clase interna privada. Más explicación se puede encontrar aquí .