JEP 260: Encapsulate Most Internal APIs

AuthorMark Reinhold
OwnerChris Hegarty
TypeFeature
ScopeJDK
StatusClosed / Delivered
Release9
Discussionjigsaw dash dev at openjdk dot java dot net
EffortM
DurationL
BlocksJEP 261: Module System
Relates toJEP 396: Strongly Encapsulate JDK Internals by Default
JEP 403: Strongly Encapsulate JDK Internals
Reviewed byAlan Bateman, Alex Buckley, Brian Goetz, John Rose, Paul Sandoz
Endorsed byBrian Goetz
Created2015/08/03 18:29
Updated2024/04/28 18:11
Issue8132928

Summary

Encapsulate most of the JDK's internal APIs by default so that they are inaccessible at compile time, and prepare for a future release in which they will be inaccessible at run time. Ensure that critical, widely-used internal APIs are not encapsulated, so that they remain accessible until supported replacements exist for all or most of their functionality.

Non-Goals

This JEP does not define replacements for any internal APIs; that work is or will be covered by separate JEPs and, where appropriate, JSRs.

This JEP does not commit to preserve the compatibility of any internal APIs across releases; they continue to remain unstable and subject to change without notice.

Motivation

Some popular libraries make use of non-standard, unstable, and unsupported APIs that are internal implementation details of the JDK and were never intended for external use. In the modular JDK (JEP 200), limiting access to these APIs by leveraging the module system (JEP 261) improves the integrity and security of the platform since many of these internal APIs define privileged, security-sensitive operations. In the long run this change will reduce the costs borne by the maintainers of the JDK itself and by the maintainers of libraries and applications that, knowingly or not, make use of these internal APIs.

Description

Based upon analyses of various large collections of code, including Maven Central, and also feedback received since the release of JDK 8 and its dependency analysis tool (jdeps), we divide the JDK's internal APIs into two broad categories:

Critical internal APIs are encapsulated in JDK 9, or not, according to whether supported replacements exist in JDK 8. A supported replacement is one that was either part of the Java SE 8 standard, i.e., in a java.* or javax.* package, or else JDK-specific and annotated with @jdk.Exported, typically in a com.sun.* or jdk.* package. In detail:

All non-critical internal APIs are encapsulated in JDK 9.

Internal APIs that are encapsulated in JDK 9 are inaccessible at compile time. They can be made accessible at compile time via the --add-exports command-line option. At run time they remain accessible if they were in JDK 8 but in a future release they will become inaccessible, at which point the --add-exports or --add-opens options can be used to make them accessible at run time as well. The --illegal-access option controls the run-time accessibility of these APIs and can be used to emulate the future run-time inaccessibility of internal APIs.

Critical internal APIs not encapsulated in JDK 9

The critical internal APIs that are not encapsulated in JDK 9, because supported replacements did not exist in JDK 8, are listed here.

These APIs are defined in, and exported by, the JDK-specific jdk.unsupported module. This module is present in full JRE and JDK images. These APIs are thus accessible by default to code on the class path, and accessible to code in modules if those modules declare dependences upon the jdk.unsupported module.

Critical internal APIs for which replacements are introduced in JDK 9 are deprecated in JDK 9 and will be either encapsulated or removed in a future release.

A consequence of jdk.unsupported exporting and opening the sun.misc and sun.reflect packages is that all non-critical internal APIs in those packages were either moved to some other package or removed, as appropriate. Standard and JDK modules that are not upgradeable should not depend upon the jdk.unsupported module, but instead use proper internal APIs.

Maintainers of libraries that use critical internal APIs for which replacements exist in JDK 9 may wish to use Multi-Release JAR Files (JEP 238) in order to ship single artifacts that use the old APIs on releases prior to JDK 9 and the replacement APIs on later releases.

Risks and Assumptions

If some widely-used critical internal API was not identified as critical, and that API was moved or removed, then applications that depend upon it will fail.

If some widely-used critical internal API was not identified as critical but still exists then applications that depend upon it may cause a warning to be issued in this release and will fail in a future release.

The short-term workaround for both such situations is for the end user to expose the API via the above-mentioned command-line option; in the longer term, in a later release the API could be moved to the jdk.unsupported module and exported for external use.

The non-critical internal APIs previously present in the sun.misc and sun.reflect packages have been either moved or removed. Existing code that depends upon them may not work correctly.

Dependences

JEP 200 (The Modular JDK) defines the modular structure of the JDK, and JEP 261 (Module System) implements the module system.