Java Language
Archivos JAR Multi-Release
Buscar..
Introducción
Una de las características introducidas en Java 9 es el Jar de lanzamiento múltiple (MRJAR), que permite agrupar código dirigido a múltiples lanzamientos de Java dentro del mismo archivo Jar. La característica se especifica en JEP 238 .
Ejemplo de contenido de un archivo Jar multi-release.
Al establecer Multi-Release: true
en el archivo MANIFEST.MF, el archivo Jar se convierte en un Jar multi-release y el tiempo de ejecución de Java (siempre que sea compatible con el formato MRJAR) seleccionará las versiones apropiadas de las clases dependiendo de la versión principal actual .
La estructura de dicho Jar es la siguiente:
jar root
- A.class
- B.class
- C.class
- D.class
- META-INF
- versions
- 9
- A.class
- B.class
- 10
- A.class
- En JDKs <9, solo las clases en la entrada raíz son visibles para el tiempo de ejecución de Java.
- En un JDK 9, las clases A y B se cargarán desde el directorio
root/META-INF/versions/9
, mientras que C y D se cargarán desde la entrada base. - En un JDK 10, la clase A se cargaría desde el directorio
root/META-INF/versions/10
.
Creando un Jar multi-release usando la herramienta jar
El comando jar
se puede usar para crear un Jar de varias versiones que contiene dos versiones de la misma clase compilada para Java 8 y Java 9, aunque con una advertencia que indica que las clases son idénticas:
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
La opción --release 9
le dice a jar
que incluya todo lo que sigue (el paquete de demo
dentro del directorio sampleproject-9
) dentro de una entrada versionada en MRJAR, es decir, bajo root/META-INF/versions/9
. El resultado son los siguientes contenidos:
jar root
- demo
- SampleClass.class
- META-INF
- versions
- 9
- demo
- SampleClass.class
Ahora creamos una clase llamada Main que imprime la URL de SampleClass
y la agregamos para la versión 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 compilamos esta clase y volvemos a ejecutar el comando jar, obtenemos un 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
La razón es que la herramienta jar
impide agregar clases públicas a las entradas versionadas si no se agregan a las entradas base también. Esto se hace para que MRJAR exponga la misma API pública para las diferentes versiones de Java. Tenga en cuenta que en tiempo de ejecución, esta regla no es necesaria. Solo se puede aplicar con herramientas como el jar
. En este caso particular, el propósito de Main
es ejecutar código de ejemplo, por lo que simplemente podemos agregar una copia en la entrada base. Si la clase formara parte de una implementación más nueva que solo necesitamos para Java 9, se podría hacer no pública.
Para agregar Main
a la entrada raíz, primero debemos compilarlo para apuntar a una versión anterior a Java 9. Esto se puede hacer usando la nueva opción --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
La ejecución de la clase Main muestra que SampleClass se carga desde el directorio versionado:
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 de una clase cargada dentro de un Jar multi-release
Teniendo en cuenta el siguiente Jar multi-lanzamiento:
jar root
- demo
- SampleClass.class
- META-INF
- versions
- 9
- demo
- SampleClass.class
La siguiente clase imprime la URL de 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);
}
}
Si la clase se compila y se agrega en la entrada versionada para Java 9 en MRJAR, ejecutarla resultaría en:
C:\Users\manouti>java --class-path MR.jar demo.Main
jar:file:/C:/Users/manouti/MR.jar!/META-INF/versions/9/demo/SampleClass.class