-
Notifications
You must be signed in to change notification settings - Fork 0
User guide
This page gives an introduction to the Maven compiler plugin 4.0. For differences compared to the previous compiler plugin, see migration from Maven 3 to Maven 4.
The recommended way to declare source directories is with <source>
elements.
Note that these sources are declared in the <build>
element and therefore can apply to all plugins.
If no source is declared, the default values relevant to the compiler plugin are as below:
<build>
<sources>
<source>
<lang>java</lang>
<scope>main</scope>
<directory>src/main/java</directory>
</source>
<source>
<lang>java</lang>
<scope>test</scope>
<directory>src/test/java</directory>
</source>
</sources>
<build>
If a <sources>
element is declared, its content will replace the above default values.
Therefore, the above defaults may need to be copied if the developer wants to add sources
instead of replacing them.
The <source>
element can be repeated as many times as desired for the same language and scope.
Optionally, an enabled
flag allows to include or exclude the whole directory according a property value.
The following example adds the extension
directory only if the value of the include.extension
property is set to true
.
For brevity, this example uses the default values of the <scope>
and <lang>
elements when applicable.
<build>
<sources>
<source>
<directory>src/main/java</directory>
</source>
<source>
<directory>src/extension/java</directory>
<enabled>${include.extension}</enabled>
</source>
<source>
<scope>test</scope>
<directory>src/test/java</directory>
</source>
</sources>
<build>
The <source>
element can be repeated many times with different Java releases.
The lowest release value is given to the --release
compiler option for the base classes,
and the source files in all directories associated to that version are compiled together.
Then, the sources of all other releases are compiled in separated javac
executions,
one execution for each release, in the order of increasing release values.
For each new execution, the output directories of all previous executions are added to the class-path with highest releases first,
and the output is written in the META-INF/versions/${release}/
sub-directory.
Example:
<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>
Note: For targeting Java 8, the version number shall be 8
, not 1.8
.
For each source directory, the list of source files to compile can be filtered.
If <include>
elements are specified, only the files that match at least one include filters may be compiled.
If no <include>
element is specified, then the default filter is glob:**/*.java
.
Next, if <exclude>
elements are specified, all included elements matching at least one exclude filter become excluded.
The filtering implementation uses java.nio.file.PathMatcher
. The syntax is described in the
Javadoc of standard Java.
Various syntaxes are possible, including glob and regex.
If no syntax is specified, Maven defaults to the glob syntax where
/
is the path separator regardless the platform (including Windows),
*
matches any filename inside a directory and **
matches any number of directories
(see above-cited Javadoc for more detailed explanation).
All paths to be matched are relative to the path specified in the <directory>
element.
Example:
<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 recommended way to build a project using the Java Module System is to declare the module name(s)
together with the sources, as in the example below. The name declared inside the <module>
element
must match the name declared inside the module-info.java
file of that module.
More than one module can be declared if desired.
It means that for Java modular projects, there is no longer a one-to-one relationship between a
Maven project or subproject and a Java module, unless the developer chooses to restrict herself
to exactly one Java module per Maven subproject. Note, however, that there is still a one-to-one
relationship between Java modules and Maven artifacts (the JAR files identified by Maven coordinates).
See the maven-jar-plugin
for more information.
(TODO: maven-jar-plugin
has not yet been updated for Java module support.)
<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>
<source>
<module>my.product.bar</module>
<directory>src/java/my.product.bar/main</directory>
</source>
<source>
<module>my.product.bar</module>
<directory>src/java/my.product.bar/test</directory>
<scope>test</scope>
</source>
</sources>
</build>
While it is a common practice to have a sub-directory of the same name as the module, this is not mandatory.
It is also a common practice to place the main
and test
sub-directories after the java
sub-directory
instead of before it (in order to group them per module), but this is not mandatory neither.
It is also possible to specify multiple source directories for the same module.
For a modular project, the compiler writes the class files of each module in a directory of the same name as the module.
For example, the classes of the my.product.foo
module will be written in the target/classes/my.product.foo/
directory
rather than directly in target/classes/
. This is the standard javac
behavior, not a Maven particularity.
Technically, the behavior of the Maven compiler plugin is straightforward: if a <module>
element is present,
the plugin declares the source directories using the --module-source-path
compiler option,
which implies the above-cited new directories.
Otherwise, the plugin declares the source directories with the --source-path
option.
The plugin does nothing more.
If that new output directory is not desired, the Maven 3 way to do a modular project is still supported:
setup the Maven project has if it was non-modular (without <module>
element),
but keep adding a module-info.java
file in the sources.
However, migration to a fully modular project is recommended when applicable.
The maven compiler plugin automatically adds --patch-module
options for the <source>
elements having a test
scope.
It also adds --add-reads
options for dependencies having the test
or test-only
scope.
In many cases, this is sufficient and there is no need for to configure the plugin with additional compiler arguments.
By default, each dependency of a modular project is placed on the module-path if the dependency contains
a module-info.class
file or an Automatic-Module-Name
entry in the META-INF/MANIFEST.MF
file,
otherwise the dependency is placed on the class-path.
This heuristic rule can be overridden by specifying explicitly the type of the dependency.
For example, the following snippet forces the placement of a dependency on the module-path
even if that dependency has no module-info or manifest entry:
<dependencies>
<dependency>
<groupId>my.dependency</groupId>
<artifactId>foo</artifactId>
<type>modular-jar</type>
<version>1.0</version>
</dependency>
</dependencies>
If the version is managed by a <dependencyManagement>
section,
the managed dependency must contains the same <type>
element,
otherwise Maven will consider that this is not the same artifact.
For the reverse operation
(force placement on the class-path instead of the module-path even if the dependency is modular),
replace modular-jar
type by classpath-jar
.
If the compilation failed, the Maven compiler plugin writes the options that it used in a javac.args
or
javac-test.args
file (for compilation of main code and test code respectively) in the target
directory.
The compilation can be executed on the command-line as below.
Note that the paths to source files inside javac.args
are relative to the project directory.
Therefore, that command must be executed in the same directory as the pom.xml
file,
or in a directory containing a copy or a branch of that project.
javac @target/javac.args
By default, javac.args
is not written if the compilation succeed.
Users can force the plugin to write that file in the following ways:
- Execute
mvn
with the--verbose
option (more exactly: enable logging messages at the debug level). - Or provide the
<verbose>true</verbose>
option in the plugin configuration.