force maven to use different java version

2.5k views Asked by At

I have my existing project that uses Java 1.8 My JAVA_HOME is set to Java 1.8 As a result maven is using Java 1.8 , which is fine Now our project has decided to start using SonarQube 9.x which runs on Java 11 In addition to run any scan / analysis of our code - it needs Java 11 as well

So here is what I need to be doing :

#1 Compile code using default jdk ( 1.8 ) ( mvn clean install )

#2 Run sonar scan using jdk 11 ( mvn sonar:sonar )

To execute #2 need maven to use jdk 11 while to execute #1 need maven to use jdk 1.8.

After reading various questions on SO came across 'toolchain'

So added toolchains.xml into my 'm2' folder :

<?xml version="1.0" encoding="UTF-8"?>
<toolchains>
 <!-- JDK toolchains -->
 <toolchain>
  <type>jdk</type>
  <provides>
   <version>1.11</version>
   <vendor>sun</vendor>
  </provides>
  <configuration>
   <jdkHome>C:\construction\tools\jdk-11.0.12</jdkHome>
  </configuration>
</toolchain>
<toolchain>
 <type>jdk</type>
 <provides>
  <version>1.8</version>
  <vendor>sun</vendor>
 </provides>
 <configuration>
  <jdkHome>C:\Program Files\Java\jdk1.8.0_191</jdkHome>
 </configuration>
</toolchain>  

Added toolchain plugin in my projects pom.xml

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-toolchains-plugin</artifactId>
            <version>1.1</version>
            <executions>
                <execution>
                    <goals>
                      <goal>toolchain</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <toolchains>
                    <jdk>
                        <version>1.11</version>
                        <vendor>sun</vendor>
                    </jdk>
                </toolchains>
            </configuration>
        </plugin>

Now when I run maven clean install can see in logs that java 11 'seems' to be used :

[INFO] --- maven-toolchains-plugin:1.1:toolchain (default) @ TreeSurveyAPI ---

[INFO] Required toolchain: jdk [ vendor='sun' version='1.11' ] [INFO] Found matching toolchain for type jdk: JDK[C:\construction\tools\jdk-11.0.12]

[INFO] --- maven-compiler-plugin:3.7.0:compile (default-compile) @ TreeSurveyAPI --- [INFO] Toolchain in maven-compiler-plugin: JDK[C:\construction\tools\jdk-11.0.12] [INFO] Changes detected - recompiling the module! [INFO] Compiling 11 source files to C:\construction\xxx\XYZ-main\target\classes

So it 'seems' that maven along with toolchain is using Java 11 to compile the code . However after executing javap against compiled class file indicates Major version as 52 ( Java 8 )

javap -verbose Abc.class | findstr "major"

So here are my questions :

#1 in the above case since toolchain points to java 11 shouldnt the code be compiled with java 11 ? why is it using java 8 ?

#2 How can I conditionally use java 8 Vs java 11 ( compile and build using java 8 and run sonar task using java 11 ) ?

Thanks

2

There are 2 answers

7
Arthur Klezovich On

You can run your project on java 11 also. It will run java 8 code no problem for 99% of the cases. This is what I would do. Therefore, upgrading the projects java version seems to be the easiest solution.

If this does not work, check out this answer

Also, if you need to be able to quickly change JVM versions for various tasks and in various folders, you can use this tool

0
Markus Hoffrogge On

There are two main aspects to understand:

  1. The Maven toolchains plugin enables us to separate the JDK/JRE version being used for the projects building Maven plugin execution runtime from the JDK version being used to compile AND to run the surefire plugins running the JUnit tests.

  2. The Maven compile plugins configuration <target> (user property maven.compiler.target) JAVA version defines the code and class JAVA version the compiler will create - BUT this does NOT guarantee that your code will run 100% on that target versions actual JAVA runtime (s. below under the risk headline).

Both topics have to be well understood in terms of risks and pre-requisites.

The most common required scenario is like this:

Maven build execution requires JAVA version A
Target classes compiled require JAVA version B

In your questioned case you have to meet:

  1. Use JAVA 11 for Maven build execution to meet SonarQube plugin requirements
  2. Use JAVA 1.8 to compile and JUnit test your code

The correct configuration to meet this requirement is:

  1. Define your JAVA_HOME being used to run the Maven build process to the JDK 11 home
    => meets your question #2
  2. Configure your toolchains plugin to make use of the JDK 1.8 home
  3. Configure the maven-compiler-plugin
...
  <configuration>
    <source>1.8</source>
    <target>1.8</target>
  </configuration>
... 

=> 2. and 3. meet your question #1

Potential risk if not configuring a separate toolchain

If you run the build with JDK 11 without having defined a separate JDK 8 by the toolchain, then your compiled classes will be compliant to JDK 8, if you configure the maven-compiler-plugin target to 1.8,

__ BUT __

  • You compile your code vs. the JDK 11 API (JDK's rt.jar) - and by this your code would even get compiled if it is using JAVA 11 API's that are NOT available on JAVA 8 or did have been modified vs. JAVA 8.
    => Your project goes risk to fail late on JAVA 8 runtime with unexpected and suspicious class not found or method missing exceptions.
  • JUnit tests may endup different as if they would have been run within a JAVA 8 runtime.