Java: торжественное обращение с jar и атрибутами MANIFEST.MF
Java-приложения гораздо удобнее собирать в один jar-файл, нежели хранить сложную структуру нескольких тысяч файлов. Однако плюсы использования jar-файлов этим удобством не ограничиваются, иногда может возникнуть необходимость передавать параметры из манифеста.
Многие Java-приложения поставляются в виде одного или нескольких jar-файлов (Java ARchive), которые по сути являются обыкновенными zip-архивами. В них обычно, кроме байт-кода программы, размещаются дополнительные ресурсы и конфигурационные файлы.
Такой подход позволяет:
- подписывать содержимое jar-файла, повышая таким образом уровень безопасности;
- сокращать время загрузки апплетов за счет отсутствия необходимости открытия нового соединения для каждого файла;
- сокращать объем приложения;
- упростить процесс создания библиотеки;
- осуществлять контроль версий.
Полноценно работать с технологией JAR можно как с помощью утилиты jar, входящей в состав JDK (Java Development Kit), так и с использованием классов JAR API.
Первый способ распространен повсеместно, в то время как второй, зачастую незаслуженно, обделен вниманием и, как показывает практика, напрасно – во многих случаях это может существенно облегчить жизнь разработчика. Именно поэтому в данной статье будут описаны несколько способов применения JAR API для вызова произвольных методов из jar-файла, записи и чтения атрибутов манифеста. (Манифест – (устар.) торжественное письменное обращение верховной власти к народу в связи с важным политическим событием, торжественной датой и т. д. (Толковый словарь русского языка).
Прежде всего следует уделить некоторое внимание утилите jar (http://java.sun.com/javase/6/docs/technotes/tools/solaris/jar.html). Это консольное приложение, запускаемое с набором параметров.
Примеры вызова утилиты:
// Создание нового jar-файла
jar cf file.jar список_файлов
// Просмотр содержимого архива
// Извлечение содержимого из jar-файла
JAR File Specification (http://java.sun.com/javase/6/docs/technotes/guides/jar/jar.html), позволяет расположить в архиве file.jar только один манифест с дополнительной служебной информацией META-INF/MANIFEST.MF, представляющий собой текстовый файл в кодировке UTF-8. Если он не был задан при создании jar-файла, используется манифест, который по умолчанию содержит информацию о своей версии и JDK, в которой был создан конкретный jar-файл:
Created-By: 1.6.0 (Sun Microsystems Inc.)
Условно содержимое можно разделить на главную группу (содержит определенные стандартами атрибуты, некоторые из них приведены в таблице 1) и индивидуальную группу (состав которой определяется произвольно).
Таблица 1. Атрибуты главной группы манифеста
Номер версии файла-манифеста. Определяется спецификацией как регулярное выражение следующего вида: цифра+*
Версия и поставщик платформы Java, с помощью которой был создан манифест. Автоматически генерируется утилитой jar
Версия подписи jar-файла. Определяется так же, как и Manifest-Version
Относительные указатели ресурсов (URL) для всех используемых дополнительных классов и библиотек
Относительный путь к главному классу приложения, который должен содержать точку входа – метод main(String[] args). Значение атрибута не должно содержать расширение .class. Атрибут определяется для автономных настольных приложений, которые собраны в выполняемые jar-файлы, которые могут быть запущены виртуальной машиной Java напрямую командой: java -jar file.jar
Имена произвольных атрибутов могут содержать только цифры, строчные и заглавные буквы латинского алфавита и знак «_», а по длине существует ограничение – 70 символов. К значению атрибута никаких требований, кроме элементарной логики, не предъявляется.
Более подробно структуру и состав JAR и META-INF/MANIFEST.MF в рамках этого текста мы затрагивать не будем по той простой причине, что любой желающий может прочесть более подробно cпецификацию JAR.
Использование JAR API
В последней на текущий момент Java 1.6 к JAR API относятся классы пакета java.util.jar, а также классы java.net.JarURLConnection и java.net.URLClassLoader. Ограничимся рассмотрением наиболее используемых классов (см. таблицу 2).
Таблица 2. Наиболее используемые классы в JAR API
Полное название класса
Таблица соответствий между именем атрибута и его значением
Перечисление в виде констант всех имен атрибутов главной группы
Класс описывает элемент jar-файла, например, файл с расширением .class
Наследник класса java.util.zip.ZipFile с поддержкой манифеста. Используется для чтения содержимого jar-файла
Наследник класса java.util.zip.ZipInputStream с поддержкой манифеста. Используется для чтения содержимого jar-файла из любого входящего потока
Наследник класса java.util.zip.ZipOutputStream с поддержкой записи манифеста. Используется для записи содержимого jar-файла в любой исходящий поток
Класс используется для работы с манифестом и его атрибутами
Соединение с jar-файлом или его элементом с помощью указателя ресурсов вида: ar:<url_к_jar_файлу >!/, например: jar:http://www.site.org/folder/file.jar!/org/site/Clazz.class
Используется для загрузки классов и ресурсов из classpath (может определяться, к примеру, атрибутом манифеста Class-Path)
Запуск методов класса
Прежде всего рассмотрим пример, который будет запускать метод public static void main(String[] args) из произвольного класса в jar-файле. Предположим, что у нас есть некий файл file.jar, который содержит класс pkg.Main:
public class Main