tutorial operator modules java java-9 java-module

operator - java 9 modules tutorial



¿Qué es un acceso reflexivo ilegal? (3)

Hay muchas preguntas sobre el acceso reflexivo ilegal en Java 9.

Ahora, lo que no puedo encontrar porque todo lo que Google hace es que la gente trata de evitar los mensajes de error, es lo que realmente es un acceso reflexivo ilegal.

Así que mi pregunta es bastante simple:

¿Qué define un acceso de reflexión ilegal y qué circunstancias activan la advertencia?

Me he dado cuenta de que tiene algo que ver con los principios de encapsulación que se introdujeron en Java 9, pero cómo todo se une y qué provoca la advertencia en qué escenario no puedo encontrar una explicación.


Además de una comprensión de los accesos entre los módulos y sus respectivos paquetes. Creo que el quid de esto radica en el Sistema de Módulo # Relajado-fuerte-encapsulado y simplemente elegiré las partes relevantes para tratar de responder la pregunta.

¿Qué define un acceso de reflexión ilegal y qué circunstancias activan la advertencia?

Para ayudar en la migración a Java9, la fuerte encapsulación de los módulos podría relajarse.

  • Una implementación puede proporcionar acceso estático , es decir, mediante bytecode compilado.

  • Puede proporcionar un medio para invocar su sistema de tiempo de ejecución con uno o más paquetes de uno o más de sus módulos abiertos al código en todos los módulos sin nombre , es decir, al código en el classpath. Si el sistema de tiempo de ejecución se invoca de esta manera, y si lo hace, algunas invocaciones de las API de reflexión tienen éxito donde, de lo contrario, habrían fallado.

En tales casos, realmente terminó haciendo un acceso reflexivo que es "ilegal" ya que en un mundo completamente modular no estaba destinado a hacer tales accesos.

¿Cómo se articula todo y qué provoca la advertencia en qué escenario?

Esta relajación de la encapsulación se controla en tiempo de ejecución mediante una nueva opción de --illegal-access que, de forma predeterminada, en Java9 permit . El modo de permit asegura

La primera operación de acceso reflexivo a un paquete de este tipo hace que se emita una advertencia, pero no se emiten advertencias después de ese punto. Esta única advertencia describe cómo habilitar más advertencias. Esta advertencia no puede ser suprimida.

Los modos son configurables con valores de debug (mensaje, así como pilatrace para cada acceso), warn (mensaje para cada acceso) y deny (deshabilita dichas operaciones).

Pocas cosas para depurar y corregir en aplicaciones serían:

  • Ejecútelo con --illegal-access=deny para conocer y evite abrir paquetes de un módulo a otro sin una declaración de módulo que incluya dicha directiva ( opens ) o un uso explícito de --add-opens VM arg.
  • Las referencias estáticas del código compilado a las API internas de JDK se podrían identificar utilizando la herramienta jdeps con la opción --jdk-internals

    El mensaje de advertencia emitido cuando se detecta una operación de acceso reflexivo ilegal tiene la siguiente forma:

    WARNING: Illegal reflective access by $PERPETRATOR to $VICTIM

    dónde:

    $PERPETRATOR es el nombre completamente calificado del tipo que contiene el código que invocó la operación de reflexión en cuestión más la fuente del código (es decir, la ruta del archivo JAR), si está disponible, y

    $VICTIM es una cadena que describe al miembro al que se accede, incluido el nombre completo del tipo que lo incluye

Preguntas para un ejemplo de advertencia: = JDK9: Se ha producido una operación de acceso reflexivo ilegal. org.python.core.PySystemState

Por último, y una nota importante, al tratar de asegurarse de que no se enfrenta a tales advertencias y de que está seguro en el futuro, todo lo que necesita hacer es asegurarse de que sus módulos no estén realizando esos accesos reflectivos ilegales. :)


Hay un article Oracle que encontré sobre el sistema de módulos Java 9.

De forma predeterminada, un tipo en un módulo no es accesible a otros módulos a menos que sea un tipo público y exporte su paquete. Solo expones los paquetes que quieras exponer. Con Java 9, esto también se aplica a la reflexión.

Como se señaló en https://.com/a/50251958/134894 , las diferencias entre AccessibleObject#setAccessible para JDK8 y JDK9 son instructivas. Específicamente, JDK9 agregó

Este método puede ser utilizado por una persona que llama en la clase C para permitir el acceso a un miembro que declara la clase D si se cumple alguna de las siguientes condiciones:

  • C y D están en el mismo módulo.
  • El miembro es público y D es público en un paquete que el módulo que contiene D exporta al menos al módulo que contiene C.
  • El miembro está protegido como estático, D es público en un paquete que el módulo que contiene D exporta al menos al módulo que contiene C y C es una subclase de D.
  • D está en un paquete que el módulo que contiene D se abre al menos al módulo que contiene C. Todos los paquetes en módulos sin nombre y abiertos están abiertos a todos los módulos, por lo que este método siempre tiene éxito cuando D está en un módulo sin nombre o abierto.

que destaca la importancia de los módulos y sus exportaciones (en Java 9)


Solo mire el método setAccessible() utilizado para acceder a campos y métodos private :

https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/AccessibleObject.html#setAccessible-boolean-

https://docs.oracle.com/javase/9/docs/api/java/lang/reflect/AccessibleObject.html#setAccessible-boolean-

Ahora se requieren muchas más condiciones para que este método funcione. La única razón por la que no rompe casi todo el software anterior es que los módulos generados automáticamente a partir de JAR simples son muy permisivos (abrir y exportar todo para todos).