Maven and Java multi-version modules
Are you struggling with performance issues in your Spring, Jakarta EE, or Java EE application?
Imagine having a tool that could automatically detect performance issues in your JPA and Hibernate data access layer long before pushing a problematic change into production!
With the widespread adoption of AI agents generating code in a heartbeat, having such a tool that can watch your back and prevent performance issues during development, long before they affect production systems, can save your company a lot of money and make you a hero!
Hypersistence Optimizer is that tool, and it works with Spring Boot, Spring Framework, Jakarta EE, Java EE, Quarkus, Micronaut, or Play Framework.
So, rather than allowing performance issues to annoy your customers, you are better off preventing those issues using Hypersistence Optimizer and enjoying spending your time on the things that you love!
Introduction
In this article, you are going to learn how to configure Maven to choose a specific Java version when the OS has multiple Java versions installed.
For instance, FlexyPool uses Java 8 for all modules, except for the flexy-pool-core-java9 module that needs to be built using Java 9.
Using Maven Toolchains to define multiple Java versions
To use multiple Java versions, you need to use Maven Toolchains, which require you to create a toolchains.xml file in your ~/.m2 Maven folder, containing all Java versions installed on your machine:
<toolchains>
<toolchain>
<type>jdk</type>
<provides>
<id>Java17</id>
<version>17</version>
</provides>
<configuration>
<jdkHome>${env.JAVA_HOME_17}</jdkHome>
</configuration>
</toolchain>
<toolchain>
<type>jdk</type>
<provides>
<id>Java9</id>
<version>9</version>
</provides>
<configuration>
<jdkHome>${env.JAVA_HOME_9}</jdkHome>
</configuration>
</toolchain>
<toolchain>
<type>jdk</type>
<provides>
<id>Java8</id>
<version>8</version>
</provides>
<configuration>
<jdkHome>${env.JAVA_HOME_8}</jdkHome>
</configuration>
</toolchain>
<toolchain>
<type>jdk</type>
<provides>
<id>Java7</id>
<version>7</version>
</provides>
<configuration>
<jdkHome>${env.JAVA_HOME_7}</jdkHome>
</configuration>
</toolchain>
<toolchain>
<type>jdk</type>
<provides>
<id>Java6</id>
<version>6</version>
</provides>
<configuration>
<jdkHome>${env.JAVA_HOME_6}</jdkHome>
</configuration>
</toolchain>
</toolchains>
The JAVA_HOME_17, JAVA_HOME_9, JAVA_HOME_8, JAVA_HOME_7, JAVA_HOME_6 environment variables are configured so that they reference the path where the associated Java version is installed.
The parent pom.xml Maven configuration defining a default Java version
The parent pom.xml Maven configuration file defines the global Java version settings
<properties>
<jdk.version>8</jdk.version>
...
</properties>
Now, we need to instruct both the compiler and the test plugins to use the configured java version.
<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>${jdk.version}</version>
</jdk>
</toolchains>
</configuration>
</plugin>
<pre><code> &lt;plugin&gt;
&lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
&lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;
&lt;version&gt;${maven-compiler-plugin.version}&lt;/version&gt;
&lt;configuration&gt;
&lt;source&gt;${jdk.version}&lt;/source&gt;
&lt;target&gt;${jdk.version}&lt;/target&gt;
&lt;showDeprecation&gt;true&lt;/showDeprecation&gt;
&lt;showWarnings&gt;true&lt;/showWarnings&gt;
&lt;/configuration&gt;
&lt;/plugin&gt;
&lt;plugin&gt;
&lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
&lt;artifactId&gt;maven-surefire-plugin&lt;/artifactId&gt;
&lt;version&gt;${maven-surefire-plugin.version}&lt;/version&gt;
&lt;/plugin&gt;
&lt;/plugins&gt;
</code></pre>
</build>
The child Maven module pom.xml using a non-default Java version
The flexy-pool-core-java9 child Maven module that requires a different Java version only needs to override the default jdk.version Maven property:
<properties>
<jdk.version>9</jdk.version>
</properties>
And that’s it, we can now build each module using its own minimum viable Java version.
Conclusion
Using multiple Java versions is a common requirement when developing open-source frameworks that target a wide range of project environments. Thanks to the Maven Toolchains plugin, this task is very easy to address.

