Java Language
File JAR multi-release
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