La JEP 403 (Strongly Encapsulate JDK Internals), l'une des 14 JEP définies comme l'ensemble de fonctionnalités final pour JDK 17, encapsule fortement tous les éléments internes du JDK, à l'exception des API internes critiques telles que sun.misc.Unsafe
. En tant que successeur de la JEP 396 (Strongly Encapsulate JDK Internals by Default), il ne sera plus possible d'accéder aux API internes via l'option de ligne de commande --illegal-access
.
L'objectif principal de l'encapsulation est d'encourager les développeurs à utiliser des API standard au lieu des API internes pour une sécurité et une maintenabilité accrues. Cela permet également aux développeurs qui contribuent à OpenJDK de mettre à jour le code interne sans casser le code existant. Les développeurs peuvent profiter de l'outil JDeps, avec les plugins Maven et Gradle, pour vérifier si une base de code existante utilise des éléments internes du JDK.
L'option de ligne de commande --add-opens
, également utilisable via l'attribut Add-Opens du fichier manifest d'un fichier JAR, peut être utilisée pour ouvrir des packages spécifiques. Considérez l'exemple suivant qui permettra l'accès via reflexion par tous les unnamed modules au module java.util
.
$ java --add-opens java.base/java.util=ALL-UNNAMED
--classpath {classpath} -jar {jarfile}
Les éléments internes tels que les clés cryptographiques sont actuellement disponibles via la réflexion. Cela inclut toutes les classes, méthodes et champs des packages sun.*
. com.sun.*
, jdk.*
et org.*
qui contiennent également des éléments internes et la liste de tous les packages concernés (internes et exportés) sont disponibles pour revue. La reflection peut toujours être utilisée via les packages sun.misc
et sun.reflect
, qui sont toujours exportés par le module jdk.unsupported
.
La forte encapsulation des API internes du JDK a progressivement évolué au cours des dernières années depuis que le JDK 9 a introduit le système de modules qui fournit une encapsulation forte. Les autres modules ne peuvent utiliser que les classes, méthodes et attributs publics et protégés (via la sous-classe) pendant la compilation et l'exécution des packages exportés par le module.
Depuis sa sortie en 2017, des API prises en charge dans le JDK 9 ont été introduites en remplacement des éléments internes tels que java.util.Base64
, une classe qui se compose de méthodes statiques pour obtenir des encodeurs et des décodeurs pour le schéma d'encodage Base64. Par conséquent, les appels aux API internes doivent être remplacés par des appels aux API prises en charge.
Les nouveaux éléments internes ajoutés dans le JDK 9 et les versions ultérieures sont fortement encapsulés par défaut. Cependant, les API internes introduites avant JDK 9 ne sont pas fortement encapsulées lors de l'exécution.
Avec le JDK 9, il est toujours possible d'accéder aux API internes via l'encapsulation forte relâchée en utilisant l'option de ligne de commande --illegal-access
introduite pour la première fois dans la JEP 261. Cette nouvelle option par défaut --illegal-access=permit
permet à tout le code dans les unnamed modules d'accéder aux API internes par réflexion. Une alternative à --illegal-access=permit
est --illegal-access=warn
qui peut être utilisé pour émettre un avertissement pour chaque accès par reflexion. Des informations supplémentaires sont disponibles via --illegal-access=debug
qui affichera une stacktrace avec chaque avertissement. Avec --illegal-access=deny
, chaque accès par reflexion est bloqué sauf lorsqu'un module est explicitement ouvert avec une autre option de ligne de commande telle que --add-opens
.
Livré dans le JDK 16, la JEP 396 a changé l'option par défaut pour --illegal-access
de permit
à deny
et il est toujours possible d'utiliser explicitement les autres options. La JEP 396 déprécie déjà l'option de ligne de commande --illegal-access
de sorte qu'un avertissement d'obsolescence est émis lors de son utilisation.
Avec la sortie du JDK 17, l'accès sera encore plus restreint aux API internes. L'option --illegal-access
n'autorisera plus l'accès aux API internes. Au lieu de cela, l'option de ligne de commande --add-opens
peut être utilisée pour ouvrir des packages spécifiques.
La tentative d'utilisation de l'option de ligne de commande --illegal-access
avec le JDK 17, par exemple avec la valeur permit
, sur la ligne de commande se traduira par un avertissement :
$ java --illegal-access=permit {filename}.java
OpenJDK 64-Bit Server VM warning: Ignoring option --illegal-access=permit;
support was removed in 17.0
On s'attend à ce que cette option soit complètement supprimée à l'avenir.
Tenter d'accéder à une API interne dans le code source entraînera l'exception suivante :
java.lang.reflect.InaccessibleObjectException:
Unable to make field private final {type} accessible:
module java.base does not "opens {module}" to unnamed module {module}
Voici quelques réponses de la communauté Java : Nicolai Parlog, developer advocate chez Oracle, a fourni un contexte sur l'utilisation des API internes du JDK ; et OkHttp, un projet HTTP proposé par Square Open Source, a documenté comment la JEP 403 a eu un impact sur leur projet en utilisant les API internes.