Currently Existing Solutions With Maven 3

The current solution to create a multi release jar is not very convenient. An examples https://github.com/khmarbaise/mrelease or others (please add them if you have some?) The issue with those setups is that you have to go a bit tricky way to resolve that.

  • XXX

Current Impediments

  • Currently IDE's do not support having different JDK version based code in a single module/project; for example one directory with JDK 11 source and another with JDK 17 source code. The current state is that the support of such setup is a non usual setup which is more or less only required for library producer. 
  • The convenience of the solutions is not good.. 

Maven 4 Solution

Model Enhancements 

The POM model extended as version 4.1.0 in Maven 4.0.0-rc-3 has in the example below:

<build>
  <sources>
    <source>
      <release>17</release>
      <!-- The default directory is src/main/java -->
    </source>
    <source>
      <release>21</release>
      <directory>src/main/java-21</directory>
    </source>
  </sources>
</build>

When used with the maven-compiler-plugin version 4.0.0-beta-3 (released in October 15th, 2025), the plugin automatically performs the following steps, in that order:

  1. Compile src/main/java with the --release 17 compiler option and with target/classes as the destination directory.
  2. Compile src/main/java-21 with the --release 21 compiler option, with target/classes added to the classpath, and with target/classes/META-INF/versions/21 as the destination directory.
  3. Repeat step 2 for all other versions, from oldest to newest. The output directory of the previous version is added to the classpath at each step, with newest versions appearing first in the classpath (i.e., newest code have precedence over oldest code).

Consequences

Some questions in a previous version of the wiki page are answered by the maven-compiler-plugin 4.0.0-beta-3 implementation:

  • How should the above setup being triggered that when the user wants to build a multi release jar?
    • Answer: when there is at least two <release> elements with different value.
  • Do we need a particular maven plugin for that purpose? 
    • Answer: no. Instead, it is up to each plugin to be muli-version aware if this is relevant to them.

Open questions

How to specify a particular JDK version for the test? In current version, the behavior is as below:

  • Tests that put the target/classes directory on the class-path would execute only the base version, because this is how class-path work.
    • A workaround could be to put explicitly all target/classes/versions/* directories on the classpath from newest to oldest, as done by the compiler plugin. It could be done automatically with a Surefire configuration option which would specify the highest version to put on the classpath.
  • Tests that put the JAR file on the class-path would execute the highest version compatible with the Java runtime.

And also things like code coverage (running surefire for different versions? or all together?) and maybe other tools like static code analyzers?  Another part is: What about generators who generate code? How to separate them? Currently we have things like target/generated-sources/ ... that would require a change as well to generate targeted to a particular JDK version? (What about those plugins? How to configure them? for each version different?)

TODO (May 2023): This rest of this section may need to be reviewed for taking in account what exist in Maven 4.0.0-rc-3 and maven-compiler-plugin 4.0.0-beta-3.

The following needs to be summarized (TBD):
Furthermore if you have several JDK versions for example; you have one non-version dependendat maybe just JDK 8 based and version dependant parts for version 11,17,21,22 so you need for each version separated test/main code + resources and also you might require different deps for different jdk versions... (as already suggested).
But on the other hand we could think about a packaging type "multi-release" which automatically defines a default directory layout (as suggested src/main/java/.. base version.. and "src/main/java11/ for JDK 11 etc. also the resources like src/main/resources11/.. and for src/test/java11 etc. the same way)...
Those diretories could automatically trigger the appropriate --release option (The default is defined by the usual configuration of maven-compiler-plugin --release also associated with src/main/java;) so if you create a directory src/main/java21 it will be compiled via --release 21...That would just remove the requirement to define all those things in your pom file by hand..(and might be more following the idea convention over configuration)..
The same way for the the src/test/java21 ...A not trivial thing is about things like code coverage how to handle things in that setup? Also how to run tests only limited to a JDK 21 code area which might be require code from the default area (src/main/java). And how could it be handled to have different deps in different code areas (JDK 21 requires for testing a different library?) and in case of code coverage we require the agents (or even other tools?) ? and let later combine them into a single one...Those thoughs are bringing me at the moment to go into the multi module setup which solves already a lot of those issues...(current setup not convenient of course)... and also keep the flexibility ...

Packaging Type - multirelease

TODO (May 2023): This section may be obsolete. The code in Maven 4.0.0-rc-3 and maven-compiler-plugin 4.0.0-beta-3 do not need a particular packing type for multi-release support.

The assumption is to have a multi module build setup where one module is responsible for producing the final multi release jar which is based on the new packaging type multirelease.  This type binds the maven-compiler-plugin to the life cycle which is required to compile the module-info.java file which is located in the usual src/main/java/ location.

We create a maven-multi-release-plugin which handles the final packaging into the resulting jar file. This combines the compiles module-info.class file and also from the other modules the code and of course only picks up the right files (it's bit like maven-shade-plugin with filters?) The dependencies given are put into the resulting multi release jar ... (maybe those needed to be identified by a particular scope? Not sure about that). (Needs more thourougly thinking/trying about it). Based on the usage of plugin supplemental requirements like defining OSGi enhancements could be done easier?

The issues like creating code coverage or having different dependencies in the different version based modules can be done with the existing mechanisms and also code generators can easily be configured in the appropriate module without even chaning existing plugins... (Maven 4 itself is a different story?) 

Questions

  • ??

Consequences

  • The triggering for building a multi release jar is done by the packaging type
  • The work is done mainly by a new plugin?
  • No labels