JEP 260: Encapsulate Most Internal APIs
|Discussion||jigsaw dash dev at openjdk dot java dot net|
|Reviewed by||Alan Bateman, Alex Buckley, Brian Goetz, John Rose, Paul Sandoz|
|Endorsed by||Brian Goetz|
|Blocks||JEP 261: Module System|
Make most of the JDK's internal APIs inaccessible by default but leave a few critical, widely-used internal APIs accessible, until supported replacements exist for all or most of their functionality.
This JEP will not itself propose replacements for any internal APIs; that work 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.
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. Limiting access to these APIs by leveraging the forthcoming module system (JEP 200) will improve 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.
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 can divide the JDK's
internal APIs into two broad categories:
Those which do not appear to be used by code outside of the JDK, or are used by outside code merely for convenience, i.e., for functionality that is available in supported APIs or can easily be provided by libraries (e.g.,
Those which provide critical functionality that would be difficult, if not impossible, to implement outside of the JDK itself (e.g.,
In JDK 9 we propose to:
Encapsulate all non-critical internal APIs by default: The modules that define them will not export their packages for outside use. (Access to such APIs will be available, as a last resort, via a command-line flag at both compile time and run time, unless those APIs are revised or removed for other reasons.)
Encapsulate critical internal APIs for which supported replacements exist in JDK 8, in the same manner and with the same last-resort workaround. (A supported replacement is one that is either part of the Java SE 8 standard (i.e., in a
javax.*package) or else JDK-specific and annotated with
@jdk.Exported(typically in a
Not encapsulate critical internal APIs for which supported replacements do not exist in JDK 8 and, further, deprecate those which have supported replacements in JDK 9 with the intent to encapsulate them, or possibly even remove them, in JDK 10.
The critical internal APIs proposed to remain accessible in JDK 9 are:
sun.misc.Unsafe(The functionality of many of the methods in this class is now available via variable handles (JEP 193).)
sun.reflect.Reflection::getCallerClass(int)(The functionality of this method may be provided in a standard form via JEP 259.)
Suggested additions to this list, justified by real-world use cases and estimates of developer and end-user impact, are welcome.
The above critical internal APIs will be placed in, and their packages
exported from, a JDK-specific module named
jdk.unsupported. This module
will be present in full JRE and JDK images. These APIs will therefore be
accessible by default to code on the class path, and accessible to code
in modules if those modules declare dependences upon the
As noted above, replacements for some of these internal APIs already exist, in whole or in part, in JDK 9. Developers are strongly encouraged to test these replacements in the JDK 9 early-access builds and send feedback if the replacements are not sufficient or could be improved.
Critical internal APIs for which replacements are introduced in JDK 9 will be deprecated in JDK 9 and either encapsulated or removed in JDK 10.
The consequence of
sun.reflect is that:
non-critical internal APIs in the
sun.reflectpackages will be moved, or removed as appropriate, since they should not be accessible
standard and JDK modules cannot depend on
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 is not identified by the time
that JDK 9 is released then applications that depend upon it will fail.
The short-term workaround for such a situation would be for the end user
to expose the API via the above-mentioned command-line flag; in the
longer term, in a JDK 9 update release the API could be moved to the
jdk.unsupported module and exported for external use.
jdk.unsupported module will export
sun.reflect, all non-critical internal APIs in these packages will be
moved, or removed, as appropriate. If removed they will no longer be
visible or accessible. If moved they will be accessible, through the use
of a command-line flag, but their fully qualified name will be changed,
i.e. they will be in a package of another name.
Beyond the proposed critical APIs for
sun.reflect, said package contains
the machinery that implements the
java.lang(.reflect) subsystem. That
machinery will be moved to an internal, non-exported, package in the base
module. Consequently, the stack trace of reflective calls will appear
somewhat different. That is, stack frames that represent the reflective
implementation will see their class name (
jdk.internal.reflect.XXX. Any code
analysing, or filtering, based on the stack trace element's class name
should be updated appropriately, to handle this. See
8137058 for further