Easier Than It Looks

Sometimes difficult to solve problems are obvious in hindsight.

I’ve mentioned my need to build an MR JAR for Simplestub, and my dissatisfaction with the existing solutions. So I started playing around with Gunnar Morling’s approach, and realized that there were ways to improve it. That starting with discovering that:

  • The compiler plugin has a couple of obvious parameters, which are not documented: the source directories and the output directory,
  • The compiler plugin also has a way to select the toolchains-determined JDK, and is not restricted to using the configured one,
  • The surefire plugin has a way to select the JDK based on a path, and
  • The path to the JDK that is running Maven is available as a system property.

Combined, this led to the approach described here.

Normally, the goal is the following set of source-to-target mappings:

source directorytarget directory
 src/main/javatarget/classes
src/main/java9target/classes/META-INF/versions/9
src/main/java10target/classes/META-INF/versions/10

in order to create the MR JAR. But what if you want to run unit tests? We can change these mappings, so that each source tree is compiled, one at a time, into the same directory. Each subsequent compile replaces the corresponding classes, with the ones the JDK would pick up from the MR JAR, and you wind up with a single classes directory against which you can run your tests. Profiles based on the JDK version decide which compiles to activate. If you are building with Java 9, the Java 9 classes replace the corresponding 1.7/1.8 versions, but are not replaced by the Java 10 implementations, as they are not built. This can be done in Maven by using properties for the output directories, and letting profiles adjust them as needed.

Now that is a lot of configuration, which is bad; however, it is generic enough that it can be moved into a parent POM, and can be used by all projects that use the same parent POM. For many standalone projects, that means the one provided by OSS. That means that the only configuration needed is the specification of the parent POM.

The above behavior, suiting for running unit tests, is the default. To build a multi-release JAR, specify -Dmulti_release=true on the Maven command line. This will happen automatically when using the release plugin.

The result has now been released, and is being used in SimpleStub.