Java 9+ projects with module-info
If a project with a module-info.java file does not need to be compatible with Java 8 or earlier environment, there is nothing special to do.
Java 8 projects with module-info
Using the maven-compiler-plugin
Projects that want to be compatible with older versions of Java (i.e, 8 or below bytecode and API), but also want to provide a module-info.java for use on Java 9+ runtime, must be aware that they need to call javac twice:
- the
module-info.javamust be compiled withreleaseset to 9 or later, - the rest of the sources must be compiled with the lower expected compatibility version of source/target.
A way to do this is by having two execution blocks, as described below:
- default
default-compileexecution withreleaseset to 9 or later, - additional custom
base-compileexecution with expected target compatibility.
The following snippet gives an example. This snippet assumes that the JDK used by Maven supports the --release 8 option. It may not be the case for all JDKs, as newer JDKs may drop the support of Java versions that are too old.
<project>
[...]
<build>
[...]
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>...</version>
<executions>
<execution>
<id>default-compile</id>
<configuration>
<release>9</release>
<!-- no excludes: compile everything to ensure module-info contains right entries -->
</configuration>
</execution>
<execution>
<id>base-compile</id>
<goals>
<goal>compile</goal>
</goals>
<configuration>
<release>8</release>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
[...]
</build>
[...]
</project>
If the JDK used by Maven does not support the --release 8 option, then projects which want to be compatible with old Java versions need to use two different JDKs for the two executions. Using a toolchains configuration, it is possible to achieve this, even if more complex. In above snippet, the following fragment:
<release>8</release>
can be replaced by:
<source>1.8</source>
<target>1.8</target>
<jdkToolchain>
<version>1.8</version>
</jdkToolchain>
Using the moditect-maven-plugin
A clean way to generate the module-info.class file without compiling the sources twice is to use the moditect-maven-plugin.
The goal that adds a module descriptor to the project jar is add-module-info.
With this plugin you can keep the maven.compiler.release property set to 8, i.e. the same Java version for the whole build.
A minimal example looks like this:
<project>
<properties>
<maven.compiler.release>8</maven.compiler.release>
<project.package.name>com.example.project</project.package.name>
</properties>
<build>
<plugin>
<groupId>org.moditect</groupId>
<artifactId>moditect-maven-plugin</artifactId>
<version>1.3.0.Final</version>
<executions>
<execution>
<id>add-module-infos</id>
<phase>package</phase>
<goals>
<goal>add-module-info</goal>
</goals>
<configuration>
<module>
<moduleInfo>
<name>${project.package.name}</name>
<exports>
${project.package.name};
</exports>
</moduleInfo>
</module>
</configuration>
</execution>
</executions>
</plugin>
</build>
</project>
Summary
maven-compiler-plugin+ two compiler runs – flexible but a bit cumbersome.moditect-maven-plugin– createsmodule‑info.classin a single build pass, keeps the target Java version (e.g.,8) unchanged, and reduces build‑time complexity.

