The Java Platform Module System ( JSR 376)

Final Release Specification

Mark Reinhold

2017/8/21 15:24 -0700 [52c38248458b]

This specification defines the Java Platform Module System.

The goal of this specification, as stated in the JSR, is to define an approachable yet scalable module system for the Java Platform. It must be approachable, i.e., easy to learn and easy to use, so that developers can use it to construct and maintain their own libraries, frameworks, and applications. It must be scalable so that it can be used to modularize the Java SE Platform itself, and its implementations.

This specification achieves that goal by providing two fundamental capabilities:

These capabilities are realized by treating modules as a fundamental new kind of program component that is defined by a construct of the Java programming language and interpreted uniformly at both compile time and run time.

This specification contains:

Related external documents which may be of interest include:

These two documents are cited for information only; they are not part of this specification.

Future work

This specification intentionally leaves some features and capabilities to future releases, when there will be more time to work out the specification and implementation details and when there is more practical experience with the module system to inform choices which at this point are difficult to make. Several potential topics for future exploration are enumerated here, in a rough decreasing order of priority, for the benefit of those who will evolve this specification going forward.

Avoid concealed-package conflicts  Make it easy to load modules, without using reflection, when they contain non-exported packages of the same name.

The simplest way to provide this capability is to load modules that contain conflicting packages into their own class loaders. This approach may seem simple on the surface but it raises numerous design and implementation issues that require careful investigation, so a specific solution is left to a future release.

The impact of leaving this to a future release is ameliorated by two factors: The chances of package-name conflicts are reduced by the near-universal use of the reversed Internet domain-name convention for package names, and there are already effective—if somewhat crude—techniques for coping with conflicting packages, namely shading and shadowing.

Cyclic module relationships  Allow cyclic relationships amongst modules at run time, though not at compile time.

The arguments for forbidding cyclic relationships are that this restriction makes the module graph easier to reason about, it simplifies the module system itself, and that, philosophically, any modules involved in a cycle are logically one module anyway, so they should be defined as such in the first place in order to guide developers toward better design practices. (For further discussion see Kirk Knoernschild’s book, Java Application Architecture, §4.4, “Cyclic Dependencies—The Death Knell.”)

The argument for allowing cyclic relationships, at least at run time, is based on real-world experience with large applications assembled from many unrelated components. In such systems it is possible for cyclic relationships to arise unexpectedly, especially as the application evolves over time. It is useful to be able to accommodate such cycles, if only temporarily, since removing them can be costly or impractical when the components involved have different maintainers.

If cyclic module relationships at run time are allowed now then they could not be disallowed in a future release without breaking compatibility; if they are disallowed now, they could still be allowed later on. If they are ever allowed then that would require non-trivial changes to both this specification and its implementations. There are arguments both for and against allowing such relationships, so the safest course of action is to disallow them in this release and wait to see if practical experience with the module system suggests that they should be allowed in a future release.

Multi-module JAR files  Define a standard way to package more than one module in a single artifact, while preserving module identities and boundaries.

Strong interest in this feature was expressed only late in the development of this specification. It could easily be designed and implemented in a future release.

Additional module-layer operations  Add further methods to the ModuleLayer.Controller API, for use by frameworks and by other module systems.

Two specific methods have been proposed thus far: An addUses method, similar to that already present in the Module class, and an addPackage method, which would add a package to a module that has already been defined. They carry risks and uncertainties, however, so they are left for further investigation in a future release. An addUses method could make it too easy for service dependences to go undeclared, which would be confusing, and sophisticated code can likely work around the lack of this operation via the method-handle API. An addPackage method could impose undesirable constraints on the future evolution of all Java virtual-machine implementations.

History

The following significant changes were made after the Public-Review Reconsideration Specification:

The following changes were made after the second Public Review Specification:

In the second Public Review Specification the API specification was updated to make two significant changes: