-
Notifications
You must be signed in to change notification settings - Fork 0
Migration
This page lists some usage patterns of Maven 3 which have changed in Maven 4.
The Maven 3 elements are deprecated and should be replaced by the new <sources>
element introduced in Maven 4.
<build>
<sourceDirectory>src/main/java</sourceDirectory>
<testSourceDirectory>src/test/java</testSourceDirectory>
</build>
<build>
<sources>
<source>
<directory>src/main/java</directory>
</source>
<source>
<scope>test</scope>
<directory>src/test/java</directory>
</source>
</sources>
<build>
Note that the declaration of a <sources>
element replaces the default values,
hence the need to declare the source and test directories together.
The new <source>
element allows more flexibility such as specifying many directories,
the include/exclude filters, the targeted Java release and more.
The external plugin used in Maven 3 is no longer needed
and should be replaced by the build-in <sources>
elements.
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<executions>
<execution>
<id>add-directory</id>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>src/extension/java</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<build>
<sources>
<source>
<directory>src/main/java</directory>
</source>
<source>
<directory>src/extension/java</directory>
</source>
<source>
<scope>test</scope>
<directory>src/test/java</directory>
</source>
</sources>
<build>
Reminder: because <sources>
replaces the default values, these defaults need to be explicitly specified.
The new compiler plugin handles automatically multiple executions of javac
with different --release
option values,
and with automatic adjustments of class-path and output directories for producing a multi-releases project.
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<executions>
<execution>
<id>compile-java-17</id>
<goals>
<goal>compile</goal>
</goals>
<configuration>
<release>17</release>
</configuration>
</execution>
<execution>
<id>compile-java-21</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
<configuration>
<release>21</release>
<compileSourceRoots>
<compileSourceRoot>${project.basedir}/src/main/java_21</compileSourceRoot>
</compileSourceRoots>
<multiReleaseOutput>true</multiReleaseOutput>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<build>
<sources>
<source>
<directory>src/main/java</directory>
<targetVersion>17</targetVersion>
</source>
<source>
<directory>src/main/java_21</directory>
<targetVersion>21</targetVersion>
</source>
<source>
<scope>test</scope>
<directory>src/test/java</directory>
</source>
</sources>
</build>
The Maven 3 way to declare include/exclude filters is still supported,
but should be replaced by the <sources>
element when applicable.
Those two ways are not strictly equivalent:
- The Maven 4 way specifies filters independently for each source directory. These filters will be applied by all plugins that migrated to the Maven 4 API, not only the compiler plugin.
- Conversely, the Maven 3 way specifies filters which will be applied only by the compiler plugin. However, these filters apply to all source directories.
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<excludes>
<exclude>**/Foo*.java</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
<build>
<sources>
<source>
<directory>src/main/java</directory>
<excludes>
<exclude>**/Foo*.java</exclude>
</excludes>
</source>
<source>
<scope>test</scope>
<directory>src/test/java</directory>
</source>
</sources>
</build>
The Maven 3 way to make a modular project is to put a module-info.java
file in the root directory of Java source files.
Because the compilation and execution of tests usually require an amended version of module information,
Maven 3 allows to overwrite that file with another module-info.java
file placed in the test source directory.
While this approach is still supported in Maven 4 for compatibility reasons,
it is deprecated and may no longer be supported in a future version.
Developers are strongly encouraged to migrate to the approach described in this section.
The directory layout was as below:
src
├─ main
│ └─ java
│ ├─ module-info.java
│ └─ my/product/*.java
├─ test
│ └─ java
│ ├─ module-info.java
│ └─ my/product/*.java
└─ target
└─ classes
An alternative to test/java/module-info.java
was to declare compiler arguments
such as --add-reads
in the <testCompilerArgs>
element of the plugin configuration.
Same directory layout as Maven 3 with only the test/java/module-info.java
file removed
or replaced by a module-info-patch.maven
file in the same directory.
This approach can be used when compatibility with Maven 3 is required
regarding the source and target directory structures.
src
├─ main
│ └─ java
│ ├─ module-info.java
│ └─ my/product/*.java
├─ test
│ └─ java
│ ├─ module-info-patch.maven (optional)
│ └─ my/product/*.java
└─ target
└─ classes
└─ my/product/*.class
The Maven compiler automatically adds --patch-module
, --add-modules
and --add-reads
arguments for compiling the tests.
In many cases (but not always), a <testCompilerArgs>
plugin configuration is unnecessary.
If more control is needed, a module-info-patch.maven
file can be used instead of the
module-info.java
file which was used to be put in the test/java
directory.
When using the package hierarchy, problems may occur if the module name is a single name without .
separator
(for example, foo
or bar
but not foo.bar
) and that name is identical to a package name.
In such case, the hack implemented in the Maven compiler plugin for Maven 3 compatibility
become confused about whether a directory named foo
represents the module or the package.
For avoiding hack and ambiguity, prefer the module source hierarchy described below.
See the user guide for more information. This approach is recommended for new modular projects, (TODO: pending upgrade of other Maven plugins) as it makes the best use of compiler options dedicated to modular projects.
src
├─ java
│ └─ my.product.foo
│ ├─ main
│ │ ├─ module-info.java
│ │ └─ my/product/*.java
│ └─ test
│ ├─ module-info-patch.maven (optional)
│ └─ my/product/*.java
└─ target
└─ classes
└─ my.product.foo
└─ my/product/*.class
Above layout needs to be declared with the following section in the pom.xml
file:
<build>
<sources>
<source>
<module>my.product.foo</module>
<directory>src/java/my.product.foo/main</directory>
</source>
<source>
<module>my.product.foo</module>
<directory>src/java/my.product.foo/test</directory>
<scope>test</scope>
</source>
</sources>
</build>
The Maven compiler automatically adds --patch-module
and --add-reads
arguments for compiling the tests.
In many cases (but not always), a <testCompilerArgs>
plugin configuration is unnecessary.
For non-modular projects,
or for modular projects that do not use the module source hierarchy described in the above section,
the Maven 3 dependencies of type test-jar
continue to work.
For modular projects using module source hierarchy, an easier alternative is possible
if all the Java modules that need the shared test classes are in the same Maven (sub)project.
In such case, the shared test classes can be declared in any package of any base module
(a module required by all other modules that will need the test classes).
That package does not need to exist in the main code.
It can be, for example, my.product.test
.
Then, the only thing to do is to export that package to the other modules.
It can be done easily with a module-info-patch.maven
file having the following content:
patch-module my.product.foo { // Put here the name of the module to patch.
add-modules TEST-MODULE-PATH; // Recommended value in the majority of cases.
add-reads TEST-MODULE-PATH;
add-exports my.product.test // The package that contains the test fixtures.
to SUBPROJECT-MODULES; // The other modules which want to use those test fixtures.
}
SUBPROJECT-MODULES
is a Maven-specific keyword for exporting to all other Java modules
in the Maven (sub)project being compiled. It can be replaced by an explicit list of modules.
That's all, no need to deploy or install a test JAR.
See the user guide
for more information about the module-info-patch.maven
file.