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


Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow