JEP 260: Encapsulate Most Internal APIs
Author | Mark Reinhold |
Owner | Chris Hegarty |
Created | 2015/08/03 18:29 |
Updated | 2016/03/10 21:54 |
Type | Feature |
Status | Proposed to Target |
Scope | JDK |
Discussion | jigsaw dash dev at openjdk dot java dot net |
Effort | M |
Duration | L |
Priority | 1 |
Reviewed by | Alan Bateman, Alex Buckley, Brian Goetz, John Rose, Paul Sandoz |
Endorsed by | Brian Goetz |
Release | 9 |
Issue | 8132928 |
Blocks | JEP 261: Module System |
Summary
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.
Non-Goals
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.
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. 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.
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 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.,
sun.misc.BASE64Decoder
); andThose which provide critical functionality that would be difficult, if not impossible, to implement outside of the JDK itself (e.g.,
sun.misc.Unsafe
).
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
java.*
orjavax.*
package) or else JDK-specific and annotated with@jdk.Exported
(typically in acom.sun.*
orjdk.*
package).)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.{Signal,SignalHandler}
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
(The functionality of this method may be provided in a standard form via JEP 259.)sun.reflect.ReflectionFactory
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 jdk.unsupported
module.
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 jdk.unsupported
exporting sun.misc
and
sun.reflect
is that:
non-critical internal APIs in the
sun.misc
andsun.reflect
packages will be moved, or removed as appropriate, since they should not be accessiblestandard and JDK modules cannot depend on
jdk.unsupported
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.
Open Issues
sun.misc.Cleaner
( was previously listed as a critical internal API, but on further investigation has been moved to an open issue, for the following reasons: 1) its primary use in the JDK is within NIO direct buffers to release native memory. The base module cannot have a dependency onjdk.unsupported
so will need to be updated to use an alternative cleaner, 2) the usage of Cleaner outside the JDK, as determined by corpus analysis, has largely been observed to hack into private fields of the internal NIO direct buffer classes to explicitly release native memory. As stated in 1), the type of the cleaner used by NIO direct buffers will have to change. Given this, and the fact that JDK 9 has a new general purposed cleaner API, java.lang.ref.Cleaner, the value of keepsun.misc.Cleaner
is questionable.
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.
Since the jdk.unsupported
module will export sun.misc
and
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.