Creating a multi-release Jar using the jar tool

suggest change

The jar command can be used to create a multi-release Jar containing two versions of the same class compiled for both Java 8 and Java 9, albeit with a warning telling that the classes are identical:

C:\Users\manouti>jar --create --file MR.jar -C sampleproject-base demo --release 9 -C sampleproject-9 demo
Warning: entry META-INF/versions/9/demo/SampleClass.class contains a class that
is identical to an entry already in the jar

The --release 9 option tells jar to include everything that follows (the demo package inside the sampleproject-9 directory) inside a versioned entry in the MRJAR, namely under root/META-INF/versions/9. The result is the following contents:

jar root
  - demo
     - SampleClass.class
  - META-INF
     - versions
        - 9
           - demo
              - SampleClass.class

Let us now create a class called Main that prints the URL of the SampleClass, and add it for the Java 9 version:

package demo;

import java.net.URL;

public class Main {

    public static void main(String[] args) throws Exception {
        URL url = Main.class.getClassLoader().getResource("demo/SampleClass.class");
        System.out.println(url);
    }
}

If we compile this class and re-run the jar command, we get an error:

C:\Users\manouti>jar --create --file MR.jar -C sampleproject-base demo --release 9 -C sampleproject-9 demoentry: META-INF/versions/9/demo/Main.class, contains a new public class not found in base entries
Warning: entry META-INF/versions/9/demo/Main.java, multiple resources with same name
Warning: entry META-INF/versions/9/demo/SampleClass.class contains a class that
is identical to an entry already in the jar
invalid multi-release jar file MR.jar deleted

The reason is that the jar tool prevents adding public classes to versioned entries if they are not added to the base entries as well. This is done so that the MRJAR exposes the same public API for the different Java versions. Note that at runtime, this rule is not required. It may be only applied by tools like jar. In this particular case, the purpose of Main is to run sample code, so we can simply add a copy in the base entry. If the class were part of a newer implementation that we only need for Java 9, it could be made non-public.

To add Main to the root entry, we first need to compile it to target a pre-Java 9 release. This can be done using the new --release option of javac:

C:\Users\manouti\sampleproject-base\demo>javac --release 8 Main.java
C:\Users\manouti\sampleproject-base\demo>cd ../..
C:\Users\manouti>jar --create --file MR.jar -C sampleproject-base demo --release 9 -C sampleproject-9 demo

Running the Main class shows that the SampleClass gets loaded from the versioned directory:

C:\Users\manouti>java --class-path MR.jar demo.Main
jar:file:/C:/Users/manouti/MR.jar!/META-INF/versions/9/demo/SampleClass.class

Feedback about page:

Feedback:
Optional: your email if you want me to get back to you:


Multi-release JAR files:
* Creating a multi-release Jar using the jar tool

Table Of Contents
8 Arrays
10 Maps
11 Strings
25 JAXB
29 Enums
32 Audio
41 Scanner
63 Logging
75 Lists
78 Sets
89 JAX-WS
96 XJC
98 Process
106 Modules
114 Applets
122 JNDI
139 JavaBean
141 Literals
144 Packages
150 JMX
153 JShell
156 Multi-release JAR files
159 Sockets
167 Enum Map
175 Hashtable
177 SortedMap