Why Maven Cannot Generate Your Module Declaration

To declare modules for Java 9’s module system we need to create a file module-info.java – a so called module declaration. Amongst other things, it declares dependencies on other modules. If the project uses a build tool, though, Maven for example, it already manages dependencies. Keeping two files in sync surely seems redundant and error-prone, so the question arises: “Can’t Maven generate the module-info file for me?” Unfortunately, the answer is “No”, and here is why.

(To get the most out of this article, you should be familiar with the module system’s basics, particularly how it manages dependencies. If you want to read up on that, check out this hands-on guide.)

The Motivation

So everyone wonders, can Maven generate the module declaration? The reason is obvious: If I add a dependency to a POM, it is very likely a requirement, too. Or the other way around: If I add a requirement to the declaration, probably a matching dependency must be added to the POM as well. Sounds like something which could be automated.

Let’s start with the attempt to go from requirement back to a dependency: This is not possible because of the lack of information. A module name cannot be transformed to a Maven coordinate, information like the groupId and artifactId is missing. And also: Which version to choose? The module declaration is not interested in which version of an artifact is on the path, only that it is available.

On the other hand, to go from dependency-file to module name is possible. However, that’s not enough to generate all the elements of the module declaration.

Separation of Concerns

When talking about this topic there are three entities in play: Maven’s POM, the module system’s module-info file, and Maven plugins that are involved in building class and module paths. The three together make it possible to work with modules, but they all have their own responsibilities.

POM Dependencies

The task of a dependency is (1) to have a unique reference to a file based on the coordinate and (2) to specify when to use it. The when to use it part is controlled by the scope and is basically any combination of compile, test, and runtime.

The coordinate is a combination of at least the groupId, artifactId, version and file-extension, which is derived from the type. Optionally a classifier could be added as well. Based in this information it is possible to refer to a file in the local repository. It’ll look like the following, where every dot in the groupId is replaced with a slash:

${localRepo}/${groupId}/${artifactId}/${version}/
    ${artifactId}-${version}[-${classifier}].${ext}

As you can see, you can refer to any file: a text-file, an image, an executable. Within the context of the dependency it doesn’t matter. To add to this, the dependency has no idea about the content of the file. For instance in case of a JAR: was it built for Java 8 or Java 1.4, which could make a big difference in case your project has to be compatible with a rather old Java version.

Module Declaration

The module declaration file is built up with five declarations:

requires
The module(s) that must be available to compile or run this application.
exports
The package(s) whose types are visible to a few or all modules.
opens
The package(s) whose types are [accessible via reflection](https://www.sitepoint.com/reflection-vs-encapsulation-in-the-java-module-system/) to a few or all modules.
uses
The service interface(s) that this module may discover.
provides
The implementation(s) provided for a certain service interface.

From these declarations the requires clauses are closely related to the dependencies of the Maven project. If the JDK/JRE together with the dependency-files provided by Maven doesn’t cover these requirements, the project simply won’t compile or run. Consider it as a quality rule one must obey.

Maven Plugins

Every plugin (or actually plugin-goal) can specify the resolution scope for dependencies and get access to these file. For instance the compile-goal of the maven-compiler-plugin states that it uses compile-time dependency resolution. It is up to this plugin to construct the correct arguments for the Java compiler based on the dependency-files provided by Maven and the configuration of the plugin.

Class Paths and Module Paths

Continue reading %Why Maven Cannot Generate Your Module Declaration%


Source: Sitepoint