Facilitating the Spread of Knowledge and Innovation in Professional Software Development

Write for InfoQ


Choose your language

InfoQ Homepage News Internal JDK Elements Strongly Encapsulated in JDK 17

Internal JDK Elements Strongly Encapsulated in JDK 17

This item in japanese

Lire ce contenu en français

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: 

  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.

Rate this Article