У меня есть простой привет мир, который я пытаюсь встроить в модульный jar-файл, чтобы протестировать запуск jlink. Я не могу ни запустить файл jar, ни создать для него образ с помощью jlink.
Я работаю в Windows и использую Java 21.
Вот Java-файлы в проекте.
$ find src/main/java -name '*\.java'
src/main/java/com/foo/bar/demoapp/App.java
src/main/java/module-info.java
package com.foo.bar.demoapp;
public class App
{
public static void main( String[] args )
{
System.out.println("hello hello");
}
}
module demoapp {
exports com.foo.bar.demoapp;
}
Я использую Maven 3.9.6, и мой файл pom довольно прост. Там указано maven.compiler.(source|target)=21
. Он устанавливает версию плагина компилятора 3.13.0. Он устанавливает для плагина jar версию 3.1.2 и указывает класс App как mainClass.
<configuration>
<archive>
<manifest>
<mainClass>com.foo.bar.demoapp.App</mainClass>
</manifest>
</archive>
</configuration>
Я проверил, что файл jar содержит ожидаемое содержимое.
$ unzip -l jars/demo-app-1.0-SNAPSHOT.jar
Archive: jars/demo-app-1.0-SNAPSHOT.jar
Length Date Time Name
--------- ---------- ----- ----
116 2024-04-08 12:30 META-INF/MANIFEST.MF
552 2024-04-08 12:30 com/foo/bar/demoapp/App.class
5160 2024-04-08 12:09 META-INF/maven/com.foo.bar/demo-app/pom.xml
64 2024-04-08 12:30 META-INF/maven/com.foo.bar/demo-app/pom.properties
283 2024-04-08 12:30 module-info.class
Я использовал javap
, чтобы убедиться, что класс информации о модуле отображает основной класс как требуется.
$ javap -verbose --module demoapp --module-path jars module-info
Classfile jar:file:///C:/Users/wrobert1/dev/foo/demo-app/jars/demo-app-1.0-SNAPSHOT.jar!/module-info.class
Last modified Apr 8, 2024; size 283 bytes
SHA-256 checksum 004814b6bbe32c09ecba1fe2a02289d5e4b33a14426856ca6598e1c256405443
Compiled from "module-info.java"
module [email protected]
minor version: 0
major version: 65
flags: (0x8000) ACC_MODULE
this_class: #1 // "module-info"
super_class: #0
interfaces: 0, fields: 0, methods: 0, attributes: 4
... constant pool elided ...
SourceFile: "module-info.java"
Module:
#6,0 // demoapp
#8 // 1.0-SNAPSHOT
1 // requires
#9,8000 // "java.base" ACC_MANDATED
#11 // 21.0.1
1 // exports
#12,0 // com/foo/bar/demoapp
0 // opens
0 // uses
0 // provides
ModuleMainClass: #16 // com.foo.bar.demoapp.App
ModulePackages:
#12 // com.foo.bar.demoapp
Я также использовал javap
, чтобы убедиться, что App.class имеет основную функцию.
$ javap --module demoapp --module-path jars com.foo.bar.demoapp.App
Compiled from "App.java"
public class com.foo.bar.demoapp.App {
public com.foo.bar.demoapp.App();
public static void main(java.lang.String[]);
}
Учитывая все это, когда я пытаюсь запустить файл jar, я получаю исключение ClassNotFoundException.
$ java --module-path jars com.foo.bar.demoapp.App
Error: Could not find or load main class com.foo.bar.demoapp.App
Caused by: java.lang.ClassNotFoundException: com.foo.bar.demoapp.App
И jlink
не работает, вероятно, по той же причине.
$ jlink --module-path jars --output linked --add-modules=java.base --launcher startmeup=demoapp/com.foo.bar.demoapp.App
Error: java.lang.IllegalArgumentException: demoapp does not have main class: com.dhl.raf.demoapp.App
Я уже довольно долго ищу, в чем может быть проблема, но безуспешно. Я не уверен, что я сделал здесь не так.
При выполнении основного класса с помощью java
один из способов решить эту проблему — указать, какие модули должны быть добавлены из пути к модулю для разрешения.
java --module-path jars --add-modules demoapp com.foo.bar.demoapp.App
Это также будет работать и в случае jlink
с чем-то вроде:
jlink --module-path jars --output linked --add-modules=java.base,demoapp --launcher startmeup=demoapp/com.foo.bar.demoapp.App
Альтернативой вашему подходу к использованию javap
может быть указание модуля вместе с mainClass
, например:
java --module-path jars --module demoapp/com.foo.bar.demoapp.App
Дополнительную информацию об этом можно получить с помощью самой командной строки java -help
.
Насчет jlink
, именно это я имел в виду под последней строкой первого раздела ответа. Позвольте мне отредактировать, чтобы сделать это явным.
Этот ответ попадает в точку для запуска Java, но это немного расплывчатый jlink WRT, который кажется немного неудобным. Для работы jlink необходимо также добавить модуль приложения, но нельзя указать путь к классу приложения в опциях --launcher. то есть
jlink --module-path jars --output linked --launcher startmeup=demoapp --add-modules=java.base,demoapp
работает.