Maven and Java multi-version modules

Are you struggling with performance issues in your Spring, Jakarta EE, or Java EE application?

What if there were a tool that could automatically detect what caused performance issues in your JPA and Hibernate data access layer?

Wouldn’t it be awesome to have such a tool to watch your application and prevent performance issues during development, long before they affect production systems?

Well, 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 fixing performance issues in your production system on a Saturday night, you are better off using Hypersistence Optimizer to help you prevent those issues so that you can spend 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.

&lt;build&gt;
    &lt;plugins&gt;
        &lt;plugin&gt;
            &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
            &lt;artifactId&gt;maven-toolchains-plugin&lt;/artifactId&gt;
            &lt;version&gt;1.1&lt;/version&gt;
            &lt;executions&gt;
                &lt;execution&gt;
                    &lt;goals&gt;
                        &lt;goal&gt;toolchain&lt;/goal&gt;
                    &lt;/goals&gt;
                &lt;/execution&gt;
            &lt;/executions&gt;
            &lt;configuration&gt;
                &lt;toolchains&gt;
                    &lt;jdk&gt;
                        &lt;version&gt;${jdk.version}&lt;/version&gt;
                    &lt;/jdk&gt;
                &lt;/toolchains&gt;
            &lt;/configuration&gt;
        &lt;/plugin&gt;

<pre><code>    &amp;lt;plugin&amp;gt;
        &amp;lt;groupId&amp;gt;org.apache.maven.plugins&amp;lt;/groupId&amp;gt;
        &amp;lt;artifactId&amp;gt;maven-compiler-plugin&amp;lt;/artifactId&amp;gt;
        &amp;lt;version&amp;gt;${maven-compiler-plugin.version}&amp;lt;/version&amp;gt;
        &amp;lt;configuration&amp;gt;
            &amp;lt;source&amp;gt;${jdk.version}&amp;lt;/source&amp;gt;
            &amp;lt;target&amp;gt;${jdk.version}&amp;lt;/target&amp;gt;
            &amp;lt;showDeprecation&amp;gt;true&amp;lt;/showDeprecation&amp;gt;
            &amp;lt;showWarnings&amp;gt;true&amp;lt;/showWarnings&amp;gt;
        &amp;lt;/configuration&amp;gt;
    &amp;lt;/plugin&amp;gt;

    &amp;lt;plugin&amp;gt;
        &amp;lt;groupId&amp;gt;org.apache.maven.plugins&amp;lt;/groupId&amp;gt;
        &amp;lt;artifactId&amp;gt;maven-surefire-plugin&amp;lt;/artifactId&amp;gt;
        &amp;lt;version&amp;gt;${maven-surefire-plugin.version}&amp;lt;/version&amp;gt;
    &amp;lt;/plugin&amp;gt;
&amp;lt;/plugins&amp;gt;
</code></pre>

&lt;/build&gt;

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.

Transactions and Concurrency Control eBook

Leave a Reply

Your email address will not be published. Required fields are marked *

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