JEP 260: Encapsulate Most Internal APIs

AuthorMark Reinhold
OwnerChris Hegarty
Created2015/08/03 18:29
Updated2016/07/12 15:27
TypeFeature
StatusCompleted
ScopeJDK
Discussionjigsaw dash dev at openjdk dot java dot net
EffortM
DurationL
Priority1
Reviewed byAlan Bateman, Alex Buckley, Brian Goetz, John Rose, Paul Sandoz
Endorsed byBrian Goetz
Release9
Issue8132928
BlocksJEP 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:

In JDK 9 we propose to:

The critical internal APIs proposed to remain accessible in JDK 9 are:

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:

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.

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.

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 ( StackTraceElement.getClassName() ) change from sun.reflect.XXX to 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 details.