Вопрос или проблема
Вот мои шаги для воспроизведения проблемы:
com/example/Library.kt
package com.example
class Library {
fun getValue(): Int {
return 123
}
}
MyCode.kt
import com.example.Library
fun main() {
println("Hello World")
println(Library().getValue())
}
Я могу скомпилировать оба файла с помощью команды ниже, без каких-либо ошибок:
kotlinc com/example/Library.kt -d Library.jar
kotlinc -cp Library.jar MyCode.kt -d MyCode.jar
Структура файлов после компиляции:
$ tree
.
├── Library.jar
├── MyCode.jar
├── MyCode.kt
└── com
└── example
└── Library.kt
Однако я не могу выполнить MyCode.jar
$ java -cp Library.jar -jar MyCode.jar
Hello world
Exception in thread "main" java.lang.NoClassDefFoundError: com/example/Library
at MyCodeKt.main(MyCode.kt:5)
at MyCodeKt.main(MyCode.kt)
Caused by: java.lang.ClassNotFoundException: com.example.Library
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
at java.base/jdk/internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:526)
... 2 more
Также не работает использование kotlin вместо java:
$ kotlin -cp Library.jar MyCode.jar
Hello world
Exception in thread "main" java.lang.NoClassDefFoundError: com/example/Library
at MyCodeKt.main(MyCode.kt:5)
at MyCodeKt.main(MyCode.kt)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
at org.jetbrains.kotlin.runner.AbstractRunner.run(runners.kt:70)
at org.jetbrains.kotlin.runner.Main.run(Main.kt:194)
at org.jetbrains.kotlin.runner.Main.main(Main.kt:204)
Caused by: java.lang.ClassNotFoundException: com.example.Library
at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:445)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:593)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:526)
... 7 more
Может кто-нибудь сказать мне, в чем проблема?
(Maven / Gradle не вариант, я пытаюсь создать быстрый инструмент для компиляции кодов пользователей)
Причина ошибки указана в команде kotlin -help
:
app.jar Выполняет указанный JAR файл так, как это делает 'java -jar'
Поэтому нам нужно посмотреть, что делает java -jar
. Для этого смотрите документацию Java:
-jar jarfile
Выполняет программу, инкапсулированную в JAR файле. Аргумент jarfile – это имя JAR файла с манифестом, который содержит строку в формате Main-Class:classname, определяющую класс с общедоступным статическим методом void main(String[] args), который служит точкой входа для вашего приложения. Когда вы используете -jar, указанный JAR файл является источником всех пользовательских классов, и другие настройки пути к классам игнорируются. Если вы используете JAR файлы, то смотрите jar.
Соответствующее предложение выделено жирным шрифтом. Таким образом, kotlin MyCode.jar
игнорирует аргумент -cp
. Решение состоит в том, чтобы либо запустить его так, как вы указали в своем ответе, либо поместить файл Library.class
внутри вашего MyCode.jar
.
Благодарю @liaifat85 за то, что дал мне большой намек, который решал мою проблему.
Вместо использования опции -jar вы можете попробовать опцию -cp для обоих JAR файлов и явно указать основной класс.
java -cp Library.jar:MyCode.jar MyCodeKt
Ответ или решение
При выполнении программного кода на Kotlin, скомпилированного с использованием внешних библиотек и упакованного в файлы JAR, вы можете столкнуться с исключением ClassNotFoundException
. Эта проблема часто возникает, когда неправильно настроен класс-путь или не учитывается специфика выполнения JAR-файлов в Java.
Описание проблемы
Как видно из вашего примера, вы создали два файла: Library.kt
и MyCode.kt
. Файл Library.kt
содержит класс Library
, который вы используете в вашем основном коде MyCode.kt
. Вы успешно скомпилировали оба файла в JAR-файлы с помощью следующих команд:
kotlinc com/example/Library.kt -d Library.jar
kotlinc -cp Library.jar MyCode.kt -d MyCode.jar
Однако при попытке выполнения MyCode.jar
с использованием следующей команды возникает исключение ClassNotFoundException
:
java -cp Library.jar -jar MyCode.jar
Причина ошибки
Ошибка связана с тем, как работает ключ -jar
в команде Java. Когда вы используете -jar
, процесс выполнения игнорирует все дополнительные параметры -cp
(classpath) и использует только JAR-файл, указанный после -jar
. Это означает, что JAR-файл MyCode.jar
воспринимается как отдельная единица, и Java ищет все классы именно в этом файле, без учета других JAR-файлов, которые вы указали в параметре -cp
.
Как указано в официальной документации Java, использование -jar
требует, чтобы в манифесте JAR-файла содержалась строка Main-Class
, указывающая на класс с методом public static void main(String[] args)
. В данном случае, поскольку Library.class
не находится в MyCode.jar
, JVM не может загрузить класс com.example.Library
, что и приводит к ClassNotFoundException
.
Решение проблемы
Для решения проблемы у вас есть несколько вариантов:
-
Только использование Classpath:
Запустите программу без ключа-jar
, но явно укажите класс-путь для обоих JAR-файлов и основной класс:java -cp Library.jar:MyCode.jar MyCodeKt
Эта команда позволяет JVM видеть оба JAR-файла, и она успешно найдет класс
com.example.Library
, вызываяmain
метод вашего приложения. -
Создание манифеста:
Если вы все же хотите использовать ключ-jar
, вам нужно создать манифест дляMyCode.jar
, в который включить указание класса сmain
методом и обеспечить наличие в этом JAR файле всех необходимых классов. Для этого необходимо:-
Объединить классы из обеих JAR-файлов в один JAR-файл, используя команду
jar
:jar -cvfm MyCode.jar MANIFEST.MF -C output-directory/ .
-
В вашем
MANIFEST.MF
укажите:Main-Class: MyCodeKt
Однако, для небольших и краткосрочных проектов, как ваш, первый вариант с использованием ключа
-cp
наиболее удобен и прост. -
Заключение
Проблема ClassNotFoundException
при работе с JAR-файлами в Kotlin устраняется пониманием принципа работы с -jar
и -cp
. Убедитесь, что все необходимые классы доступны для JVM, и используйте правильные параметры запуска. Если вы будете следовать предложенным шагам, выполнение ваших Kotlin-программ должно проходить без ошибок.
Помните, что корректная организация вашего кода и понимание работы классов и пакетов являются важными аспектами программирования на Kotlin.