Файл манифеста содержится внутри архива JAR по пути “META-INF/MANIFEST.MF”. Он содержит информацию, которая позволяет указывать версию, производителя, цифровую подпись, дополнительные пути поиска классов и многое другое.
Пример файла “MANIFEST.MF”:
1 2 3 |
Manifest-Version: 1.0 Ant-Version: Apache Ant 1.8.1 Created-By: 1.6.0_26-b03 (Sun Microsystems Inc.) |
Как видите, файл состоит из ключей и их значений, разделённый символом «:». В нашем случае указывается версия спецификации манифеста 1.0, и что jar был создал 1.6.0_26-b03 (Sun Microsystems Inc.).
Пока эта информация не очень полезна. Но файл манифеста может содержать входную точку программы, например:
1 |
Main-Class: ru.urvanov.javaexamples.springjavamailsenderimpl.App |
Здесь мы указали, что класс App в пакете ru.urvanov.javaexamples.springjavamailsenderimpl содержит статический метод main, который и должен запускаться при запуске Jar-файла командой:
1 |
java -jar MyJarFile.jar |
Также в файле манифеста бывают различные секции. Секции обычно отделяются друг от друга пустой строкой и содержат название секции (пакета Java), для которого указываются отдельные атрибуты. Примерно так:
1 2 3 4 5 6 7 |
Name: java/util/ Specification-Title: Java Utility Classes Specification-Version: 1.2 Specification-Vendor: Example Tech, Inc. Implementation-Title: java.util Implementation-Version: build57 Implementation-Vendor: Example Tech, Inc. |
Файл манифеста должен быть в кодировке UTF-8 и может использовать переводы строк CR+LF, LF или просто CR.
Последняя строка в файле манифеста обязательно должна заканчиваться переводом строки!
Из самого кода на Java мы можем вручную считывать и обрабатывать файлы манифеста, если это необходимо. Для этого используется класс java.util.jar.Manifest. Напишем небольшой пример его использования. Считывать будем следующий файл манифеста:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
Manifest-Version: 1.0 Automatic-Module-Name: org.json Bnd-LastModified: 1534236178661 Build-Jdk: 10.0.2 Built-By: Benjamin Gehrels Bundle-License: http://json.org/license.html Bundle-ManifestVersion: 2 Bundle-Name: JSON in Java Bundle-SymbolicName: json Bundle-Version: 20180813.0.0 Created-By: Apache Maven Bundle Plugin Export-Package: org.json;version="20180813.0.0" Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.6))" Tool: Bnd-3.0.0.201509101326 |
Код программы, считывающей этот файл:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.jar.Attributes; import java.util.jar.Manifest; /** * https://urvanov.ru */ public class ManifestReader { public static void main(String[] args) throws IOException { Manifest manifest = new Manifest(); // Не забудьте положить файл манифеста по указанному пути! try (InputStream inputStream = new FileInputStream("C:\\tmp\\MANIFEST.MF")) { manifest.read(inputStream); } Attributes attributes = manifest.getMainAttributes(); System.out.println("Built-By: " + attributes.getValue("Built-By")); System.out.println("Bundle-Name: " + attributes.getValue("Bundle-Name")); System.out.println("=========="); System.out.println("All entries:"); attributes.forEach((key, value) -> { System.out.println(key + ": " + value); } ); } } |
В результате после запуска в консоли получим следующее:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
Built-By: Benjamin Gehrels Bundle-Name: JSON in Java ========== All entries: Automatic-Module-Name: org.json Bundle-License: http://json.org/license.html Bundle-SymbolicName: json Built-By: Benjamin Gehrels Bnd-LastModified: 1534236178661 Bundle-ManifestVersion: 2 Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.6))" Tool: Bnd-3.0.0.201509101326 Manifest-Version: 1.0 Export-Package: org.json;version="20180813.0.0" Bundle-Name: JSON in Java Bundle-Version: 20180813.0.0 Build-Jdk: 10.0.2 Created-By: Apache Maven Bundle Plugin |
Если мы собираем JAR-файл мавеном, то мы используем maven-jar-plugin, который позволяет указывать любые записи для файла манифеста:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
<build> <plugins> ... <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <configuration> <archive> <manifest> <!-- указываем класс с методом main --> <mainClass>ru.urvanov.javaexamples.mypackage.MyApp</mainClass> <!-- Указываем дополнительный каталог, который нужно включить в classpath --> <addClasspath>true</addClasspath> <classpathPrefix>data/lib/</classpathPrefix> </manifest> <manifestEntries> <!- Эти записи добавятся в MANIFEST.MF- --> <My-Super-Description>Just my super description</My-Super-Description> <Some-Key>Some-Value</Some-Key> </manifestEntries> </archive> </configuration> </plugin> ... </plugins> </build> |
В секции manifest мы указываем стандартные свойства, которые попадут в файл манифеста, а в manifestEntries мы можем прописать абсолютно любые свойства, какие хотим.