Tuesday, January 8, 2019

Explicitly Naming Automatic Java Modules

Nicolas Fränkel recently published the surprising post "A hard look at the state of Java modularization." In that post, Fränkel provides the results of his investigation into support available in the 29 libraries referenced in the blog post "20 popular Java libraries" for modules introduced with JDK 9. Fränkel's investigation aimed to identify which of these popular Java libraries was "modularized" (fully implemented module defined in module-info.java) or provided at least an "automatic module name" via MANIFEST.MF even if the library isn't modularized.

Of the 29 popular Java libraries investigated, Fränkel identified only two (SLF4J 1.8.0-beta2 and JAXB 2.3.1) that are fully modularized. Of the remaining 27 libraries that are not fully modularized, 12 do have an automatic module name defined. That means, of course, that 15 of the 29 libraries (just over 50%) do not have any explicit support for modularity introduced with JDK 9!

In the post "Automatic-Module-Name: Calling all Java Library Maintainers" a little over one year ago, Sander Mak (one of the authors of Java 9 Modularity) describes "what needs to be done to move the Java library ecosystem toward modules." Mak explains that "support for the Java module system can be incrementally added to libraries" and uses this post to "explain the first step ... to becoming a Java module." Mak writes:

This first step boils down to picking a module name, and adding it as Automatic-Module-Name: <module name> entry to the library's MANIFEST.MF. That's it. With this first step you make your library usable as Java module without moving the library itself to Java 9 or creating a module descriptor for the library, yet.

In the "Automatic-Module-Name: Calling all Java Library Maintainers" post, Mak also provides guidance for providing an automatic name for a module. He recommends picking an explicit name for the module rather than relying on the ModuleFinder-based name derivation algorithm (module named based on JAR filename). Mak references Stephen Colebourne's post "Java SE 9 - JPMS automatic modules," in which Colebourne concludes, "Community members must at all costs avoid publishing modular jar files that depend on filenames." Incidentally, Colebourne's post "Java SE 9 - JPMS module naming" provides additional guidance on module naming.

The naming of the automatic module is significant because later changes to that name will cause backwards incompatibilities for the library. It is also important to not have the module name collide with others' libraries' module names. The recommended way of doing this is to use the root package name contained within the module, assuming that package uses the typical Java package naming convention to ensure uniqueness.

Mak also outlines in his post some "potential issues you need to verify" before adding the Automatic-Module-Name entry to the MANIFEST.MF file to avoid "false expectations." See the "Sanity-Check Your Library" section of Mak's post for the full list and detailed description of these issues which include not using internal JDK types and not having any classes in the unnamed package.

Before concluding my post, I am going to briefly present the difference between an explicitly named automatic module and an implicitly named automatic module. For this, I'll be using a JAR file generated from the code example in my previous post "Parsing Value from StreamCorruptedException: invalid stream header Message." The Java source is not that important for my purposes here other than to point out that the main class used in my post has the package name dustin.utilities.io.

The generated JAR file, which I've called io-examples.jar is not modularized (does not have a module-info file). The jar tool's option --describe-module can be used to quickly determine the automatic module name of the JAR file.

The next two screen snapshots show the results of running jar with the --describe-module option against the JAR. The first screen snapshot indicates the results when the JAR has nothing in its MANIFEST.MF file to indicate an automatic module name. The result is a automatic module named after the JAR name. The second screen snapshot shows the results from running jar --describe-module against the almost identical JAR except for the addition of the attribute Automatic-Module-Name: dustin.utilities.io to the JAR's MANIFEST.MF file. In that case, the automatic module is named the explicitly provided name provided in the manifest file (dustin.utilities.io).

Fränkel opens his post with the assertion, "With the coming of Java 11, the latest Long-Term Support, I think it's a good time to take a snapshot of the state of modularization." I too think that recent and pending changes make it more important for all of us in the Java community to start understanding Java's built-in modularity and its implications and to take steps toward more complete modularity support.

Additional (Previously Referenced) Resources

No comments: