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 Hibernate Types project modules are built using the lowest-possible Java version required by the associated Hibernate version:

  • The hibernate-types-60 module targets Hibernate 6 hence it needs to be compiled using Java 11
  • The hibernate-types-55 and hibernate-types-52 modules target the Hibernate versions 5.2 to 5.6, and these modules use Java 8
  • The hibernate-types-5, hibernate-types-43, and hibernate-types-4 modules are built using Java 6 just like the associated Hibernate versions that are older than 5.1.

And that’s not all.

The hibernate-types-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 hibernate-types-60 module. Because older JDBC Drivers no longer work with newer databases that are available now on Docker using Testcontainers, even the hibernate-types-5, hibernate-types-43, and hibernate-types-4 modules 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 hibernate-types-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 hibernate-types-5, hibernate-types-43, and hibernate-types-4 are 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.

Transactions and Concurrency Control eBook

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.