Maven with Java [duplicate] - java

This question already has an answer here:
Compiling Scala Using Maven
(1 answer)
Closed 2 years ago.
When we compile a Maven project, by default the Java compiler is used to compile the source files. But nowhere this is mentioned in the POM file to instruct the compile phase to use the Java compiler.
Can someone please help how Maven automatically uses the Java compiler?
Suppose that we use maven to build a Scala programs, then how we can we instruct Maven to use the Scala compiler instead of Java?

Can someone please help how maven automatically uses java compiler?
Maven is designed to build and manage dependencies for a Java project. By default it will use a Java compiler.
If mvn is used to compile Scala programs instead of Java, then you'll need to use a maven plugin to compile Scala code. This plugin will work. Then code that is in src/main/scala will get compiled with the Scala compiler used by the plugin.

By default Maven uses Java compiler included in the JDK. As stated here the default is the class javax.tools.JavaCompiler.
If you want to override parameters for the compiler you can include your own plugin section:
<build>
<plugins>
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
<showDeprecation>true</showDeprecation>
<showWarnings>true</showWarnings>
<compilerArgument>-Xlint:all</compilerArgument>
</configuration>
</plugin>
...
</plugins>
</build>
and set the version of the compiler in properties:
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
If you want to use Scala, there are instructions on how to do this. You'll still need a Java compiler available.

There is maven-compile plugin which is active by default when your pom packaging is jar:
https://maven.apache.org/plugins/maven-compiler-plugin/index.html
Usually you do not have to tweak it at all

Related

Method introduced in java 9 is compiled using compiler target java 8

I'm experiencing an odd behavior in maven as well as in eclipse itself.
Even though i configured my project to be compiled in Java 1.8, I can compile and run (eclipse) a piece of code that was introduced in Java 9
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
The code line in question:
LocalTime.ofInstant(cal.toInstant(), cal.getTimeZone().toZoneId());
I'm using Oracle's JDK 11 locally for compiling and running in eclipse without any errors. When i package it into a docker container using openjdk:8-jdk-alpine it will boot up, but throw the following Exception when I call the method:
java.lang.NoSuchMethodError: java.time.LocalTime.ofInstant(Ljava/time/Instant;Ljava/time/ZoneId;)Ljava/time/LocalTime
How can I avoid and identify these situations before they go to testing? Am I doing something wrong or is it a bug in the build system or in JDK11?
thanks in advance
The source option specifies that the source code must be compatible with Java 8, the target option that the classes should be compatible with Java 8. However, you will still compile with the Java 11 class library if you build with Java 11 and then you can get errors like the one you have.
There are two good solutions. One is to use the Maven toolchains plugin and build with Java 8. Then you can have multiple Java versions installed and Maven will use the configured one on a per-project basis.
The other is to use the new release and testRelease options. They will build with API classes from the given release. Just add <release>1.8</release>.
If you are using JDK 11, configure your maven pom.xml like that:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<version>2.5.3</version>
</plugin>
</plugins>
</build>

What's the difference between `spring-boot-maven-plugin` and `maven-compiler-plugin`?

I do not know the difference between spring-boot-maven-plugin and maven-compiler-plugin.
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
Is that mean Spring Boot Maven Plugin's feature include maven-compiler-plugin?
I just use Spring Boot Maven Plugin is ok, do not need add 2 plugins??
"Spring Boot Maven Plugin provides Spring Boot support in Maven, letting you package executable jar or war archives and run an application “in-place”."
"Maven Compiler Plugin is used to compile the sources of your project."
maven-compiler-plugin has two goals. Both are already bound to their proper phases within the Maven Lifecycle and are therefore, automatically executed during their respective phases.
compiler:compile is bound to the compile phase and is used to compile the main source files.
compiler:testCompile is bound to the test-compile phase and is used to compile the test source files.
To understand more about maven build lifecycle - http://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html#Lifecycle_Reference
maven-compiler-plugin usages -
To compile source code using -source and -target javac Options
To compile source code using a different JDK
To compile source code using Memory Allocation Enhancement
To Pass Compiler Arguments
Most commonly used to define source and target versions.
Sometimes you may want to compile a certain project to a different version than what you are currently using. The javac can accept such command using -source and -target. maven-compiler-plugin can also be configured to provide these options during compilation.
For example, if you want to use the Java 8 language features (-source 1.8) and also want the compiled classes to be compatible with JVM 1.8 (-target 1.8), you can either add the two following properties, which are the default property names for the plugin parameters:
<project>
[...]
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
[...]
</project>
or configure the plugin directly:
<project>
[...]
<build>
[...]
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
[...]
</build>
[...]
</project>
Technically we can use both spring-boot-maven-plugin and maven-compiler-plugin in combination if the requirement is to create an executable jar as well as make sure source and target code have a specific version (which is accomplished by including maven-compiler-plugin).
In my case, i didn't use in combination but when my java project is a spring boot app that needs to run as a micro-service etc then we need an executable jar as build output so used spring boot maven plugin (only) but my other java project that consists of spring beans or components and is going to be used as a spring enabled library in other external apps but not required to run on its own but had to make sure source and target versions are specified then normal "mvn package" generated jar should work. For that maven compiler plugin (only) should do the job.

Maven install issue with Java 1.8 version

I have written code which can compile on Java 1.8 (try block). It is compiled and running for me when I run it directly. While I am trying to build it using Maven in my local, I am facing an issue which is saying to use -source 7 or later. I tried all possible ways to use java 8 and all places I have specified 8 only but Maven is trying to compile using java 1.6 it seems.
Can any one you please help me where can I correct it to pick my maven to use java 1.8.
Thanks,
Venkat
Following should work too:
<properties>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
</properties>
You can specify that using the maven-compiler-plugin:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.0<</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
Just remember to use the newest version of the plugin.

Specifying Java version in maven - differences between properties and compiler plugin

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 this:
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 don't 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 between 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?
Use any of three ways: (1) Spring Boot feature, or use Maven compiler plugin with either (2) source & target or (3) with release.
Spring Boot
<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 :
1.8
Feel free to use it if you use Spring Boot.
maven-compiler-plugin with source & target
Using maven-compiler-plugin or maven.compiler.source/maven.compiler.target properties are equivalent.
That is indeed :
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
is equivalent to :
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
according to the Maven documentation of the compiler plugin
since the <source> and the <target> elements in the compiler configuration use the properties maven.compiler.source and maven.compiler.target if they are defined.
source
The -source argument for the Java compiler.
NOTE: Since 3.8.0 the default value has changed from 1.5 to 1.6. Since 3.9.0 the default value has changed from 1.6 to 1.7
Default value is: 1.7.
User property is: maven.compiler.source.
target
The -target argument for the Java compiler.
NOTE: Since 3.8.0 the default value has changed from 1.5 to 1.6. Since 3.9.0 the default value has changed from 1.6 to 1.7
Default value is: 1.6.
User property is: maven.compiler.target.
About the default values for source and target, note that
since the 3.8.0 of the maven compiler, the default values have changed from 1.5 to 1.6.
maven-compiler-plugin with release instead of source & target
The maven-compiler-plugin 3.6 and later versions provide a new way :
org.apache.maven.plugins
maven-compiler-plugin
3.8.0
9
You could also declare just :
<properties>
<maven.compiler.release>9</maven.compiler.release>
</properties>
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 conveys release : a new JVM standard option that we could pass from Java 9 :
Compiles against the public, supported and documented API for a
specific VM version.
This way provides a standard way to specify the same version for the source, the target and the bootstrap 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 the maven-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:
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
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 the bootstrap JVM option with as value the path of the rt.jar of the target version.
An important thing to consider is that the source and the target version in the Maven configuration should not be superior to the JDK version referenced by the JAVA_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 :
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
<compilerVersion>1.8</compilerVersion>
<fork>true</fork>
<executable>D:\jdk1.8\bin\javac</executable>
</configuration>
</plugin>
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 :
...
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>2.5</version>
<executions>
<execution>
<id>default-clean</id>
<phase>clean</phase>
<goals>
<goal>clean</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>2.6</version>
<executions>
<execution>
<id>default-testResources</id>
<phase>process-test-resources</phase>
<goals>
<goal>testResources</goal>
</goals>
</execution>
<execution>
<id>default-resources</id>
<phase>process-resources</phase>
<goals>
<goal>resources</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<executions>
<execution>
<id>default-compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>default-testCompile</id>
<phase>test-compile</phase>
<goals>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
</plugin>
...
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 solutions above worked for me straight away. So I followed these steps:
Add in pom.xml:
<properties>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
</properties>
Go to Project Properties > Java Build Path, then remove the JRE
System Library pointing to JRE1.5.
Force updated the project.
The below steps work for me like charm! so thought to share with everyone.
These are the lines i added in the pom.xml file to work with a basic project. I am using Java 12 (you can replace yours 11, 10, 1.8 etc).
<properties>
<maven.compiler.source>12</maven.compiler.source>
<maven.compiler.target>12</maven.compiler.target>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<release>12</release>
</configuration>
</plugin>
</plugins>
</build>
After changing the pom file please reload your project so that IDE can download/fetch the plugin to the project. (For IntelijIDEA: Right-click on pom.xml -> Go to maven -> Reload project).
please make sure to configure the desire version in your IDE as well.
if you are using IntelliJ idea maven build.
Consider the alternative:
<properties>
<javac.src.version>1.8</javac.src.version>
<javac.target.version>1.8</javac.target.version>
</properties>
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)
For NetBeans IDE, changing project properties - (Jersey Service) - Categories > Sources >
Selected 'Source/Binary Format' as 1.8.

Maven: compiling and testing on different source levels

I am currently working on a project which will run on an embedded device. The device runs a Java ME JRE (comparable to Java 1.4).
Because of this maven is configured to compile for source & target level 1.4.
Is it possible to run the maven test phase on a different source/target level? Because this way I could use Mockito for unit-testing.
The source and target versions can be set separately for the compile and testCompile goals of the maven compiler plugin. You can change the settings either by defining properties in your pom:
<properties>
<maven.compiler.source>1.4</maven.compiler.source>
<maven.compiler.target>1.4</maven.compiler.target>
<maven.compiler.testSource>1.5</maven.compiler.testSource>
<maven.compiler.testTarget>1.5</maven.compiler.testTarget>
</properties>
Or by explicit configuration of the compiler plugin:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.4</version>
<configuration>
<source>1.4</source>
<target>1.4</target>
<testSource>1.5</testSource>
<testTarget>1.5</testTarget>
</configuration>
</plugin>

Categories

Resources