JDK-8132928 : JEP 260: Encapsulate Most Internal APIs
  • Type: JEP
  • Component: not defined
  • Priority: P1
  • Status: Closed
  • Resolution: Delivered
  • Fix Versions: 9
  • Submitted: 2015-08-03
  • Updated: 2024-04-28
  • Resolved: 2017-09-21
Related Reports
Blocks :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Description
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][sun-faq].  In the modular JDK
([JEP 200][jep-mp]), limiting access to these APIs by leveraging the
module system ([JEP 261][jep-ms]) 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.

[sun-faq]: http://web.archive.org/web/19980215011039/http://java.sun.com/products/jdk/faq/faq-sun-packages.html


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] (`jdeps`), we divide the JDK's internal
APIs into two broad categories:

  - _Non-critical internal APIs_ 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`); and

  - _Critical internal APIs_ which provide critical functionality that
    would be difficult, if not impossible, to implement outside of the
    JDK itself (_e.g._, `sun.misc.Unsafe`).

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:

  - Critical internal APIs for which supported replacements exist in
    JDK 8 are encapsulated in JDK 9.

  - Critical internal APIs for which supported replacements did not exist
    in JDK 8 are not encapsulated in JDK 9.  A detailed list is
    provided below.

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

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][add-exports].  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][illegal-access] and
can be used to emulate the future run-time inaccessibility of internal
APIs.

[illegal-access]: http://openjdk.java.net/jeps/261#Relaxed-strong-encapsulation


### 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.

  - `sun.misc.{Signal,SignalHandler}`

  - `sun.misc.Unsafe` (The functionality of many of the methods in this
    class is available via _variable handles_
    ([JEP 193](http://openjdk.java.net/jeps/193)).)

  - `sun.reflect.Reflection::getCallerClass(int)` (The functionality of
    this method is available in the stack-walking API defined by
    [JEP 259](http://openjdk.java.net/jeps/259).)

  - `sun.reflect.ReflectionFactory`

  - `com.sun.nio.file.{ExtendedCopyOption,ExtendedOpenOption,
    ExtendedWatchEventModifier,SensitivityWatchEventModifier}`

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)][jep-mrjar] in order to ship
single artifacts that use the old APIs on releases prior to JDK 9
and the replacement APIs on later releases.

[jdeps]: https://wiki.openjdk.java.net/display/JDK8/Java+Dependency+Analysis+Tool
[jep-mp]: http://openjdk.java.net/jeps/200
[jep-ms]: http://openjdk.java.net/jeps/261
[ea]: http://jdk9.java.net/
[jep-mrjar]: http://openjdk.java.net/jeps/238
[cleaner]: https://bugs.openjdk.java.net/browse/JDK-8138696
[add-exports]: http://openjdk.java.net/jeps/261#Breaking-encapsulation


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)][jep-mp] defines the modular structure of the
JDK, and [JEP 261 (Module System)][jep-ms] implements the module system.

Comments
Removing the open issue referring to sun.misc.Cleaner. sun.misc.Cleaner was previously listed as a critical internal API, but on further investigation has been removed, 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 on jdk.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 keep sun.misc.Cleaner is questionable. See JDK-8148117 for further details.
03-05-2016