Skip to content

Incompatible changes

Martin Desruisseaux edited this page Aug 3, 2024 · 7 revisions

This page describes behaviors of the compiler plugin that changed in incompatibles way compared to versions 3. Some projects building successfully with version 3 of the compiler plugin may fail with version 4 because of those changes. This page describes corrections that can be applied to projects for fixing those build failures.

Cannot use both --release and --source

As a general rule, the new compiler plugin does not modify the compiler options specified in the configuration. This policy may break projects that specify the <release> option together with <source> and <target>. The previous version of the compiler plugin applied some heuristic rules for deciding which options to pass. The new version passes all options verbatim, which may result if the following message from the javac compiler:

option --source cannot be used together with --release

Correction if the build fails

Removes the <source> and <target> configuration parameters. They may be specified indirectly through the maven.compiler.source and maven.compiler.target properties. If those configuration parameters or properties are inherited from a super-POM that cannot be modified, clear the <source> and <target> parameters as below:

<project>
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <source/>
          <target/>
          <release>17</release>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

Use of dependencies with automatic names

If a dependency does not declare explicitly whether the JAR file should be placed on the class-path or on the module-path, the compiler plugin uses heuristic rules for making its own decision. Those rules are not obvious, and the selected option is not always appropriate for the project. The results may sometime be different between this version and the previous version of the compiler plugin. Some JAR files may placed on the class-path when they were previously on the module-path, or conversely.

By default, a dependency is placed on --module-path if the project is itself modularized (i.e., contains a module-info.java) and one of the following conditions is true:

  • The JAR contains a module-info.class entry.
  • The JAR contains a META-INF/MANIFEST.MF entry with an Automatic-Module-Name attribute.

In all other cases, the dependency is placed on --class-path. This default behavior may be adjusted in future compiler plugin versions depending on experience.

Correction if the build fails

Developers are strongly encouraged to specify explicitly where they want their non-modular JAR files to appear in a modular project. It can be done by setting the type of a dependency to modular-jar or classpath-jar. Example:

<project>
  <dependencies>
    <dependency>
      <groupId>org.codehaus.plexus</groupId>
      <artifactId>plexus-utils</artifactId>
      <version>3.0.24</version>
      <type>modular-jar</type>
    </dependency>
  </dependencies>
</project>

Note that specifying the dependency type is usually not needed in other cases (e.g., non-modular project, or dependencies that are already modular). It should not be needed neither for dependencies with the runtime scope.

Chosing the dependency type

If a non-modular dependency is forced to the modular-jar type, Java will automatically infer a module name from the file name. That module name must be declared in the module-info.java file. For example, for the plexus-utils above:

module my.module {
    requires plexus.utils;
}

Conversely, if a dependency is forced to the classpath-jar type, then the module-info.java is not modified. Instead, the pom.xml file should have the following (replace my.module by the actual project module name):

<project>
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <compilerArgs>
            <arg>--add-reads</arg>
            <arg>my.module=ALL-UNNAMED</arg>
          </compilerArgs>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

Overriding module-info.java in tests

It is not allowed anymore to have a module-info.java defined in both the main and the test directories. The module graph changes required for the tests shall be handled with --add-reads, --add-exports and --add-opens options.

Correction if the build fails

TODO: explain how the plugins make this task easier.

Clone this wiki locally