How to use different Java versions for main and test in Maven
Imagine having a tool that can automatically detect JPA and Hibernate performance issues. Wouldn’t that be just awesome?
Well, Hypersistence Optimizer is that tool! And it works with Spring Boot, Spring Framework, Jakarta EE, Java EE, Quarkus, or Play Framework.
So, enjoy spending your time on the things you love rather than fixing performance issues in your production system on a Saturday night!
Introduction
In this article, we are going to see how we can use different Java versions for the main and test folders in Maven so that you can run tests on a newer version of Java.
Why even use different Java versions in a Maven project
If you develop an end-user project, then, most likely, you need a single version of Java. However, things are way different for frameworks and libraries.
For instance, the Hypersistence Utils modules are built using the lowest-possible Java version required by the associated Hibernate version:
- The
hypersistence-utils-hibernate-60
module targets Hibernate 6; hence it needs to be compiled using Java 11 - The
hypersistence-utils-hibernate-55
andhypersistence-utils-hibernate-52
modules target the Hibernate versions 5.2 to 5.6, and these modules use Java 8 - The
hypersistence-utils-hibernate-5
module is built using Java 6, just like the associated Hibernate versions that are older than 5.1.
And that’s not all.
The hypersistence-utils-hibernate-60
provides the amazing HibernateRepository
that fixes the anti-patterns provided by the default Spring Data JpaRepository
, so it needs to be tested with Spring 6.
However, Spring 6 is built using Java 17, so tests need to use Java 17, not Java 11, as otherwise, the test classes would not even compile.
And this issue is not limited to the hypersistence-utils-hibernate-60
module. Because older JDBC Drivers no longer work with newer databases that are available now on Docker using Testcontainers, even the hypersistence-utils-hibernate-5
module need to be tested using Java 8 while they are built using Java 6.
That’s the beauty of working on an OSS library that targets a wide range of Hibernate versions.
Supporting multiple Java versions using Maven Toolchains
The first step is to set up Maven Toolchains, as I explained in this article.
Maven Toolchains allows you to have multiple versions of Java installed on your OS and configure the Maven project to pick a specific Java version.
For that, you need to add the maven-toolchains-plugin
to your pom.xml
file, like this:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-toolchains-plugin</artifactId> <version>${maven-toolchains-plugin.version}</version> <executions> <execution> <goals> <goal>toolchain</goal> </goals> </execution> </executions> <configuration> <toolchains> <jdk> <version>${jdk-test.version}</version> </jdk> </toolchains> </configuration> </plugin>
The jdk-test.version
references the Java version we are going to use for testing.
For more details about using Maven Toolchains, check out this article.
Using different Java versions for the main and test Maven folders for Hibernate 6
Now, for the hypersistence-utils-hibernate-60
module, we are going to use the following maven-compiler-plugin
properties to differentiate between the Java versions used to compile the classes in src/main/java
and src/test/java
folders:
<jdk.version>11</jdk.version> <jdk-test.version>17</jdk-test.version> <maven.compiler.release>${jdk.version}</maven.compiler.release> <maven.compiler.testRelease>${jdk-test.version}</maven.compiler.testRelease>
That’s it!
Java 11 is used to compile the classes in src/main/java
while the src/test/java
test classes are compiled and run using Java 17.
Using different Java versions for the main and test Maven folders for Hibernate 4
The hypersistence-utils-hibernate-5
module is built using Java 6, but tested using Java 8.
So, the maven-compiler-plugin
properties look like this for the older modules:
<jdk.version>6</jdk.version> <jdk-test.version>8</jdk-test.version> <maven.compiler.source>${jdk.version}</maven.compiler.source> <maven.compiler.target>${jdk.version}</maven.compiler.target> <maven.compiler.testSource>${jdk-test.version}</maven.compiler.testSource> <maven.compiler.testTarget>${jdk-test.version}</maven.compiler.testTarget>
Cool, right?
If you enjoyed this article, I bet you are going to love my Book and Video Courses as well.
Conclusion
I’ve been using Maven since 2008, and it’s amazing how easily you can customize it for all sorts of non-standard configuration options.
Using different Java versions for the main and test folders in Maven is actually very easy, thanks to Toolchains and the maven-compiler-plugin
configuration options.
