webentwicklung-frage-antwort-db.com.de

Was ist ein illegaler reflektierender Zugang?

In Java 9 gibt es viele Fragen zum illegalen reflektierenden Zugriff.

Was ich jetzt nicht finden kann, weil Google nur versucht, die Fehlermeldungen zu umgehen, ist, was ein illegaler reflektierender Zugriff tatsächlich ist.

Meine Frage ist also ziemlich einfach:

Was definiert einen illegalen reflektierenden Zugriff und welche Umstände lösen die Warnung aus?

Ich habe festgestellt, dass es etwas mit den Kapselungsprinzipien zu tun hat, die in Java 9 eingeführt wurden, aber wie alles zusammen hängt und was die Warnung auslöst, in welchem ​​Szenario ich keine Erklärung finden kann.

68
Tschallacka

Abgesehen von einem Verständnis der Zugriffe zwischen Modulen und deren jeweiligen Paketen. Ich glaube, der springende Punkt liegt in der Modul System # Relaxed-Strong-Encapsulation und ich würde nur die relevanten auswählen Teile davon, um zu versuchen, die Frage zu beantworten.

Was definiert einen illegalen reflektierenden Zugriff und welche Umstände lösen die Warnung aus?

Um die Migration auf Java9 zu erleichtern, könnte die starke Verkapselung der Module gelockert werden.

  • Eine Implementierung kann statischen Zugriff bereitstellen, d. H. Durch kompilierten Bytecode.

  • Kann ein Mittel bereitstellen, um sein Laufzeitsystem mit einem oder mehreren Paketen eines oder mehrerer seiner Module aufzurufen, die zum Codieren in alle unbenannten Module geöffnet sind, d. H. Zum Codieren auf dem Klassenpfad. Wenn das Laufzeitsystem auf diese Weise aufgerufen wird und auf diese Weise einige Aufrufe der Reflection-APIs erfolgreich sind, wenn sie andernfalls fehlgeschlagen wären.

In solchen Fällen haben Sie tatsächlich einen reflective access erstellt, was "illegal" ist, da Sie in einer reinen modularen Welt nicht dazu gedacht waren, solche Zugriffe durchzuführen.

Wie hängt das alles zusammen und was löst die Warnung in welchem ​​Szenario aus?

Diese Lockerung der Kapselung wird zur Laufzeit durch eine neue Launcher-Option --illegal-access gesteuert, die in Java9 standardmäßig permit entspricht. Der permit Modus stellt sicher

Bei der ersten Reflective-Access-Operation für ein solches Paket wird eine Warnung ausgegeben, nach diesem Zeitpunkt werden jedoch keine Warnungen mehr ausgegeben. Diese einzelne Warnung beschreibt, wie Sie weitere Warnungen aktivieren. Diese Warnung kann nicht unterdrückt werden.

Die Modi können mit den Werten debug (Nachricht sowie Stacktrace für jeden solchen Zugriff), warn (Nachricht für jeden solchen Zugriff) und deny (Deaktivierung solcher Vorgänge) konfiguriert werden.


Einige Dinge, die Sie debuggen und an Anwendungen beheben müssen, sind:

  • Führen Sie es mit --illegal-access=deny aus, um Pakete ohne eine Moduldeklaration mit einer solchen Direktive (opens) oder einer expliziten Verwendung von open von einem Modul zum anderen zu lernen und zu vermeiden --add-opens VM arg.
  • Statische Verweise von kompiliertem Code auf JDK-interne APIs konnten mithilfe des Tools jdeps mit der Option --jdk-internals identifiziert werden

    Die Warnmeldung, die ausgegeben wird, wenn ein illegaler Reflective-Access-Vorgang erkannt wird, hat die folgende Form:

    WARNING: Illegal reflective access by $PERPETRATOR to $VICTIM
    

    wo:

    $PERPETRATOR ist der vollständig qualifizierte Name des Typs, der den Code enthält, der die betreffende Reflektionsoperation aufgerufen hat, sowie die Codequelle (d. H. Den JAR-Dateipfad), falls verfügbar, und

    $VICTIM ist eine Zeichenfolge, die das Element beschreibt, auf das zugegriffen wird, einschließlich des vollqualifizierten Namens des einschließenden Typs

Fragen für eine solche Beispielwarnung: = JDK9: Es ist eine unzulässige Reflective Access-Operation aufgetreten. Org.python.core.PySystemState

Ein letzter wichtiger Hinweis: Wenn Sie sicherstellen möchten, dass Sie solchen Warnungen nicht ausgesetzt sind und zukunftssicher sind, müssen Sie lediglich sicherstellen, dass Ihre Module diese illegalen reflektierenden Zugriffe nicht ausführen. :)

29
Naman

Es gibt ein Oracle Artikel , das ich in Bezug auf das Java 9-Modulsystem gefunden habe

Standardmäßig können andere Module nicht auf einen Typ in einem Modul zugreifen, es sei denn, es handelt sich um einen öffentlichen Typ, und Sie exportieren das Paket. Sie machen nur die Pakete verfügbar, die Sie verfügbar machen möchten. Bei Java 9 gilt dies auch für die Reflexion.

Wie in https://stackoverflow.com/a/50251958/134894 ausgeführt, sind die Unterschiede zwischen AccessibleObject#setAccessible für JDK8 und JDK9 aufschlussreich. Insbesondere JDK9 hinzugefügt

Diese Methode kann von einem Aufrufer der Klasse C verwendet werden, um den Zugriff auf ein Mitglied der Klasse D zu ermöglichen, wenn eine der folgenden Bedingungen erfüllt ist:

  • C und D befinden sich im selben Modul.
  • Das Mitglied ist public und D ist public in einem Paket, das das Modul mit D in mindestens das Modul mit C exportiert.
  • Das Mitglied ist statisch geschützt, D ist öffentlich in einem Paket, das das Modul mit D in mindestens das Modul mit C exportiert, und C ist eine Unterklasse von D.
  • D befindet sich in einem Paket, das das Modul mit D für mindestens das Modul mit C geöffnet hat. Alle Pakete in unbenannten und offenen Modulen sind für alle Module geöffnet. Diese Methode ist daher immer erfolgreich, wenn D in einem unbenannten oder offenen Modul enthalten ist.

was die Bedeutung von Modulen und deren Export hervorhebt (in Java 9)

16
ptomli

Schauen Sie sich einfach die Methode setAccessible() an, mit der auf private Felder und Methoden zugegriffen wird:

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-

Jetzt sind viel mehr Bedingungen erforderlich, damit diese Methode funktioniert. Der einzige Grund, warum die meisten älteren Programme dadurch nicht kaputt gehen, ist, dass Module, die automatisch aus einfachen JARs generiert wurden, sehr freizügig sind (alles für alle öffnen und exportieren).

10
user158037