Java Language
Файлы с несколькими релизами JAR
Поиск…
Вступление
Одной из функций, представленной в Java 9, является многорежимный Jar (MRJAR), который позволяет связывать код с таргетингом на несколько выпусков Java в одном файле Jar. Функция указана в JEP 238 .
Пример содержимого файла Jar для нескольких выпусков
Установив Multi-Release: true
в файле MANIFEST.MF, Jar-файл становится многорежимным Jar и временем выполнения Java (при условии, что он поддерживает формат MRJAR) выбирает соответствующие версии классов в зависимости от текущей основной версии ,
Структура такой банки состоит в следующем:
jar root
- A.class
- B.class
- C.class
- D.class
- META-INF
- versions
- 9
- A.class
- B.class
- 10
- A.class
- В JDK <9 в среде выполнения Java видны только классы в корневой записи.
- На JDK 9 классы A и B будут загружены из
root/META-INF/versions/9
каталогаroot/META-INF/versions/9
, а C и D будут загружены из базовой записи. - На JDK 10 класс A будет загружен из каталога
root/META-INF/versions/10
.
Создание многодисковой банки с использованием инструмента банки
Команда jar
может использоваться для создания многоэкранного Jar, содержащего две версии одного и того же класса, скомпилированные как для Java 8, так и для Java 9, хотя и с предупреждением о том, что классы идентичны:
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
Параметр --release 9
указывает jar
включить все, что следует ( demo
пакет внутри sampleproject-9
) внутри root/META-INF/versions/9
с версией в MRJAR, а именно под root/META-INF/versions/9
. Результатом является следующее содержание:
jar root
- demo
- SampleClass.class
- META-INF
- versions
- 9
- demo
- SampleClass.class
Давайте теперь создадим класс Main, который печатает URL-адрес SampleClass
и добавляет его для версии 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);
}
}
Если мы скомпилируем этот класс и запустим команду jar, мы получим сообщение об ошибке:
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
Причина в том, что инструмент jar
предотвращает добавление публичных классов к версиям, если они не добавлены в базовые записи. Это делается для того, чтобы MRJAR предоставлял один и тот же публичный API для разных версий Java. Обратите внимание, что во время выполнения это правило не требуется. Он может применяться только такими инструментами, как jar
. В этом конкретном случае целью Main
является запуск образца кода, поэтому мы можем просто добавить копию в базовую запись. Если класс был частью более новой реализации, которая нам нужна только для Java 9, она может быть сделана непубличной.
Чтобы добавить Main
в корневую запись, нам сначала нужно скомпилировать ее для таргетинга на версию до 9 Java. Это можно сделать с помощью новой опции --release
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
Запуск основного класса показывает, что SampleClass загружается из каталога версий:
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 загруженного класса внутри многоэкранного Jar
Учитывая следующий многорежимный Jar:
jar root
- demo
- SampleClass.class
- META-INF
- versions
- 9
- demo
- SampleClass.class
Следующий класс печатает URL-адрес 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);
}
}
Если класс скомпилирован и добавлен в версию для версии Java 9 в MRJAR, ее запуск приведет к:
C:\Users\manouti>java --class-path MR.jar demo.Main
jar:file:/C:/Users/manouti/MR.jar!/META-INF/versions/9/demo/SampleClass.class