Wat is een illegale reflectieve toegang?

Er zijn veel vragen over illegale reflectieve toegang in Java 9.

Ik heb veel discussie gevonden over het omzeilen van de foutmeldingen, maar ik zou graag willen weten wat een illegale reflectieve toegang eigenlijk is.

Dus mijn vraag is:

Wat definieert een illegale reflectieve toegang en welke omstandigheden leiden tot de waarschuwing?

Ik heb begrepen dat het iets te maken heeft met de inkapselingsprincipes die in Java 9 zijn geïntroduceerd, maar ik kan geen uitleg vinden over hoe het allemaal in elkaar steekt, waardoor de waarschuwing wordt geactiveerd en in welk scenario.

p>


Antwoord 1, autoriteit 100%

Behalve een begrip van de toegangen tussen modules en hun respectievelijke pakketten. Ik geloof dat de kern ervan ligt in het Modulesysteem#Relaxed-strong- inkapselingen ik zou de relevante delen ervan selecteren om te proberen de vraag te beantwoorden.

Wat definieert een illegale reflectieve toegang en onder welke omstandigheden
de waarschuwing activeren?

Om de migratie naar Java-9 te vergemakkelijken, zou de sterke inkapseling van de modules kunnen worden versoepeld.

  • Een implementatie kan statische toegangbieden, d.w.z. door gecompileerde bytecode.

  • Kan een middel bieden om zijn runtime-systeem aan te roepen met een of meer pakketten van een of meer van zijn modules die openstaan voor code in alle niet nader genoemde modules, dwz om te coderen op het klassenpad . Als het runtime-systeem op deze manier wordt aangeroepen, en als daardoor sommige aanroepen van de reflectie-API’s slagen waar ze anders zouden hebben gefaald.

In dergelijke gevallen heb je uiteindelijk een reflectieve toeganggemaakt die “illegaal”is, aangezien het in een pure modulaire wereld niet de bedoeling was om dergelijke toegangen te doen .

Hoe het allemaal in elkaar steekt en waardoor de waarschuwing wordt geactiveerd in wat?
scenario?

Deze versoepeling van de inkapseling wordt tijdens runtime gecontroleerd door een nieuwe opstartoptie --illegal-accessdie standaard in Java9 gelijk is aan permit. De modus permitzorgt ervoor dat

De eerste bewerking van reflectieve toegang tot een dergelijk pakket veroorzaakt een
waarschuwing moet worden afgegeven, maar daarna worden geen waarschuwingen meer gegeven.
Deze enkele waarschuwing beschrijft hoe u verdere waarschuwingen kunt inschakelen. Dit
waarschuwing kan niet worden onderdrukt.

De modi zijn configureerbaar met waarden debug(message zowel als stacktrace voor elke dergelijke toegang), warn(bericht voor elke dergelijke toegang), en deny(schakelt dergelijke bewerkingen uit).


Er zijn maar weinig dingen om te debuggen en op te lossen in applicaties:-

  • Voer het uit met --illegal-access=denyom meer te weten te komen over en te voorkomen dat het openenpakketten van de ene module naar de andere moet worden geopend zonder een moduleverklaring die een dergelijke instructie bevat (opens) of expliciet gebruik van --add-opensVM-arg.
  • Statische verwijzingen van gecompileerde code naar JDK-interne API’s kunnen worden geïdentificeerd met behulp van de tool jdepsmet de optie --jdk-internals

Het waarschuwingsbericht dat wordt afgegeven bij een illegale bewerking van reflectieve toegang
wordt gedetecteerd heeft de volgende vorm:

WARNING: Illegal reflective access by $PERPETRATOR to $VICTIM

waar:

$PERPETRATORis de volledig gekwalificeerde naam van het type dat de . bevat
code die de betreffende reflectieve bewerking aanriep plus de code
bron (d.w.z. JAR-bestandspad), indien beschikbaar, en

$VICTIMis een tekenreeks die het lid beschrijft dat wordt benaderd,
inclusief de volledig gekwalificeerde naam van het omsluitende type

Vragen voor zo’n voorbeeldwaarschuwing: = JDK9: Er is een illegale reflectieve toegang opgetreden. org.python.core.PySystemState

Als laatste en een belangrijke opmerking, terwijl u probeert ervoor te zorgen dat u dergelijke waarschuwingen niet krijgt en in de toekomst veilig bent, hoeft u alleen maar ervoor te zorgen dat uw modules die illegale reflectieve toegangen niet maken. 🙂


Antwoord 2, autoriteit 38%

Er is een Oracle artikeldat ik heb gevonden over Java 9-modulesysteem

Standaard is een type in een module niet toegankelijk voor andere modules, tenzij het een openbaar type is en u het pakket exporteert. U stelt alleen de pakketten bloot die u wilt weergeven. Bij Java 9 geldt dit ook voor reflectie.

Zoals aangegeven in https://stackoverflow.com/a/50251958/134894, zijn de verschillen tussen de AccessibleObject#setAccessiblevoor JDK8 en JDK9 zijn leerzaam. In het bijzonder is JDK9 toegevoegd

Deze methode kan worden gebruikt door een beller in klasse C om toegang te verlenen aan een lid van klasse D die aangeeft dat een van de volgende zaken geblokkeerd is:

  • C en D zitten in dezelfde module.
  • Het lid is openbaar en D is openbaar in een pakket dat de module met D exporteert naar ten minste de module die C bevat.
  • Het lid is statisch beveiligd, D is openbaar in een pakket dat de module met D exporteert naar ten minste de module die C bevat, en C is een subklasse van D.
  • D zit in een pakket dat de module met D opent naar ten minste de module die C bevat. Alle pakketten in naamloze en open modules staan open voor alle modules en deze methode slaagt dus altijd als D zich in een naamloze of open module bevindt.

die het belang van modules en hun export benadrukt (in Java 9)


Antwoord 3, autoriteit 21%

Kijk maar eens naar de setAccessible()methode die wordt gebruikt om toegang te krijgen tot privatevelden en methoden:

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-

Er zijn nu veel meer voorwaarden vereist om deze methode te laten werken. De enige reden waarom bijna alle oudere software niet kapot gaat, is dat modules die automatisch zijn gegenereerd vanuit gewone JAR’s erg tolerant zijn (alles openen en exporteren voor iedereen).


Antwoord 4

Als je de add-open-optie wilt gebruiken, is hier een commando om uit te zoeken welke module welk pakket levert ->

java --list-modules | tr @ " " | awk '{ print $1 }' | xargs -n1 java -d

de naam van de module wordt weergegeven met de @, terwijl de naam van de pakketten zonder deze

Opmerking: getest met JDK 11

Belangrijk: natuurlijk is beter dan de aanbieder van het pakket niet de illegale toegang


Antwoord 5

Als u waarschuwingen wilt verbergen, kunt u het optie “–ADD-OPENS”

gebruiken

--add-opens <source-module>/<package>=<target-module>(,<target-module>)*

U hebt bijvoorbeeld een foutmelding:

java.lang.ClassLoader.findLoadedClass(java.lang.String)

eerste open string java 11 documentatie
Klasse String waar u module en pakketnaam

kunt vinden

module java.base, pakket java.lang

Oplossing:

java --add-opens=java.base/java.lang=ALL-UNNAMED -jar example.jar

Other episodes