Это исключение возникает в самых разных сценариях при запуске приложения на Java 9. Некоторые библиотеки и фреймворки (Spring, Hibernate, JAXB) особенно подвержены этому. Вот пример от Javassist:

java.lang.reflect.InaccessibleObjectException: Unable to make protected final java.lang.Class java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain) throws java.lang.ClassFormatError accessible: module java.base does not "opens java.lang" to unnamed module @1941a8ff
    at java.base/jdk.internal.reflect.Reflection.throwInaccessibleObjectException(Reflection.java:427)
    at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:201)
    at java.base/java.lang.reflect.Method.checkCanSetAccessible(Method.java:192)
    at java.base/java.lang.reflect.Method.setAccessible(Method.java:186)
    at javassist.util.proxy.SecurityActions.setAccessible(SecurityActions.java:102)
    at javassist.util.proxy.FactoryHelper.toClass2(FactoryHelper.java:180)
    at javassist.util.proxy.FactoryHelper.toClass(FactoryHelper.java:163)
    at javassist.util.proxy.ProxyFactory.createClass3(ProxyFactory.java:501)
    at javassist.util.proxy.ProxyFactory.createClass2(ProxyFactory.java:486)
    at javassist.util.proxy.ProxyFactory.createClass1(ProxyFactory.java:422)
    at javassist.util.proxy.ProxyFactory.createClass(ProxyFactory.java:394)

В сообщении написано:

Невозможно сделать защищенный конечный java.lang.Class java.lang.ClassLoader.defineClass (java.lang.String, byte [], int, int, java.security.ProtectionDomain) вызывает java.lang.ClassFormatError доступным: модуль java.base не «открывает java.lang» для безымянного модуля @ 1941a8ff

Что можно сделать, чтобы избежать исключения и успешно запустить программу?

Ответы (16)

Исключение вызвано Системой модулей платформы Java, которая была представлена ​​в Java 9, в частности, ее реализацией строгой инкапсуляции. Он разрешает доступ только при определенных условиях, наиболее важными из них являются:

  • тип должен быть публичным
  • пакет-владелец должен быть экспортирован

Те же ограничения справедливы и для отражения, которое пытался использовать код, вызывающий исключение. Точнее исключение вызвано вызовом setAccessible. Это можно увидеть в трассировке стека выше, где соответствующие строки в javassist.util.proxy.SecurityActions выглядят следующим образом:

static void setAccessible(final AccessibleObject ao,
                          final boolean accessible) {
    if (System.getSecurityManager() == null)
        ao.setAccessible(accessible); // <~ Dragons
    else {
        AccessController.doPrivileged(new PrivilegedAction() {
            public Object run() {
                ao.setAccessible(accessible);  // <~ moar Dragons
                return null;
            }
        });
    }
}

Чтобы убедиться, что программа работает успешно, необходимо убедить модульную систему разрешить доступ к элементу, для которого был вызван setAccessible. Вся необходимая для этого информация содержится в сообщении об исключении, но для этого существует ряд механизмов. Какой из них лучший, зависит от точного сценария, который его вызвал.

Невозможно сделать {member} доступным: модуль {A} не «открывает {package}» для {B}

Безусловно, наиболее заметными сценариями являются следующие два:

  1. Библиотека или фреймворк используют отражение для вызова модуля JDK. В этом сценарии:

    • {A} - это модуль Java (с префиксом java. или jdk.)
    • {member} и {package} являются частями Java API
    • {B} - это модуль библиотеки, фреймворка или приложения; часто безымянный модуль @ ...
  2. Библиотека / фреймворк на основе отражения, например Spring, Hibernate, JAXB, ... отражает код приложения для доступа к bean-компонентам, сущностям и т. Д. В этом сценарии:

    • {A} - это модуль приложения
    • {member} и {package} являются частью кода приложения
    • {B} - это либо модуль фреймворка, либо безымянный модуль @ ...

Обратите внимание, что некоторые библиотеки (например, JAXB) могут выйти из строя для обеих учетных записей, поэтому внимательно посмотрите, в каком сценарии вы находитесь! Речь идет о случае 1.

1. Отражающий звонок в JDK

Модули JDK неизменяемы для разработчиков приложений, поэтому мы не можем изменять их свойства. Остается только одно возможное решение: флаги командной строки. С их помощью можно открывать определенные пакеты для размышлений.

Итак, в случае, как указано выше (сокращенно) ...

Невозможно сделать java.lang.ClassLoader.defineClass доступным: модуль java.base не «открывает java.lang» для безымянного модуля @ 1941a8ff

... правильное решение - запустить JVM следующим образом:

# --add-opens has the following syntax: {A}/{package}={B}
java --add-opens java.base/java.lang=ALL-UNNAMED

Если отражающий код находится в названном модуле, ALL-UNNAMED можно заменить его именем.

Обратите внимание, что иногда бывает трудно найти способ применить этот флаг к JVM, который фактически выполнит отражающий код. Это может быть особенно сложно, если рассматриваемый код является частью процесса сборки проекта и выполняется в JVM, созданной инструментом сборки.

Если необходимо добавить слишком много флагов, вы можете рассмотреть возможность использования выключателя отключения инкапсуляции - разрешить-незаконный-доступ. Это позволит всему коду на пути к классу отражать все именованные модули. Обратите внимание, что этот флаг будет работать только в Java 9!

2. Отражение по коду приложения

В этом сценарии, вероятно, вы сможете отредактировать модуль, в который используется отражение. (В противном случае, вы фактически находитесь в случае 1.) Это означает, что флаги командной строки не нужны, и вместо этого можно использовать дескриптор модуля {A}для открытия его внутренних компонентов. Есть несколько вариантов:

  • экспорт пакета с помощью exports {package}, что делает его доступным во время компиляции и выполнения для всего кода
  • экспортирует пакет в модуль доступа с помощью экспорта {package} в {B}, что делает его доступным во время компиляции и выполнения, но только в {B}
  • открыть пакет с помощью открывает {package}, что делает его доступным во время выполнения (с отражением или без него) для всего кода
  • открыть пакет для модуля доступа с помощью открывает {package} для {B}, что делает его доступным во время выполнения (с отражением или без него), но только для {B}
  • открыть весь модуль с помощью open module {A} {...}, что делает все его пакеты доступными во время выполнения (с отражением или без него) для всего кода

См. этот пост для более подробного обсуждения и сравнения этих подходов.

Я столкнулся с аналогичной проблемой при запуске SornarQube, и я нашел обходной путь для загрузки отчета сонара, выполнив следующие действия:

Существующий пакет: Java 16.0.2, MacOS (BigSur)

  • Установлен sonar_scanner
  • Выполните эту команду: export SONAR_SCANNER_OPTS = "- незаконный доступ = разрешение"

Надеюсь, это поможет кому-то, если он столкнется с той же проблемой, он / она может попробовать. : -)

Для меня я только что сменил версию spring-boot-starter-web и у меня работал

У меня были предупреждения при гибернации 5.

Illegal reflective access by javassist.util.proxy.SecurityActions

Я добавил последнюю версию библиотеки javassist в gradle зависимостей:

compile group: 'org.javassist', name: 'javassist', version: '3.22.0-GA'

Это решило мою проблему.

Я столкнулся с той же проблемой после импорта существующего проекта Springboot на основе JDK1.8 в SpringTestSuite4. Когда я запустил приложение на встроенном сервере Tomcat, я получил эту ошибку

java.lang.reflect.InaccessibleObjectException: невозможно сделать защищенный окончательный java.lang.Class java.lang.ClassLoader.defineClass (java.lang.String, byte [], int, int, java.security.ProtectionDomain) выбрасывает java.lang.ClassFormatError доступным: модуль java.base делает не «открывает java.lang» для безымянного модуля @ 140c9f39% 09

Я добавил предустановленную JDK1.8 JRE с моего ПК в SpringTestSuite4 в разделе «Установленная JRE» в разделе «Окно» -> «Настройки» -> «Java» и сделал добавленную JRE по умолчанию. Затем я нажал «Применить», а затем «Закрыть».

У меня сработало.

В затмении:

Windows -> Preferences -> Java -> Installed JREs

В открывшемся мастере нажмите «Добавить», выберите Стандартная виртуальная машина и нажмите Далее, а затем выберите путь к установленной Java в программных файлах. Например, для меня это было C: \ Program Files \ Java \ jre1.8.0_301 \ lib.

Нажмите «Готово», затем выберите только что добавленную JR.

Right-click on your Project -> Build Path -> Configure Build Path

В открывшемся мастере перейдите на вкладку Библиотеки и нажмите Добавить библиотеку, затем выберите Системная библиотека JRE нажмите «Далее». Выберите Альтернативная JRE, а затем выберите JRE, добавленную ранее, из раскрывающегося списка. Щелкните Готово. Перейдите на вкладку Порядок и экспорт, выберите добавленную JRE и переместите ее над другой системной библиотекой, которая вызвала проблему. Выберите применить и закрыть. Готово.

Добавьте --illegal-access = warn и --add-opens java.base / java.lang = ALL-UNNAMED в ваш eclipse.ini

Использование --add-opens следует рассматривать как обходной путь. Правильно, если Spring, Hibernate и другие библиотеки делают незаконный доступ для решения своих проблем.

В 2021 году проблема возникала только тогда, когда я использовал версию 16 языка OpenJDK. Она сработала, когда я перешел на более раннюю версию. Я предполагаю, что это связано с тем, что OpenJDK сделал это: JEP 396: строго инкапсулирует внутренние компоненты JDK по умолчанию

Как указать eclipse для добавления-экспорта при компиляции

Я выполнил шаги из верхнего комментария, но во всплывающем окне Конфигурация экспорта-добавления я ввожу модули, которые были в моей ошибке, и выбрал открывает флажок вместо экспортирует флажок и сохранил его. Это устранило мою проблему.

Для Eclipse, Вам нужно две вещи, перейти на

  1. Окно -> Предпочтения -> Java -> Компилятор Установите уровень соответствия компилятора для конкретной версии В моем случае версия Eclipse была установлена ​​на JDK 16, я вернул ее к 1.8, поскольку мой код был написан в 1.8

  2. Окно -> Настройки -> Java -> Установленные JRE. Добавьте путь установки JRE (Выберите стандартную виртуальную машину)

У меня сработало ровно ..

Перейдите в файл eclipse.ini в каталоге Eclipse и добавьте следующее. Это решит проблему.

- незаконный доступ = предупреждать

- надстройка открывает java.base / java.lang = ALL-UNNAMED

У меня была такая же проблема в 2021 году при использовании openJDK 1.8 и STS 4.

Window => Preferences => Java => Installed JREs.

Я добавил новую JRE (упомянутую ниже), используя опцию добавления, перешел в папку openJdk и выбрал OK. Сделайте новый JDK по умолчанию. Нажмите «Применить» и закройте.

/usr/lib/jvm/java-1.8.0-openjdk-amd64/jre

Сработало как шарм :)

Столкнулся с такой же проблемой. Одна из причин может заключаться в использовании неправильного JDK / Project SDK.

Чтобы решить эту проблему в Intellij:

Щелкните правой кнопкой мыши проект Maven -> Открыть настройки модуля -> Проект Настройки -> Проект -> Выберите свой SDK для уже установленного JDK 1.8

У меня сработало!

Это очень сложная проблема; и, как отмечали другие, параметр --add-opens - это только обходной путь. Актуальность решения основных проблем возрастет только после того, как Java 9 станет общедоступной.

Я оказался на этой странице после того, как получил эту точную ошибку Javassist во время тестирования своего приложения на основе Hibernate на Java 9. И поскольку я стремлюсь поддерживать Java 7, 8 и 9 на нескольких платформах, я изо всех сил пытался найти лучшее решение . (Обратите внимание, что Java 7 и 8 JVM немедленно прерывают работу, когда они видят нераспознанный аргумент «--add-opens» в командной строке; поэтому это не может быть решено с помощью статических изменений в пакетных файлах, сценариях или ярлыках.)

• 100001 *

После долгих экспериментов и тестов я с облегчением нашел решение для Hibernate:

  1. Используйте Hibernate 5.0.0 или выше (более ранние версии не работают) и
  2. Запрос улучшение байт-кода во время сборки (с использованием подключаемых модулей Gradle, Maven или Ant).

Это избавляет Hibernate от необходимости выполнять модификации классов на основе Javassist во время выполнения, устраняя трассировку стека, показанную в исходном сообщении.

ОДНАКО, вам следует после этого тщательно протестировать свое приложение. Изменения байт-кода, применяемые Hibernate во время сборки, по-видимому, отличаются от тех, которые применяются во время выполнения, что вызывает несколько иное поведение приложения. Модульные тесты в моем приложении, которые успешно работали в течение многих лет, внезапно перестали работать, когда я включил улучшение байт-кода во время сборки. (Мне пришлось искать новые исключения LazyInitializationExceptions и другие проблемы.) И поведение, похоже, различается от одной версии Hibernate к другой. Действуйте осторожно.

Только недавний отзыв

Многие предложения по решению этой проблемы касаются опции запуска vm - нелегальный доступ.

Согласно Oracle, с JEP 403 (link1) и JEP 403 (link2), который был решен , доставленным из JDK 17 и далее, опция запуска - нелегальный доступ перестанет работать!

Резюме Строго инкапсулируйте все внутренние элементы JDK, кроме для критически важных внутренних API, таких как sun.misc.Unsafe. Это больше не будет можно ослабить сильную инкапсуляцию внутренних элементов с помощью единственная опция командной строки, как это было возможно в JDK 9 - JDK 16.

И

С этим изменением больше не сможет использовать конечные пользователи параметр --illegal-access, чтобы разрешить доступ к внутренним элементам JDK. (Список затронутых пакетов доступен здесь.) Пакеты sun.misc и sun.reflect по-прежнему будут экспортироваться jdk.unsupported, и он по-прежнему будет открыт, чтобы код мог получить доступ их непубличные элементы через отражение. Никакие другие пакеты JDK не будут будьте открыты таким образом.

Еще можно будет использовать - адд открывает параметр командной строки или Add-Opens Атрибут манифеста JAR-файла для открытия определенных пакетов.

Таким образом, следующее решение будет продолжать работать

# --add-opens has the following syntax: {A}/{package}={B}
java --add-opens java.base/java.lang=ALL-UNNAMED

Но решение с - незаконный доступ перестанет работать с JDK 17 и далее.

2022 WebDevInsider