JEP 403 (Strongly Encapsulate JDK Internals), one of the 14 JEPs defined as the final feature set for JDK 17, strongly encapsulates all internal elements of the JDK except for critical internal APIs such as sun.misc.Unsafe
. As the successor to JEP 396 (Strongly Encapsulate JDK Internals by Default), it will no longer be possible to access internal APIs via the --illegal-access
command line option.
The main goal for the encapsulation is to encourage developers to use standard APIs instead of the internal APIs for increased security and maintainability. This also allows developers who contribute to OpenJDK to update internal code without breaking existing code. Developers may take advantage of the JDeps tool, with Maven and Gradle plugins, to verify if an existing codebase uses JDK internals.
The --add-opens
command line option, also known as the Add-Opens JAR-file manifest attribute, may be used to open specific packages. Consider the following example that will allow access from all unnamed modules to the java.util
module.
$ java --add-opens java.base/java.util=ALL-UNNAMED
--classpath {classpath} -jar {jarfile}
Internal elements such as cryptographic keys are currently available via reflection. This includes all classes, methods and fields in the sun.*
packages. The com.sun.*
, jdk.*
and org.*
packages also contain some internal elements and the list of all affected packages (internal and exported) are available for review. Reflection may still be used via the sun.misc
and sun.reflect
packages, which are still exported by the jdk.unsupported
module.
Strong encapsulation of the JDK internal APIs have gradually evolved over the past few years since JDK 9 introduced the module system that provided strong encapsulation. Other modules may only use the public and protected (via subclass) classes, methods and attributes during compile and runtime from the packages exported by the module.
Since its release in 2017, supported APIs in JDK 9 were introduced as replacements for the internal elements such as the java.util.Base64
, a class that consists of static methods for obtaining encoders and decoders for the Base64 encoding scheme. Therefore, calls to the internal APIs should be replaced by calls to the supported APIs.
New internal elements added in JDK 9 and later are strongly encapsulated by default. However, internal APIs introduced before JDK 9 aren’t strongly encapsulated at runtime.
With JDK 9, it’s still possible to access the internal APIs through relaxed strong encapsulation by using the --illegal-access
command line option first introduced in JEP 261. The new default --illegal-access=permit
opens all internal code to unnamed modules in which code may access the internal APIs via reflection. An alternative to the --illegal-access=permit
is --illegal-access=warn
which may be used to issue a warning for each reflective access. Additional information is available via --illegal-access=debug
which will print a stack trace along with a warning. With --illegal-access=deny
, every reflective access is blocked except when a module is explicitly opened with another command line option such as --add-opens
.
Delivered in JDK 16, JEP 396 changed the default option for --illegal-access
from permit
to deny
and it’s still possible to explicitly use the other options. JEP 396 already deprecates the --illegal-access
command line option such that a deprecation warning is issued when using it.
With the release of JDK 17, access will be further restricted to the internal APIs. The --illegal-access
option will no longer allow access to internal APIs. Instead, the --add-opens
command line option may be used to open specific packages.
Attempting to use the --illegal-access
command line option with JDK 17, for instance with the value permit
, on the command line will result in a warning:
$ java --illegal-access=permit {filename}.java
OpenJDK 64-Bit Server VM warning: Ignoring option --illegal-access=permit;
support was removed in 17.0
It’s expected that this option will be completely removed in the future.
Attempting to access an internal API in source code will result in the following exception:
java.lang.reflect.InaccessibleObjectException:
Unable to make field private final {type} accessible:
module java.base does not "opens {module}" to unnamed module {module}
Some response from the Java community included: Nicolai Parlog, developer advocate at Oracle, provided a background on the use of JDK internal APIs; and OkHttp, an HTTP project offered by Square Open Source, has documented how JEP 403 has impacted their project using the internal APIs.