Java Language Créer un Jar multi-release à l'aide de l'outil JAR


Exemple

La commande jar peut être utilisée pour créer un Jar multi-versions contenant deux versions de la même classe compilées pour Java 8 et Java 9, mais avec un avertissement indiquant que les classes sont identiques:

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

L'option --release 9 indique à jar d'inclure tout ce qui suit (le package demo dans le sampleproject-9 ) dans une entrée versionnée du MRJAR, à savoir sous root/META-INF/versions/9 . Le résultat est le contenu suivant:

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

Créons maintenant une classe appelée Main qui SampleClass l'URL de SampleClass et l'ajoute à la version Java 9:

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);
    }
}

Si nous compilons cette classe et réexécutons la commande jar, nous obtenons une erreur:

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

La raison en est que l'outil jar empêche l'ajout de classes publiques aux entrées versionnées si elles ne sont pas également ajoutées aux entrées de base. Ceci est fait pour que MRJAR expose la même API publique pour les différentes versions de Java. Notez qu'au moment de l'exécution, cette règle n'est pas requise. Il ne peut être appliqué que par des outils tels que le jar . Dans ce cas particulier, le but de Main est d'exécuter un exemple de code, nous pouvons donc simplement ajouter une copie dans l'entrée de base. Si la classe faisait partie d'une nouvelle implémentation dont nous avons seulement besoin pour Java 9, elle pourrait être rendue non publique.

Pour ajouter Main à l'entrée root, nous devons d'abord le compiler pour cibler une version antérieure à Java 9. Cela peut être fait en utilisant la nouvelle option --release de 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

L'exécution de la classe Main montre que SampleClass est chargé depuis le répertoire versionné:

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