The Java Platform Module System
- 9.1 The Module Concept
- 9.2 Naming Modules
- 9.3 The Modular "Hello, World!" Program
- 9.4 Requiring Modules
- 9.5 Exporting Packages
- 9.6 Modular JARs
- 9.7 Modules and Reflective Access
- 9.8 Automatic Modules
- 9.9 The Unnamed Module
- 9.10 Command-Line Flags for Migration
- 9.11 Transitive and Static Requirements
- 9.12 Qualified Exporting and Opening
- 9.13 Service Loading
- 9.14 Tools for Working with Modules
Learn how encapsulation characterizes object-oriented programming. Declare and use Java platform modules, and migrate your applications to work with the modularized Java platform and third-party modules.
An important characteristic of object-oriented programming is encapsulation. A class declaration consists of a public interface and a private implementation. A class can evolve by changing the implementation without affecting its users. A module system provides the same benefits for programming in the large. A module can make classes and packages selectively available so that its evolution can be controlled.
Several existing Java module systems rely on class loaders to isolate classes. However, Java 9 introduced a new system, called the Java Platform Module System, that is supported by the Java compiler and virtual machine. It was designed to modularize the large code base of the Java platform. You can, if you choose, use this system to modularize your own applications.
Whether or not you use Java platform modules in your own applications, you may be impacted by the modularized Java platform. This chapter shows you how to declare and use Java platform modules. You will also learn how to migrate your applications to work with the modularized Java platform and third-party modules.
9.1 The Module Concept
In object-oriented programming, the fundamental building block is the class. Classes provide encapsulation. Private features can only be accessed by code that has explicit permission—namely, the methods of the class. This makes it possible to reason about access. If a private variable has changed, you can produce a set of all possible culprits. If you need to modify the private representation, you know which methods are affected.
In Java, packages provide the next larger organizational grouping. A package is a collection of classes. Packages also provide a level of encapsulation. Any feature with package access (neither public nor private) is accessible only from methods in the same package.
However, in large systems, this level of access control is not enough. Any public feature (that is, a feature that is accessible outside a package) is accessible everywhere. Suppose you want to modify or drop a rarely used feature. Once it is public, there is no way to reason about the impact of that change.
This is the situation that the Java platform designers faced. Over twenty years, the JDK grew by leaps and bounds, but clearly some features are now essentially obsolete. Everyone’s favorite example is CORBA. When was the last time you used it? Yet, the org.omg.corba package was shipped with every JDK until Java 10. As of Java 11, those few who still need it must add the required JAR files to their projects.
What about java.awt? It shouldn't be required in a server-side application, right? Except that the class java.awt.DataFlavor is used in the implementation of SOAP, an XML-based web services protocol.
The Java platform designers, faced with a giant hairball of code, decided that they needed a structuring mechanism that provides more control. They looked at existing module systems (such as OSGi) and found them unsuitable for their problem. Instead, they designed a new system, called the Java Platform Module System, that is now a part of the Java language and virtual machine. That system has been used successfully to modularize the Java API, and you can, if you so choose, use it with your own applications.
A Java platform module consists of
A collection of packages
Optionally, resource files and other files such as native libraries
A list of the accessible packages in the module
A list of all modules on which this module depends
The Java platform enforces encapsulation and dependencies, both at compile time and in the virtual machine.
Why should you consider using the Java Platform Module System for your own programs instead of following the traditional approach of using JAR files on the class path? There are two advantages.
Strong encapsulation: You can control which of your packages are accessible, and you don't have to worry about maintaining code that you didn't intend for public consumption.
Reliable configuration: You avoid common class path problems such as duplicate or missing classes.
There are some issues that the Java Platform Module System does not address, such as versioning of modules. There is no support for specifying which version of a module is required, or for using multiple versions of a module in the same program. These can be desirable features, but you must use mechanisms other than the Java Platform Module System if you need them.