Older projects with module-info

Projects that want to be compatible with older versions of Java (i.e 1.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:

  1. the module-info.java must be compiled with release=9,
  2. while the rest of the sources must be compiled with the lower expected compatibility version of source/target.

The preferred way to do this is by having 2 execution blocks, as described below:

  1. default default-compile execution with release=9,
  2. additional custom base-compile execution with expected target compatibility.

Notice that, in addition, JDK 9 only supports compilations for Java 6 and above, so projects wanting to be compatible with Java 5 or below need to use two different JDKs for the 2 executions. With toolchains configuration, it is quite easy to achieve this, even if a little bit more complex.

Java 6 to 8 Compatibility

In case you want the project to be Java 6, 7 or 8 compatible, you can simply use JDK 9 for both execution blocks.

The easiest way is to use Java 9 as the runtime for Maven, by setting JAVA_HOME=/path/to/jdk-9 before running mvn. But if you want to use an older Java runtime for Maven, you can use the maven-toolchain-plugin to specify the shared JDK or a custom jdkToolchain and refer to the JDK 9 installation on your system.

<project>
  [...]
  <build>
    [...]
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.13.0</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>
              <!-- recompile everything for target VM except the module-info.java -->
              <excludes>
                <exclude>module-info.java</exclude>
              </excludes>
            </configuration>
          </execution>
        </executions>
        <!-- defaults for compile and testCompile -->
        <configuration>
          <release>6</release><!-- or 7 or 8 depending on compatibility expectations -->
          <!-- Only required when Maven runtime JAVA_HOME isn't at least Java 9 and when haven't configured the maven-toolchains-plugin -->
          <jdkToolchain>
            <version>9</version>
          </jdkToolchain>
        </configuration>
      </plugin>
    </plugins>
    [...]
  </build>
  [...]
</project>

Java 5 or below Compatibility

Given that Maven 3 requires newer Java release at runtime, you'll absolutely need to use Toolchains to use a JDK different from Maven runtime.

You could add a jdkToolchain to do base-compile execution-block as well referring to JDK 5.

<project>
  [...]
  <build>
    [...]
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.13.0</version>
        <executions>
          <execution>
            <id>default-compile</id>
            <configuration>
              <release>9</release>
              <!-- no excludes: compile everything to ensure module-info contains right entries -->
              <!-- toolchain required when JAVA_HOME is JDK 8 or below -->
              <jdkToolchain>
                <version>9</version>
              </jdkToolchain>
            </configuration>
          </execution>
          <execution>
            <id>base-compile</id>
            <goals>
              <goal>compile</goal>
            </goals>
            <configuration>
              <!-- recompile everything for target VM except the module-info.java -->
              <excludes>
                <exclude>module-info.java</exclude>
              </excludes>
            </configuration>
          </execution>
        </executions>
        <!-- defaults for compile and testCompile -->
        <configuration>
          <source>1.5</source>
          <target>1.5</target>
          <!-- jdkToolchain required when JAVA_HOME is JDK 9 or above -->
          <jdkToolchain>
            <version>[1.5,9)</version>
          </jdkToolchain>
        </configuration>
      </plugin>
    </plugins>
    [...]
  </build>
  [...]
</project>