web-dev-qa-db-fra.com

qu'est-ce qu'un accès illégal réfléchissant

Il y a beaucoup de questions sur l'accès illégal par réflexion dans Java 9.

Ce que je ne trouve pas, c’est que tout ce que Google dit, c’est que les personnes qui essaient de contourner les messages d’erreur sont ce qu’est en réalité un accès illégal réfléchissant.

Donc, ma question assez simple est:

Qu'est-ce qui définit un accès illégal réfléchi et quelles sont les circonstances qui déclenchent l'avertissement?

J'ai compris que cela avait quelque chose à voir avec les principes d'encapsulation qui avaient été introduits dans Java 9, mais comment tout se tient et ce qui déclenche l'avertissement dans quel scénario je ne trouve pas d'explication.

68
Tschallacka

Outre la compréhension des accès entre les modules et leurs packages respectifs. Je crois que le noeud de celui-ci réside dans le système de module # Relaxed-strong-encapsulation et je voudrais simplement choisir le pertinent certaines parties pour essayer de répondre à la question.

Qu'est-ce qui définit un accès réflexif illégal et quelles sont les circonstances qui déclenchent l'avertissement?

Pour faciliter la migration vers Java9, la forte encapsulation des modules pourrait être assouplie.

  • Une implémentation peut fournir un accès statique , c’est-à-dire en bytecode compilé.

  • Peut fournir un moyen d’appeler son système d’exécution avec un ou plusieurs packages d’un ou plusieurs de ses modules ouverts au code dans tous les modules non nommés , c’est-à-dire au code du chemin de classe. Si le système d'exécution est appelé de cette manière, et si, ce faisant, certains appels des API de réflexion aboutissent, sinon ils auraient échoué.

Dans de tels cas, vous avez fini par créer un accès réfléchissant qui est "illégal" car, dans un monde purement modulaire, n'étaient pas destinés à faire de tels accès.

Comment tout se bloque et qu'est-ce qui déclenche l'avertissement dans quel scénario?

Cette relaxation de l'encapsulation est contrôlée au moment de l'exécution par une nouvelle option de lanceur --illegal-access qui par défaut sous Java9 est égale à permit. Le mode permit assure

La première opération d'accès réflectif à un tel paquet provoque l'émission d'un avertissement, mais aucun avertissement n'est émis après ce point. Cet avertissement unique explique comment activer d'autres avertissements. Cet avertissement ne peut pas être supprimé.

Les modes sont configurables avec les valeurs debug (message ainsi que stacktrace pour chaque accès), warn (message pour chaque accès) et deny (désactive ces opérations).


Peu de choses à déboguer et à corriger sur les applications seraient: -

  • Exécutez-le avec --illegal-access=deny pour connaître et éviter l'ouverture de packages d'un module à l'autre sans déclaration de module incluant une telle directive (opens) ou une utilisation explicite de --add-opens VM arg.
  • Les références statiques du code compilé aux API internes au JDK peuvent être identifiées à l'aide de l'outil jdeps avec l'option --jdk-internals.

    Le message d'avertissement émis lorsqu'une opération d'accès réflectif illégale est détectée a la forme suivante:

    WARNING: Illegal reflective access by $PERPETRATOR to $VICTIM
    

    où:

    $PERPETRATOR est le nom qualifié complet du type contenant le code qui a appelé l'opération réflexive en question, ainsi que la source du code (chemin d'accès au fichier JAR), le cas échéant, et

    $VICTIM est une chaîne décrivant le membre auquel on accède, y compris le nom qualifié complet du type englobant.

Questions relatives à cet exemple d'avertissement: = JDK9: une opération d'accès par réflexion en cours illégale s'est produite. Org.python.core.PySystemState

Dernier point important, si vous essayez de vous assurer que vous ne faites pas face à de tels avertissements et que vous êtes en sécurité, tout ce que vous avez à faire est de vous assurer que vos modules ne rendent pas ces accès réfléchissants illégaux. :)

29
Naman

Il y a un Oracle article J'ai trouvé concernant le système de module Java 9

Par défaut, un type dans un module n'est pas accessible aux autres modules, sauf s'il s'agit d'un type public et que vous exportez son package. Vous n'exposez que les packages que vous souhaitez exposer. Avec Java 9, cela s'applique également à la réflexion.

Comme indiqué dans https://stackoverflow.com/a/50251958/134894 , les différences entre le AccessibleObject#setAccessible pour JDK8 et JDK9 sont instructives. Plus précisément, JDK9 a ajouté

Cette méthode peut être utilisée par un appelant de la classe C pour permettre l'accès à un membre de la classe de déclaration D si l'une des actions suivantes est en attente:

  • C et D sont dans le même module.
  • Le membre est public et D est public dans un package que le module contenant D exporte vers au moins le module contenant C.
  • Le membre est protégé en statique, D est public dans un package que le module contenant D exporte vers au moins le module contenant C, et C est une sous-classe de D.
  • D est dans un package que le module contenant D ouvre au moins le module contenant C. Tous les packages de modules non nommés et ouverts sont ouverts à tous les modules. Cette méthode réussit donc toujours lorsque D est dans un module non nommé ou ouvert.

qui met en évidence l'importance des modules et de leurs exportations (in Java 9)

16
ptomli

Il suffit de regarder la méthode setAccessible() utilisée pour accéder aux champs et méthodes 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-

Maintenant, il y a beaucoup plus de conditions requises pour que cette méthode fonctionne. La seule raison pour laquelle il ne casse pas la quasi-totalité des logiciels plus anciens est que les modules générés automatiquement à partir de fichiers JAR simples sont très permissifs (ouvrir et exporter tout pour tout le monde).

10
user158037