I'm not very experienced with maven and while experimenting with multi-module project I started wondering how can I specify java version for all my child modules in parent maven pom. Until today I was using just:
<properties>
<java.version>1.8</java.version>
</properties>
but when researching I found that you can also specify java version in maven compiler plugin, like that:
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
And then wrap this into plugin management tag to enable child poms usage of this. So the first question is what are the differences beetwen setting java version in properties and in maven compiler plugin?
I couldn't find clear answer but in process of researching I found that you can also specify java version in this way:
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
which suggest that compiler plugin is there even if I dont explicit declare it. Running mvn package outputs with
maven-compiler-plugin:3.1:compile (default-compile) @ testproj ---
and some other plugins that I didn't declare. So are those plugins default, hidden part of maven pom? Are there any differences beetwen setting source/target in properties and in maven plugin configuration element?
Some other questions are - which way should be used (and when if they are not equal)? Which one is best for multi-module project and what happens if java version specified in pom is different than version pointed in JAVA_HOME?
How to specify the JDK version?
1)
<java.version>
is not referenced in the Maven documentation.It is a Spring Boot specificity.
It allows to set the source and the target java version with the same version such as this one to specify java 1.8 for both :
Feel free to use it if you use Spring Boot.
2) Using
maven-compiler-plugin
ormaven.compiler.source
/maven.compiler.target
properties to specify thesource
and thetarget
are equivalent.and
are equivalent according to the Maven documentation of the compiler plugin since the
<source>
and the<target>
elements in the compiler configuration use the propertiesmaven.compiler.source
andmaven.compiler.target
if they are defined.About the default values for
source
andtarget
, note that since the3.8.0
of the maven compiler, the default values have changed from1.5
to1.6
.3) The maven-compiler-plugin
3.6
and later versions provide a new way :You could also declare just :
But at this time it will not work as the
maven-compiler-plugin
default version you use doesn't rely on a recent enough version.The Maven
release
argument conveysrelease
: a new JVM standard option that we could pass from Java 9 :This way provides a standard way to specify the same version for the
source
, thetarget
and thebootstrap
JVM options.Note that specifying the
bootstrap
is a good practice for cross compilations and it will not hurt if you don't make cross compilations either.Which is the best way to specify the JDK version?
The first way (
<java.version>
) is allowed only if you use Spring Boot.For Java 8 and below :
About the two other ways : valuing the
maven.compiler.source
/maven.compiler.target
properties or using themaven-compiler-plugin
, you can use one or the other. It changes nothing in the facts since finally the two solutions rely on the same properties and the same mechanism : the maven core compiler plugin.Well, if you don't need to specify other properties or behavior than Java versions in the compiler plugin, using this way makes more sense as this is more concise:
From Java 9 :
The
release
argument (third point) is a way to strongly consider if you want to use the same version for the source and the target.What happens if the version differs between the JDK in JAVA_HOME and which one specified in the pom.xml?
It is not a problem if the JDK referenced by the
JAVA_HOME
is compatible with the version specified in the pom but to ensure a better cross-compilation compatibility think about adding thebootstrap
JVM option with as value the path of thert.jar
of thetarget
version.An important thing to consider is that the
source
and thetarget
version in the Maven configuration should not be superior to the JDK version referenced by theJAVA_HOME
.A older version of the JDK cannot compile with a more recent version since it doesn't know its specification.
To get information about the source, target and release supported versions according to the used JDK, please refer to java compilation : source, target and release supported versions.
How handle the case of JDK referenced by the JAVA_HOME is not compatible with the java target and/or source versions specified in the pom?
For example, if your
JAVA_HOME
refers to a JDK 1.7 and you specify a JDK 1.8 as source and target in the compiler configuration of your pom.xml, it will be a problem because as explained, the JDK 1.7 doesn't know how to compile with.From its point of view, it is an unknown JDK version since it was released after it.
In this case, you should configure the Maven compiler plugin to specify the JDK in this way :
You could have more details in examples with maven compiler plugin.
It is not asked but cases where that may be more complicated is when you specify source but not target. It may use a different version in target according to the source version. Rules are particular : you can read about them in the Cross-Compilation Options part.
Why the compiler plugin is traced in the output at the execution of the Maven
package
goal even if you don't specify it in the pom.xml?To compile your code and more generally to perform all tasks required for a maven goal, Maven needs tools. So, it uses core Maven plugins (you recognize a core Maven plugin by its
groupId
:org.apache.maven.plugins
) to do the required tasks : compiler plugin for compiling classes, test plugin for executing tests, and so for... So, even if you don't declare these plugins, they are bound to the execution of the Maven lifecycle.At the root dir of your Maven project, you can run the command :
mvn help:effective-pom
to get the final pom effectively used. You could see among other information, attached plugins by Maven (specified or not in your pom.xml), with the used version, their configuration and the executed goals for each phase of the lifecycle.In the output of the
mvn help:effective-pom
command, you could see the declaration of these core plugins in the<build><plugins>
element, for example :You can have more information about it in the introduction of the Maven lifeycle in the Maven documentation.
Nevertheless, you can declare these plugins when you want to configure them with other values as default values (for example, you did it when you declared the maven-compiler plugin in your pom.xml to adjust the JDK version to use) or when you want to add some plugin executions not used by default in the Maven lifecycle.
None of the above solutions worked for me straight away. So I did the followings:-
Added
<properties> <maven.compiler.target>1.8</maven.compiler.target> <maven.compiler.source>1.8</maven.compiler.source> </properties>
in pom.xml
Went to the project Properties>Java Build Path, then removed the JRE System Library which was pointing to JRE1.5.
Force updated the project.
Consider the alternative:
It should be the same thing of
maven.compiler.source/maven.compiler.target
but the above solution works for me, otherwise the second one gets the parent specification (I have a matrioska of .pom)