Example of Maven project to build JEP-238 JAR with preprocessing
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
src
.gitignore
LICENSE
README.md
pom.xml

README.md

Since JDK 9 we have real risk that the new versions of JDK will be less and less compatible each other for small changes in API and it will hurt developers more and more (because Oracle is planning to make new releases of JDK much often). As a some solution for the problem, the Java community provided JEP-238 "Multi-Release JAR Files" which has been implemented since JDK 9. It allows combine versions of classes for different JDKs in single JAR file and JVM will choose apropriate versions of classes in runtime. Classes are saved in special sub-folders inside META-INF so that it works transparently but we still have the main problem with duplication of business logic in many copies of classes during development phase.

Hervé Boutemy made just nice example how to bring support of JEP-238 in a maven project, his approach is to create multi-module project and split JDK dependent classes between modules and then collect compiled classes from each module into single multi-release JAR, but how to be with cases when we need only small changes in classes? To keep separate class for each JDK is too expensive and it is very easy to forget make some important changes in all versions, it breaks DRY principle.

Many years ago I already run into similar problem with incompatibility of "standard" API implemented by different vendors, it was with J2ME platform, I resolved the problem through development of special tool Java Comment Preprocessor (which at present can work with Maven as a plugin). The Preprocessor keeps its directives inside commentaries and allows to inject small changes into classes without full duplication of code. (for instance team of Postgres-JDBC driver uses this preprocessor).

I have written the example to show how to organize maven project which build a multi-version JAR file which supports JEP-238 but without duplication of classes because it makes preprocessing of set of the same classes but with different parameters under different JDKs (for JDK 8 and JDK 9 in the example). On start the example was a multi-module one but then I decided to improve it and made optimization to make single-module project, so that now it is just a maven single module project generating single JAR as artifact. I have writte comments inside pom.xml files and hope they are no so complex for understanding.

NB! The Project uses maven-invoker-plugin which sensetive to Maven home folder and may not work with bundled versions of Maven in some IDEs, in the case you should use external non-bundled version of Maven!

The Project uses the Maven toolchains plugin and toolchains.xml file should be created in .m2 folder to provide desired paths to JDK 8 and JDK 9

<?xml version="1.0" encoding="UTF8"?>
<toolchains>
  <toolchain>
     <type>jdk</type>
     <provides>
         <version>8</version>
         <vendor>oracle</vendor>
         <id>default</id>
     </provides>
     <configuration>
        <jdkHome>/home/path/to/jdk1.8</jdkHome>
     </configuration>
  </toolchain>
  <toolchain>
    <type>jdk</type>
    <provides>    
	<version>9</version>
        <vendor>oracle</vendor>
	<id>default</id>
    </provides>
    <configuration>
	<jdkHome>/home/path/to/jdk1.9</jdkHome>
    </configuration>
  </toolchain>
</toolchains>

The Project has predefined default build goals so that you can just use mvn to build it. As theresult there will be jep-238-jcp-example-1.0.0-SNAPSHOT.jar in the target folder, it is a multi-version JAR file which can be executed under JDK 8 and JDK 9 and JVM will be using different classes in each case. The JAR has defined main class name in its manifest so that it can be started in command line with easy command
java -jar jep-238-jcp-example-1.0.0-SNAPSHOT.jar

After start under JDK 8 it should show something like the text

Hello Good Old Java!
Class uses new JDK9 API is not in scope

And after start under JDK 9 and newer, it should show something like that

Hello New Java 9+181 !
Class uses new JDK9 API is in scope