Существует много вопросов о незаконном отражающем доступе в Java 9.
Я нашел много дискуссий о том, как обойти сообщения об ошибках, но я хотел бы знать, что на самом деле представляет собой незаконный отражающий доступ.
Итак, мой вопрос таков:
Что определяет незаконный отражающий доступ и какие обстоятельства вызывают предупреждение?
Я понял, что это как-то связано с принципами инкапсуляции, которые были представлены в Java 9, но я не могу найти объяснения того, как все это сочетается, что вызывает предупреждение и в каком сценарии.
Переведено автоматически
Ответ 1
Помимо понимания доступа к модулям и их соответствующим пакетам. Я считаю, что суть этого заключается в модульной системе #Relaxed-strong-encapsulation, и я бы просто выбрал соответствующие ее части, чтобы попытаться ответить на вопрос.
Что определяет незаконный отражающий доступ и какие обстоятельства вызывают предупреждение?
Чтобы облегчить переход на Java-9, строгую инкапсуляцию модулей можно было бы ослабить.
Реализация может предоставлять статический доступ, то есть посредством скомпилированного байт-кода.
Может предоставлять средства для вызова своей системы во время выполнения с одним или несколькими пакетами одного или нескольких ее модулей, открытыми для кода во всех неназванных модулях, т. е. для кода в пути к классу. Если система времени выполнения вызывается таким образом, и если при этом некоторые вызовы API отражения завершаются успешно, тогда как в противном случае они завершились бы неудачей.
В таких случаях вы фактически создаете отражающий доступ, который является "незаконным", поскольку в чисто модульном мире вы не должны были выполнять такие обращения.
Как все это сочетается и что вызывает предупреждение, в каком сценарии?
Это ослабление инкапсуляции контролируется во время выполнения новой опцией запуска, --illegal-access которая по умолчанию в Java9 равна permit. Режим permit обеспечивает
Первая операция отражающего доступа к любому такому пакету вызывает выдачу предупреждения, но после этого предупреждения не выдаются. Это единственное предупреждение описывает, как включить дальнейшие предупреждения. Это предупреждение нельзя подавить.
Режимы настраиваются с помощью значений debug(сообщение, а также stacktrace для каждого такого доступа), warn(сообщение для каждого такого доступа) и deny(отключает такие операции).
Несколько вещей, которые необходимо отладить и исправить в приложениях::-
Запустите его с помощью --illegal-access=deny, чтобы узнать об этом и избегать открытияпакетов из одного модуля в другой без объявления модуля, включающего такую директиву (opens) или явного использования --add-opens аргумента виртуальной машины.
Статические ссылки из скомпилированного кода на JDK-внутренние API могут быть идентифицированы с помощью jdeps инструмента с --jdk-internals опцией
Предупреждающее сообщение, выдаваемое при обнаружении незаконной операции отражающего доступа, имеет следующий вид:
WARNING: Illegal reflective access by $PERPETRATOR to $VICTIM
где:
$PERPETRATOR полное имя типа, содержащего код, который вызвал рассматриваемую отражающую операцию, плюс источник кода (т. Е. Путь к JAR-файлу), если таковой имеется, и
$VICTIM это строка, описывающая элемент, к которому осуществляется доступ, включая полное имя заключающего типа
Последнее и важное замечание: пытаясь гарантировать, что вы не столкнетесь с подобными предупреждениями и будете в безопасности в будущем, все, что вам нужно сделать, это убедиться, что ваши модули не выполняют эти незаконные отражающие обращения. :)
По умолчанию тип в модуле недоступен для других модулей, если только это не открытый тип и вы не экспортируете его пакет. Вы предоставляете только те пакеты, которые хотите предоставить. В Java 9 это также относится к отражению.
Как указано в https://javalang.ru/a/50251958/134894, различия между AccessibleObject#setAccessible для JDK8 и JDK9 поучительны. В частности, JDK9 добавил
Этот метод может использоваться вызывающим объектом в классе C, чтобы разрешить доступ к члену объявляющего класса D, если выполняется любое из следующих действий:
C и D находятся в одном модуле.
Элемент является общедоступным, а D является общедоступным в пакете, который модуль, содержащий D, экспортирует по крайней мере в модуль, содержащий C.
Элемент защищен статически, D является общедоступным в пакете, который модуль, содержащий D, экспортирует по крайней мере в модуль, содержащий C, а C является подклассом D.
D находится в пакете, который модуль, содержащий D, открывает по крайней мере для модуля, содержащего C. Все пакеты в неназванных и открытых модулях открыты для всех модулей, и поэтому этот метод всегда срабатывает, когда D находится в неназванном или открытом модуле.
в котором подчеркивается важность модулей и их экспорта (в Java 9)
Ответ 3
если вы хотите скрыть предупреждения, вы могли бы просто использовать опцию "--add-opens"