що таке незаконний світловідбиваючий доступ


126

Є багато питань щодо незаконного відбиваючого доступу в Java 9.

Тепер я не можу знайти, тому що все, що Google підводить, - це люди, які намагаються обійти повідомлення про помилки - це те, що насправді є незаконним відбиваючим доступом.

Тож моє запитання досить просте:

Що визначає незаконний відбиваючий доступ та які обставини викликають попередження?

Я зібрав, що це має щось спільне з принципами інкапсуляції, які були запроваджені в Java 9, але як це все звисає і що викликає попередження, у якому сценарії я не можу знайти пояснення.


2
це також може вас зацікавити: jaxenter.com/jdk-9-replace-permit-illegal-access-134180.html
Едвін

Відповіді:


54

Крім розуміння доступу до модулів та відповідних пакетів. Я вважаю, що суть цього полягає в модульній системі # Розслаблена-сильна капсуляція, і я б просто вишнево підбирав відповідні її частини, щоб спробувати відповісти на питання.

Що визначає незаконний відбиваючий доступ та які обставини викликають попередження?

Для сприяння переходу на Java-9, сильне капсулювання модулів може бути послаблене.

  • Реалізація може забезпечити статичний доступ , тобто шляхом складеного байтового коду.

  • Може забезпечити засіб виклику своєї системи запуску з одним або декількома пакетами одного або декількох модулів, відкритих для кодування у всіх неназваних модулях , тобто для кодування на classpath. Якщо система запущеного часу викликається таким чином, і якщо це зробити, деякі виклики API-інтерфейсів відображення досягають успіху, інакше вони б не змогли.

У таких випадках ви насправді зробили рефлексивний доступ, який є "незаконним", оскільки в чистому модульному світі вам не передбачалося робити такі доступи.

Як це все висить разом і що викликає попередження в якому сценарії?

Це розслаблення інкапсуляції контролюється під час виконання новою опцією запуску, --illegal-accessяка за замовчуванням у Java9 дорівнює permit. У permitрежимі гарантує

Перша операція з відображенням доступу до будь-якого такого пакету викликає попередження, але попередження не надходять після цього. Це єдине попередження описує, як увімкнути подальші попередження. Це попередження не можна придушити.

Режими можна налаштувати зі значеннями debug(повідомлення, а також стеження за кожним таким доступом), warn(повідомлення для кожного такого доступу) та deny(відключає такі операції).


Кілька речей для налагодження та виправлення програм:

  • Запустіть його, --illegal-access=denyщоб ознайомитись і уникати відкриття пакетів від одного модуля до іншого без оголошення модуля, що включає таку директиву ( opens) або явне використання --add-opensVM arg.
  • Статичні посилання зі скомпільованого коду на внутрішні API API JDK можна ідентифікувати за допомогою jdepsінструменту з --jdk-internalsможливістю

Попереджувальне повідомлення, яке видається при виявленні незаконної операції з відображенням, має таку форму:

WARNING: Illegal reflective access by $PERPETRATOR to $VICTIM

де:

$PERPETRATOR - це повністю кваліфіковане ім’я типу, що містить код, який викликав відповідну відображаючу операцію плюс джерело коду (тобто, JAR-файл-шлях), якщо такий є, і

$VICTIM - рядок, який описує член, до якого звертаються, включаючи повністю кваліфіковане ім'я типу, що додається

Питання до такого зразка попередження: = JDK9: Виникла незаконна операція відображення доступу. org.python.core.PySystemState

Останнє та важливе зауваження, намагаючись упевнитись, що ви не стикаєтеся з подібними попередженнями та не будете безпечними у майбутньому, все, що вам потрібно зробити, це переконатися, що ваші модулі не роблять цих незаконних відбиваючих доступу. :)


21

Існує стаття Oracle, яку я знайшов щодо системи модулів Java 9

За замовчуванням тип модуля недоступний для інших модулів, якщо це не загальнодоступний тип, і ви експортуєте його пакет. Ви виставляєте лише ті пакунки, які хочете викрити. З Java 9 це стосується і рефлексії.

Як було зазначено в https://stackoverflow.com/a/50251958/134894 , відмінності між AccessibleObject#setAccessibleJDK8 та JDK9 є повчальними. Зокрема, додано JDK9

Цей метод може бути використаний абонентом класу C, щоб дозволити доступ до члена декларування класу D, якщо будь-яке з наведених нижче умов:

  • C і D знаходяться в одному модулі.
  • Член є загальнодоступним, а D - публічним у пакеті, який модуль, що містить D, експортує щонайменше до модуля, що містить C.
  • Член захищений статично, D є загальнодоступним у пакеті, який модуль, що містить D, експортує щонайменше до модуля, що містить C, а C є підкласом D.
  • D - це пакет, що модуль, що містить D, відкривається щонайменше для модуля, що містить C. Усі пакети в неназваних та відкритих модулях відкриті для всіх модулів, тому цей метод завжди досягає успіху, коли D знаходиться в неназваному або відкритому модулі.

що підкреслює значення модулів та їх експорт (на Java 9)


2
Тож якщо я прочитав цю статтю, правильно змінюючи приватні властивості в експортованих класах, виключається з таблиці. Можуть змінюватися лише захищені та загальнодоступні властивості. Тепер я не дуже переймаюся експортом інтервалу Java, але більше про сторонні бібліотеки, де мені іноді потрібен доступ до приватної змінної, щоб встановити певне значення. Це вже було б неможливо в цій схемі, якби вона визначала себе як модуль, чи правильно це?
Чаллачка

1
У мене немає прямого досвіду з цим, але це було б моє розуміння, і читати поряд із статтею, згаданою в іншому місці ( jaxenter.com/jdk-9-replace-permit-illegal-access-134180.html ), що, здавалося б, справа. Запустіть свій JVM з –illegal-access=permit...
ptomli

1
Ну, це зробить речі цікавішими, намагаючись змусити роботу працювати на деякі речі, коли вони вирішать перейти на модульний шлях. Попереду супер веселі часи.
Чаллачка

1
Для різних значеньfun
ptomli

Я прийняв іншу відповідь, тому що вона дала більше пояснень і була більше відповіді на питання, але, на жаль, я не можу прийняти дві відповіді.
Цхаллачка

13

Просто подивіться на setAccessible()метод, який використовується для доступу до 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-

Зараз існує набагато більше умов, необхідних для роботи цього методу. Єдина причина, по якій вона не порушує майже все старіше програмне забезпечення, - це те, що модулі, що генеруються із звичайних JAR, дуже дозволені (відкривати та експортувати все для всіх).


1

Якщо ви хочете перейти з опцією add-open, ось команда знайти який модуль надає, який пакет ->

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

назва модуля відображатиметься із символом @, а назва пакунків без нього

ПРИМІТКА: тестовано на JDK 11

ВАЖЛИВО: очевидно, краще, ніж постачальник пакету не робить незаконний доступ

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.