Строгая инкапсуляция внутренних API в JDK 17

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!

В JDK 17 вошли 14 JEP, один из которых — JEP 403 (Strongly Encapsulate JDK Internals), — строго инкапсулирует все внутренние элементы JDK, за исключением некоторых критических API, таких как sun.misc.Unsafe. Как преемник JEP 396 (Strongly Encapsulate JDK Internals by Default) он еще больше ограничивает доступ к внутренним API и к ним больше нельзя получить доступ с помощью параметра --illegal-access.

Основной целью инкапсуляции является улучшение безопасности и сопровождаемости через использование стандартного API вместо внутреннего. Это также позволит разработчикам OpenJDK изменять внутреннюю реализацию, не ломая обратной совместимости. Проверить использование в вашем коде внутренних компонент можно с помощью утилиты JDeps с плагинами Maven и Gradle.

Для открытия определенных пакетов можно использовать параметр командной строки --add-opens или атрибут Add-Opens в манифесте JAR-файла. Например, открыть доступ к модулю java.util из всех безымянных модулей можно следующим образом:

$ java --add-opens java.base/java.util=ALL-UNNAMED 
  --classpath {classpath} -jar {jarfile}

Внутренние элементы, такие как криптографические ключи, пока еще доступны через рефлекшн. А также все классы, методы и поля из пакетов sun.* и некоторые внутренние API в пакетах com.sun.*, jdk.* и org.* . Список пакетов, которые не открыты по умолчанию можно посмотреть здесь. Также рефлекшн все еще можно использовать для пакетов sun.misc и sun.reflect, так как они экспортируются модулем jdk.unsupported.

Строгая инкапсуляция внутренних API постепенно развивалась в течение последних лет, с тех пор как в JDK 9 появилась система модулей, обеспечивающая строгую инкапсуляцию: обращаться можно только к public и protected (через подкласс) классам, методам и полям в пакетах, экспортированных определенным модулем.

В JDK 9 некоторые внутренние API заменены публичными, например, java.util.Base64 (класс, состоящий из статических методов для кодирования и декодирования Base64). Поэтому стоит заменить вызовы внутренних API на публичные.

Новые внутренние элементы, добавленные в JDK 9 и позднее, по умолчанию строго инкапсулированы. Однако для внутренних API, появившихся до JDK 9, строгая инкапсуляция в рантайме отсутствует.

В JDK 9 можно по-прежнему получить доступ к внутренним API через ослабление строгой инкапсуляции с помощью параметра --illegal-access, впервые представленного в JEP 261. Значение по умолчанию --illegal-access=permit открывает весь внутренний код для безымянных модулей с доступом через рефлекшн. Альтернативой --illegal-access=permit является --illegal-access=warn. В этом случае при каждом доступе через рефлекшн выдается предупреждение. Через --illegal-access=debug доступна дополнительная информация с трассировкой стека. Параметр --illegal-access=deny блокирует любой доступ через рефлекшн, кроме случаев, когда к модулю явно открывается доступ с помощью такого параметра как --add-opens.

В JDK 16 (JEP 396) значение по умолчанию для --illegal-access изменилось с permit на deny (другие значения по-прежнему доступны) и параметр --illegal-access объявлен устаревшим (при его использовании выводится предупреждение).

JDK 17 продолжает ограничение доступа к внутренним API. Параметр --illegal-access больше не разрешает доступ к внутренностям, и вместо него для открытия определенных пакетов используется --add-opens.

Попытка использовать --illegal-access в JDK 17, например, со значением permit, приведет к предупреждению:

$ java --illegal-access=permit {filename}.java

OpenJDK 64-Bit Server VM warning: Ignoring option --illegal-access=permit; 
  support was removed in 17.0

Ожидается, что в будущем этот параметр будет полностью удален.

Попытка доступа к внутреннему API приведет к следующему исключению:

java.lang.reflect.InaccessibleObjectException: 
  Unable to make field private final {type} accessible:
  module java.base does not "opens {module}" to unnamed module {module}

В статье использовались материалы от Java-сообщества. Nicolai Parlog, developer advocate в Oracle, рассказал об использовании внутренних API JDK. OkHttp (проект Square Open Source) написали, как JEP 403 повлиял на их проект, использующий внутренние API.


Материал подготовлен в рамках курса «Java Developer. Professional». Если вам интересно узнать подробнее о формате обучения и программе, познакомиться с преподавателем курса — приглашаем на день открытых дверей онлайн. Регистрация здесь.

Источник: https://habr.com/ru/company/otus/blog/576688/


Интересные статьи

Интересные статьи

Приветствую вас (лично вас, а не всех кто это читает)! Сегодня мы: Создадим приложение (навык) Алисы с использованием нового (октябрь 2019) сервиса Yandex Cloud Functions. Настроим н...
Компании растут и меняются. Если для небольшого бизнеса легко прогнозировать последствия любых изменений, то у крупного для такого предвидения — необходимо изучение деталей.
Если у вас есть интернет-магазин и вы принимаете платежи через Интернет, то с 01 июля 2017 года у вас есть онлайн-касса.
В 2019 году люди знакомятся с брендом, выбирают и, что самое главное, ПОКУПАЮТ через интернет. Сегодня практически у любого бизнеса есть свой сайт — от личных блогов, зарабатывающих на рекламе, до инт...
Если Вы используете в своих проектах инфоблоки 2.0 и таблицы InnoDB, то есть шанс в один прекрасный момент столкнуться с ошибкой MySQL «SQL Error (1118): Row size too large. The maximum row si...