JEP 403: Strongly Encapsulate JDK Internals

AuthorsAlex Buckley, Mark Reinhold
OwnerMark Reinhold
TypeFeature
ScopeSE
StatusClosed / Delivered
Release17
Discussionjigsaw dash dev at openjdk dot java dot net
EffortXS
DurationXS
Relates toJEP 396: Strongly Encapsulate JDK Internals by Default
Reviewed byAlan Bateman, Chris Hegarty, Mandy Chung
Endorsed byBrian Goetz
Created2021/03/13 00:19
Updated2021/09/08 21:25
Issue8263547

Summary

Strongly encapsulate all internal elements of the JDK, except for critical internal APIs such as sun.misc.Unsafe. It will no longer be possible to relax the strong encapsulation of internal elements via a single command-line option, as was possible in JDK 9 through JDK 16.

History

This JEP is the successor to JEP 396, which transitioned the JDK from a default of relaxed strong encapsulation to a default of strong encapsulation, while allowing users to return to the relaxed posture if they wished. The Goals, Non-Goals, Motivation, and Risks and Assumptions section of this JEP are essentially identical to that of JEP 396 but are reproduced here for the reader’s convenience.

Goals

Non-Goals

Motivation

Over the years the developers of various libraries, frameworks, tools, and applications have used internal elements of the JDK in ways that compromise both security and maintainability. In particular:

In Java 9, we improved both the security and the maintainability of the JDK by leveraging modules to limit access to its internal elements. Modules provide strong encapsulation, which means that

Strong encapsulation applies at both compile time and run time, including when compiled code attempts to access elements via reflection at run time. The non-public elements of exported packages, and all elements of unexported packages, are said to be strongly encapsulated.

In JDK 9 and later releases we strongly encapsulated all new internal elements, thereby limiting access to them. As an aid to migration, however, we deliberately chose not to strongly encapsulate, at run time, the internal elements that had existed in JDK 8. Library and application code on the class path could thus continue to use reflection to access the non-public elements of java.* packages, and all elements of sun.* and other internal packages, for packages that existed in JDK 8. This arrangement is called relaxed strong encapsulation, and was the default behavior in JDK 9.

We released JDK 9 back in September 2017. Most of the commonly-used internal elements of the JDK now have standard replacements. Developers have had over three years in which to migrate away from internal elements of the JDK to standard APIs such as java.lang.invoke.MethodHandles.Lookup::defineClass, java.util.Base64, and java.lang.ref.Cleaner. Many library, framework, and tool maintainers have completed that migration and released updated versions of their components. The need for relaxed strong encapsulation is weaker now than it was in 2017, and it weakens further every year.

In JDK 16, released in March 2021, we took the next step toward strongly encapsulating all internal elements of the JDK. JEP 396 made strong encapsulation the default behavior except for critical internal APIs such as sun.misc.Unsafe, which remained available. In JDK 16 it was still possible for end users to choose relaxed strong encapsulation in order to gain access to internal elements that existed in JDK 8.

We are now ready to take one more step in this journey by removing the ability to choose relaxed strong encapsulation. This means that all internal elements of the JDK will be strongly encapsulated except for critical internal APIs such as sun.misc.Unsafe.

Description

Relaxed strong encapsulation is controlled by the launcher option --illegal-access. This option, introduced by JEP 261, was provocatively named in order to discourage its use. In JDK 16 and earlier releases, it works as follows:

As the next step toward strongly encapsulating all internal elements of the JDK, we propose to make the --illegal-access option obsolete. Any use of this option, whether with permit, warn, debug, or deny, will have no effect other than to issue a warning message. We expect to remove the --illegal-access option entirely in a future release.

With this change, it will no longer be possible for end users to use the --illegal-access option to enable access to internal elements of the JDK. (A list of the packages affected is available here.) The sun.misc and sun.reflect packages will still be exported by the jdk.unsupported module, and will still be open so that code can access their non-public elements via reflection. No other JDK packages will be open in this way.

It will still be possible to use the --add-opens command-line option, or the Add-Opens JAR-file manifest attribute, to open specific packages.

Exported com.sun APIs

Most com.sun.* packages in the JDK are for internal use, but a few are supported for external use. These supported packages were exported in JDK 9 and will continue to be exported, so you can continue to program against their public APIs. They will, however, no longer be open. Examples include

Risks and Assumptions

The primary risk of this proposal is that existing Java code will fail to run. The kinds of code that will fail include, but are not limited, to:

We encourage all developers to:

Secondary risks

Examples of the impact of this change