Ricerca…


introduzione

Una delle funzionalità introdotte in Java 9 è il multi-release Jar (MRJAR) che consente di raggruppare il codice per il targeting di più versioni di Java all'interno dello stesso file Jar. La funzione è specificata in JEP 238 .

Esempio di contenuto di un file Jar multi-release

Impostando Multi-Release: true nel file MANIFEST.MF, il file Jar diventa un Jar multi-release e il runtime Java (purché supporti il ​​formato MRJAR) sceglierà le versioni appropriate delle classi a seconda della versione principale corrente .

La struttura di un simile Jar è la seguente:

jar root
  - A.class
  - B.class
  - C.class
  - D.class
  - META-INF
     - versions
        - 9
           - A.class
           - B.class
        - 10
           - A.class
  • Su JDK <9, solo le classi nella voce root sono visibili al runtime Java.
  • Su un JDK 9, le classi A e B verranno caricate dalla directory root/META-INF/versions/9 , mentre C e D verranno caricate dalla voce base.
  • Su un JDK 10, la classe A verrebbe caricata dalla directory root/META-INF/versions/10 .

Creare un vaso multi-release usando lo strumento jar

Il comando jar può essere utilizzato per creare un jar multi-release contenente due versioni della stessa classe compilate sia per Java 8 che per Java 9, anche se con un avvertimento che indica che le classi sono identiche:

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'opzione --release 9 dice a jar di includere tutto ciò che segue (il pacchetto demo all'interno della sampleproject-9 ) all'interno di una voce con versione nel MRJAR, cioè sotto root/META-INF/versions/9 . Il risultato è il seguente contenuto:

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

Cerchiamo ora di creare una classe chiamata Main che stampa l'URL di SampleClass e aggiungila per la versione 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);
    }
}

Se compiliamo questa classe e ri-eseguiamo il comando jar, otteniamo un errore:

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

Il motivo è che lo strumento jar impedisce l'aggiunta di classi pubbliche alle voci con versione se non vengono aggiunte anche alle voci di base. Questo viene fatto in modo che MRJAR esponga la stessa API pubblica per le diverse versioni di Java. Si noti che in fase di runtime, questa regola non è richiesta. Può essere applicato solo da strumenti come jar . In questo caso particolare, lo scopo di Main è di eseguire un codice di esempio, quindi possiamo semplicemente aggiungere una copia nella voce base. Se la classe fosse parte di un'implementazione più recente di cui abbiamo bisogno solo per Java 9, potrebbe essere resa non pubblica.

Per aggiungere Main alla voce root, dobbiamo prima compilarlo per targetizzare una versione pre-Java 9. Questo può essere fatto usando la nuova opzione --release di 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'esecuzione della classe Main mostra che SampleClass viene caricato dalla directory versioned:

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

URL di una classe caricata all'interno di un Jar multi-release

Dato il seguente Jar multi-release:

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

La seguente classe stampa l'URL della SampleClass :

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

Se la classe è compilata e aggiunta alla voce con versione per Java 9 in MRJAR, eseguirla risulterebbe in:

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


Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow