MG3>agreed please see below

From: Russell Gold <>
Sent: Friday, April 13, 2018 9:07 AM
To: Maven Users List
Subject: Re: Building and unit-testing MR Jars, easily

> On Apr 13, 2018, at 8:34 AM, Martin Gainty <> wrote:
> MG2>quick comment below
> MG2>from your website:
> MG2>
> "JEP-238< 
> <>>. A problem, though, is that more than two 
> years after this feature was announced, the tools still don’t actually 
> provide much in the way of support. My next post will explore the current 
> options"
JEP 238: Multi-Release JAR Files<>
Extend the JAR file format to allow multiple, Java-release-specific versions of 
class files to coexist in a single archive. Support multi-release modular JAR 
files for goals 1 to 3. Preserve performance: The performance of tools and 
components that use multi-release JAR files must not be ...

> MG2>
> MG2>can you suggest current tools options which support JEP-238?

I haven’t found any as yet. That’s why the numerous Maven workarounds. I think 
it is a chicken-and-egg problem. Until maven (and possibly Gradle) support the 
feature with an agreed-upon directory layout, it is unlikely that the IDEs will 
support it. And until the IDEs support it naturally, it becomes painful for 
people to create projects with them.

Jetbrains has blogged about their workaround 
 but that solution bypasses the build tools.

MG3>agree with pretty much everything there except:

MG3>when creating MR jar for jar'ing JDK 9 classes one would need -release 
MG3>jar NameOfJar.jar --release 9   <Y/N>?

MG3>when JDK9 jar command creates jar with manifest one would need specify 
-manifest MANIFEST.MF
MG3>jar -c NameOfJar.jar --manifest MANIFEST.MF * --release 9 <Y/N>?

MG3>the objective is to incorporate MANIFEST.MF which includes Multi-Release 
MG3>MANIFEST.MF would be included (which includes Multi-Release: true directive)

Multi-Release: true

MG3>we can implement compile via different profiles for compile-java8 and for 

           <!-- define similar execution for java 9 -->

MG3>the remaining detail would be to handle creation of META-INF/versions/9

MG3>then populating META-INF/versions/9 with JDK-9 compiled classes with 

  1.  <build>
  2.      <plugins>
  3.        <plugin>
  4.          <artifactId>maven-resources-plugin</artifactId>
  5.          <version>3.0.2</version>
  6.          <executions>
  7.            <execution>
  8.              <id>copy-resources-jdk9</id>
  9.              <!-- here the phase you need -->
  10.             <phase>validate</phase>
  11.             <goals>
  12.               <goal>copy-resources</goal>
  13.             </goals>
  14.             <configuration>
  16.               <resources>
  17.                 <resource>
  18.                   <directory>${basedir}/target/classes</directory>
  19.                   <filtering>true</filtering>
  20.                 </resource>
  21.               </resources>
  22.             </configuration>
  23.           </execution>
  24.         </executions>
  25.       </plugin>
  26.     </plugins>

MG3>likely that we will need to separate JDK1.8 and JDK1.9 to separate child 
pom.xml with:

parent pom.xml
  JDK18 folder (compile, copy and jar all JDK1.8 classes)
  JDK19 folder (compile, copy and jar all JDK1.9 classes using 
META-INF/versions/9 folder)


> ________________________________
> From: Russell Gold < <>>
> Sent: Thursday, April 12, 2018 2:43 PM
> To: Maven Users List
> Subject: Re: Building and unit-testing MR Jars, easily
>> On Apr 12, 2018, at 1:58 PM, Martin Gainty <> wrote:
>>>       <plugin>
>>>           <groupId>org.apache.maven.plugins</groupId>
>>>           <artifactId>maven-antrun-plugin</artifactId>
>>>           <executions>
>>>               <execution>
>>>                   <id>compile-java9</id>
>>>                   <phase>compile</phase>
>>>                   <configuration>
>>>                       <tasks>
>>>                           <mkdir dir="${}" />
>>>                           <javac srcdir="${java9.sourceDirectory}" 
>>> destdir="${}"
>>>                               classpath="${}" 
>>> includeantruntime="false" />
>>>                       </tasks>
>>>                   </configuration>
>>>                   <goals>
>>>                       <goal>run</goal>
>>>                   </goals>
>>>               </execution>
>>>           </executions>
>>>       </plugin>
>> MG>looks similar to maven-compiler-plugin with srcdir / destdir /classpath 
>> attrs..a bit more intuitive than maven-compiler-plugin
>> <artifactId>maven-compiler-plugin</artifactId>
>> <executions>
>> <execution>
>> <id>default-compile</id>
>> <configuration>
>>  <compilerArgs>
>>   <srcdir>"${java9.sourceDirectory}</srcdir>
>>   <destdir>"${}"</destdir>
>>   <classpath>${}</classpath>
>>  </compilerArgs>
> Part of that, I suspect, is ant’s use of attributes, which Maven generally 
> shuns. If the Maven pom were recast to use attributes, and to infer groups, 
> it could look something like:
>        <plugin groupid="org.apache.maven.plugins" 
> artifactid="maven-compiler-plugin" version="3.7.9">
>            <execution id="java9" phase="compile" goals="compile">
>                <configuration srcdir="${java9.sourceDirectory}" 
> destdir="${}" 
> classpath="${}"/>
>            </execution>
>        </plugin>
> but that wasn’t the direction the designers took.
>> ....
>> MG>
>> If you are actively working on adding MR capabilities to the compiler 
>> plugin, is there something I can do to help?
>> MG>initial evaluation would include what are advantages/disadvantages of MR
> To a large extent, it is necessitated by the more rapid JDK changes which 
> commenced with Jigsaw’s introduction in Java 9. Until then, while APIs were 
> deprecated, they didn’t tend to go away a lot, and developers got used to 
> using both deprecated APIs and internal ones. With Jigsaw, the JDK team 
> started not only hiding the internal APIs, but also speeding up the pace of 
> removal of features.
> I’ve given an example at 
> <>
> The basic problem is that some code that works in, say, Java 8, is no longer 
> supported in Java 11, and the replacement isn’t available until Java 9. That 
> means that you often cannot write one implementation that works for all JDK 
> versions that mean to support. Nor can you use a conditional in your code, 
> since the alternative implementations don’t even necessarily compile in the 
> same JDK (the replacement feature just mentioned doesn’t compile in Java 8, 
> and if you compile it for release 9, you cannot run it with Java 8. That 
> means that you have to use some tricky reflection - or MR Jars.
> I don’t know how common they will be. I maintainer nearly two dozen modules 
> across several projects, and only two of them have needed this so far. It 
> will really depend on how many more APIs get removed.
> A related use case, of course, is that sometimes there are serious advantages 
> in performance or resilience in using newer APIs, and MR Jars allow you to do 
> that without dropping support for older JDK versions.
> The main disadvantage, then, has been tool support. Maven doesn’t support 
> them natively (nor does Gradle, and I cannot even imagine a clean way to add 
> it there). Neither do any of the IDEs, which are almost certainly waiting on 
> build tools to take the lead in defining the code layout. The workarounds 
> have generally been partial solutions, counting on Maven to add support, but 
> it has been painful to use them. That’s why I created this approach, which is 
> mostly only painful when it comes to updating the parent POM.
> MG2>from your website:
> MG2>
> "JEP-238< 
> <>>. A problem, though, is that more than two 
> years after this feature was announced, the tools still don’t actually 
> provide much in the way of support. My next post will explore the current 
> options"
> MG2>
> MG2>can you suggest current tools options which support JEP-238?
> I should also note a disappointment with the JDK. Java 9 has a -release 
> switch, which is intended to replace -source and -target, but it doesn’t 
> quite match its intended use. If you run with -release 1.8, for example, you 
> cannot compile against the Unsafe class, which is my approach needs to use 
> toolchains. I expect that not everyone will have to do that, but it is a 
> clear pain point for projects like Mockito, ByteBuddy, SimpleStub, and a 
> number of others, which have been designed to do tricky code generation or 
> field access.
>>> On Apr 12, 2018, at 10:44 AM, Martin Gainty <> wrote:
>>> MG>one-off request with ant only approach to compiling MR jars
>>> ________________________________
>>> From: Russell Gold < 
>>> <>>
>>> Sent: Thursday, April 12, 2018 7:00 AM
>>> To: Robert Scholte
>>> Cc: Maven Users List
>>> Subject: Re: Building and unit-testing MR Jars, easily
>>>> On Apr 11, 2018, at 12:36 PM, Robert Scholte <> wrote:
>>>> On Wed, 11 Apr 2018 14:25:37 +0200, Russell Gold <> 
>>>> wrote:
>>>>> Hi Robert,
>>>>> I used properties because I need to trigger multiple profiles, depending 
>>>>> on whether we’re building the MR jar, and what JDK versions will be 
>>>>> needed - and I can use them to turn profiles off, which I could not do by 
>>>>> simply turning on a profile, as far as I know.
>>>> Yes, you can turn off profiles by prefixing it with !,e.g. -P!someprofile
>>> That’s good to know. In this case, there are two profiles which are 
>>> mutually exclusive. he multi-jar profile is activated when building an MR 
>>> jar, and the test-toolchains-bypass profiles is run when NOT building an MR 
>>> jar. I can do that with a single property. Is there a way to do that with a 
>>> single -P switch?
>>>>> I didn’t consider test jars, and am not familiar with how they are used. 
>>>>> Can you tell me more about them?
>>> How to create a jar containing test classes - Apache 
>>> Maven<
>>> <>>
>>> <>
>>> When you want to create a jar containing test-classes, you would probably 
>>> want to reuse those classes. There are two ways to solve this: Create an 
>>> attached jar with the test-classes from the current project and loose its 
>>> transitive test-scoped dependencies. Create a separate project with the 
>>> test ...
>>>> The issue was exposed with 
>>>> <> 
>>>> < 
>>>> <>>
>>> That should be easy to fix. I just need to limit the configuration to the 
>>> jar goal.
>>>>> At present, the parent POM supports only up to JDK11, and doesn’t handle 
>>>>> well cases where the main jar would be, say, JDK11. To some extent I see 
>>>>> this as a stop gap. It is not clear to me if a better approach would 
>>>>> start with an extension, or if there is any real long-term alternative to 
>>>>> putting the changes into the compiler, surefire, and jar plugins.
>>>>> Unit testing is the default behavior. Toolchains are used to compile each 
>>>>> version of the code with the correct compiler (since the source/target 
>>>>> and release flags don’t quite duplicate doing so), and then surefire runs 
>>>>> the tests with the jdk used to run Maven itself. Clearly, the 
>>>>> documentation is lacking. But yes, you do need to run the build multiple 
>>>>> times, since the code actually run can vary. If you are using Travis CI, 
>>>>> that means that you need to configure the toolchains explicitly. I have 
>>>>> not yet figured out how to do this with both oracle and open jdk options, 
>>>>> since the toolchains seem to require you to make that choice in the pom, 
>>>>> not just the JDK.
>>>> Not sure if I understand. But you can add as much entries to both 
>>>> <provides> in the toolchain.xml and inside the <jdk> element of the 
>>>> maven-toolchains-plugin configuration. Only version has a special meaning.
>>>> e.g. you can add <vendor>oracle</vendor> or <vendor>openjdk</vendor> to 
>>>> the toolchain.xml and the plugin configuration. By adding it to the plugin 
>>>> you say that at least version+vendor must be specified in the 
>>>> toolchain.xml with matching values. The <provides> might have more 
>>>> elements, but these are ignored.
>>> Thank you. There are some things I will experiment with, to see if I can 
>>> handle more cases.
>>> BTW, I have posted a list of the other MR solutions that I know of at 
>>> <> 
>>> < 
>>> <>>,
>>> MG>With regards to "Use of the ant-plugin to compile the JDK 9 code"
>>> MG>do you have a build.xml target we can use to backport features and 
>>> functions of this target into maven-compiler-plugin
>>> MG>possible trigger could be maven-compiler-plugin configuration of
>>> MG><source>1.9</source> and/or
>>> MG><target>1.9</target>
>>> along with my comments. As far as I know, mine is the only one that allows 
>>> unit testing of the code for each JDK version.
>>>> thanks,
>>>> Robert
>>>>> Thanks,
>>>>> Russ
>>>>>> On Apr 4, 2018, at 3:11 PM, Robert Scholte <> wrote:
>>>>>> Hi Russell, interesting approach.
>>>>>> The difference between library developers and application developers 
>>>>>> becomes more and more clear and this concept might be useful for library 
>>>>>> builders.
>>>>>> We should probably have a separate page for all the available solutions 
>>>>>> and menion the pro's and cons.
>>>>>> Just a few remarks: why are you using property enabled profiles instead 
>>>>>> of -Pmulti-release?
>>>>>> Be aware that you can also create test-jars, which should NOT have the 
>>>>>> multi-release flag set in the MANIFEST.
>>>>>> It will mean that you should provide a new version every every half 
>>>>>> year, unless you already add all those versions right now ;)
>>>>>> What I'm missing is a clear explanation how unit testing works. IIUC you 
>>>>>> build the whole project with a specific JDK version and that's how the 
>>>>>> matching unittests are executed. So you should run the build X times, 
>>>>>> once for every multirelease version.
>>>>>> thanks,
>>>>>> Robert
>>>>>> On Tue, 03 Apr 2018 21:42:39 +0200, Russell Gold 
>>>>>> <> wrote:
>>>>>>> I have just developed a new and easier way for building MR Jars 
>>>>>>> <>, while waiting for 
>>>>>>> the capability to be built into Maven.
>>>>>>> This approach is not only simple to set up (just use the designated 
>>>>>>> parent POM, if you can), it lets you unit test for any supported JDK. 
>>>>>>> For example:
>>>>>>> jdk7 && mvn -Dmulti_release clean test
>>>>>>> jdk10 && mvn -Dmulti_release clean test
>>>>>>> where jdk7 and jdk10 set the appropriate versions for maven to use. 
>>>>>>> Either will run against the appropriate additional code.
>>>>>>> To build an MR JAR you set a property on the command line
>>>>>>> mvn -Dmulti_release clean install
>>>>>>> which happens automatically when doing a release.
>>>>>>> I have also explained how it works at Easier Than It Looks 
>>>>>>> <>
>>>>> ---------------------------------------------------------------------
>>>>> To unsubscribe, e-mail:
>>>>> For additional commands, e-mail:

Reply via email to