Proposal: #AutomaticModuleNames (revised)

Issue summary ------------- #AutomaticModuleNames -- Revise the algorithm that computes the names of automatic modules to include the Maven group identifier, when available in a JAR file's `pom.properties` file, so that module names are less likely to collide, or else drop the automatic-modules feature entirely, since it may be more trouble than it's worth. [1] Proposal -------- - Do not drop the automatic-modules feature. It's a critical part of the overall migration story: It allows application developers to get started modularizing their own code without having to wait for all of the libraries and frameworks that they use to be modularized. Popular libraries and frameworks that are actively maintained will hopefully be modularized fairly soon, but less-active projects will take longer -- perhaps years or even decades -- and many inactive or abandoned projects will never be modularized. This feature has been well-received by a wide variety of developers despite the fact that some expert users are not comfortable with it. - Define a JAR-file manifest attribute, `Automatic-Module-Name`, whose value is used as the name of the automatic module defined by that JAR file when it is placed on the module path, as previously suggested [2][3]. If a JAR file on the module path does not have such a manifest attribute then its automatic-module name is computed using the existing filename-based algorithm. The name of this attribute is now `Automatic-Module-Name` rather than `Module-Name`. The former makes it clear that if a JAR file on the module path contains both an `Automatic-Module-Name` manifest attribute and an explicit `module-info.class` file then the manifest attribute is irrelevant, because the module defined by the JAR file is explicit rather than automatic. `Module-Name` would also suggest that there are `Module-Exports` and `Module-Requires` attributes, which there are not. With this mechanism a library maintainer can claim a stable module name with very little effort; in Maven, e.g., a manifest attribute can be added in just a few lines of a project's `pom.xml` file. A library maintainer can claim a stable name early, before all of the library's dependencies are modularized, which will allow libraries and applications that depend upon it to be modularized immediately. A user of a library can suggest a stable name to the library's maintainer, and easily submit a patch that implements it. This will enable the uncoordinated modularization of libraries across the entire ecosystem. - Strongly recommend that all modules be named according to the reverse Internet domain-name convention. A module's name should correspond to the name of its principal exported API package, which should also follow that convention. If a module does not have such a package, or if for legacy reasons it must have a name that does not correspond to one of its exported packages, then its name should at least start with the reversed form of an Internet domain with which the author is associated. - Make sure that developers are aware of the risks of publishing, for broad use, explicit modules that require automatic modules. An automatic module is unreliable, since it can depend on types on the class path, and its name and exported packages could change if and when it's converted into an explicit module. It's fine to declare and use explicit modules that require automatic modules in limited settings. If you publish such a module to, e.g., Maven Central, then you must be prepared to revise both the declaration and content of your module as its dependencies are modularized over time. This may have an adverse impact on the users of your module, especially if your module `requires transitive` an automatic module. The following three points are essentially unchanged from the first proposal [4]: - Do not revise the algorithm that computes the names of automatic modules. The suggestion to use Maven coordinates when available [5] would help less than half of the most popular projects in use today, as determined by three different surveys. It would result in module names that are often annoyingly verbose and known to be objectionable to some module authors, and it would raise non-trivial issues with regard to standardization and convention. The names generated by the current algorithm do not follow the reverse-DNS convention, but they are at least easily derivable from the name of the original JAR files. [6] - To increase awareness of when automatic modules are used, and of the consequences of their use, suggest that Java language compilers issue two new types of warnings, and implement these warnings in the RI: - An opt-in (i.e., off-by-default) warning on a reference to an automatic module in a `requires` directive in a module declaration, and - An opt-out (i.e., on-by-default) warning on a reference to an automatic module in a `requires transitive` directive in a module declaration. The first warning allows developers to be maximally hygienic if they so choose. The second helps make the author of an explicit module aware that they're putting the users of that module at risk by establishing implied readability to an automatic module. - Encourage Java run-time systems to make it easy to identify via, e.g., command-line options, which observable modules are automatic, which observable modules would establish implied readability to automatic modules if resolved, and which automatic observable modules are actually resolved. Implement these capabilities in the RI. Notes ----- This revised proposal is informed by a vigorous discussion on the OpenJDK jigsaw-dev mailing list [7] of the first proposal [4]. Two things became clear in that discussion, and in related discussions triggered by it. First, after twenty years the reverse-DNS naming convention is deeply ingrained in the minds of most Java developers. Stephen Colebourne made a clear and passionate case for it [8] and many developers voiced support for his argument, both on Twitter and elsewhere. Some people may prefer shorter, project-oriented names, and those can be fine to use in limited projects that will never, ever see the light of day outside of a single organization. If you create a module that has even a small chance of being open-sourced in the future, however, then the safest course is to choose a reverse-DNS name for it at the start. Second, the fact that the name and effective API of an automatic module are inherently unstable is less of a problem than I previously thought [9][a]. Developers who use Maven and related tools, such as Gradle -- which is most developers -- are used to coping with breakage when they upgrade the dependencies of a project to a newer version [b][c]. If the name or effective API of an automatic module change, either when its maintainer adds an `Automatic-Module-Name` attribute or writes an explicit `module-info.java` file, then the maintainers of projects that use that module will just fix any problems that they encounter when they upgrade. After thinking about the first observation I'm now convinced that if tools insert `Automatic-Module-Name` manifest attributes then they will only do so when the module names that they define follow the reverse-DNS convention, since to do otherwise would go against what most developers strongly prefer and expect. After thinking about that and the second observation I hereby retract [d] my previous advice [9] that automatic modules should not be given stable names. * * * In related threads on jigsaw-dev both Stephen Colebourne [e] and Robert Scholte [f] suggest a new kind of explicit module, variously called "partial" or "incomplete" or "soft", which can read all unnamed modules so that dependencies that have not yet been modularized can be left on the class path. This is an attractive notion on the surface, and in fact one that we partly implemented in the prototype code base over two years ago, using the term "loose". We didn't pursue it then, however, and I don't think it's worth pursuing now, for two reasons: - If "partial" (or whatever) modules were to replace automatic modules then application developers would have to wait until all of their dependencies have been at least "partially" modularized before they can even begin to experiment with modularizing their own code. - We could solve that by keeping automatic modules and adding partial modules, but then we'd have a more complex module system and a more complex story to tell. To consider just one possible question, should developers go ahead and use their dependencies as automatic modules, or wait for them to become named automatic modules, or wait for them to become partial modules? The `Automatic-Module-Name` manifest attribute is, from a technical standpoint, aesthetically unpleasant since it defines a second way to name modules. Taken alone, however, it does enable uncoordinated modularization using stable module names with little effort, and so it appears to be the least-bad option on the table. [1] http://openjdk.java.net/projects/jigsaw/spec/issues/#AutomaticModuleNames [2] http://mail.openjdk.java.net/pipermail/jpms-spec-experts/2017-February/000582.html [3] http://openjdk.java.net/projects/jigsaw/spec/issues/#ModuleNameInManifest [4] http://mail.openjdk.java.net/pipermail/jpms-spec-experts/2017-April/000667.html [5] http://mail.openjdk.java.net/pipermail/jpms-spec-experts/2017-January/000537.html [6] http://mail.openjdk.java.net/pipermail/jpms-spec-experts/2017-April/000666.html [7] http://mail.openjdk.java.net/pipermail/jigsaw-dev/2017-April/thread.html#11955 [8] http://blog.joda.org/2017/04/java-se-9-jpms-module-naming.html [9] http://mail.openjdk.java.net/pipermail/jpms-spec-experts/2017-April/000682.html [a] http://mail.openjdk.java.net/pipermail/jigsaw-dev/2017-April/012304.html [b] http://mail.openjdk.java.net/pipermail/jigsaw-dev/2017-April/012327.html [c] http://mail.openjdk.java.net/pipermail/jigsaw-dev/2017-April/012335.html [d] http://mail.openjdk.java.net/pipermail/jigsaw-dev/2017-April/012367.html [e] http://mail.openjdk.java.net/pipermail/jigsaw-dev/2017-April/012370.html [f] http://mail.openjdk.java.net/pipermail/jigsaw-dev/2017-April/012399.html