Gradle - нет основного атрибута манифеста

92

Я как бы схожу с ума от этой ошибки, которую я получаю при запуске файла JAR, созданного с помощью Gradle. Ошибка гласит: «Нет основного атрибута манифеста в RxJavaDemo.jar». Я пытался манипулировать свойством манифеста, но мне кажется, что я забыл добавить к нему зависимости или что-то еще. Что именно я делаю не так?

apply plugin: 'java'
apply plugin: 'application'

mainClassName = 'demo.MainDashboard'

dependencies {
    compile files ("H:/Processes/Development/libraries/hikari-cp/HikariCP-2.4.1.jar")
    compile files ("H:/Processes/Development/libraries/controls-fx/controlsfx.jar")
    compile files ("H:/Processes/Development/libraries/database_connections/sqlite-jdbc-3.8.6.jar")
    compile files ("H:/Processes/Development/libraries/guava/guava-18.0.jar")
    compile files ("H:/Processes/Development/libraries/rxjava/rxjava-1.0.12.jar")
    compile files ("H:/Processes/Development/libraries/rxjava-extras/rxjava-extras-0.5.15.jar")
    compile files ("H:/Processes/Development/libraries/rxjavafx/RxJavaFX-1.0.0-RC1-SNAPSHOT.jar")
    compile files ("H:/Processes/Development/libraries/rxjavaguava/rxjava-guava-1.0.3.jar")
    compile files ("H:/Processes/Development/libraries/rxjava-jdbc/rxjava-jdbc-0.6.3.jar")
    compile files ("H:/Processes/Development/libraries/slf4j/slf4j-api-1.7.12.jar")
    compile files ("H:/Processes/Development/libraries/tom-commons/tom-commons.jar")
}

sourceSets {
    main.java.srcDir "src/main/java"
    main.resources.srcDir "src/main/resources"
}

jar { 
    manifest {
    attributes(
        "Class-Path": configurations.compile.collect { it.getName() }.join(' '))
    }
    from configurations.compile.collect { entry -> zipTree(entry) }
}
tmn
источник

Ответы:

143

Попробуйте изменить атрибуты манифеста, например:

jar {
  manifest {
    attributes(
      'Class-Path': configurations.compile.collect { it.getName() }.join(' '),
      'Main-Class': 'hello.HelloWorld'
    )
  }
}

А затем просто измените его 'hello.helloWorld'на '<your packagename>.<the name of your Main class>'(где у вашего основного класса есть основной метод). В этом случае вы делаете в своем манифесте атрибут, указывающий на этот класс, тогда запускается jar.

Станислав
источник
1
@Stanislav Значение 'Main-Class' - это основной класс? Что такое hello и helloWorld в вашем примере?
Даниэла Майя,
2
@DanielaMaia, это просто полное имя класса, обязательно нужно писать как hello.HelloWorld, где hello - это пакет, в котором расположен класс HelloWorld
Станислав
9
Мне нужно было удалить collect {}часть, чтобы заставить ее работать на меня. Ваш код предполагает, что все зависимости находятся в той же папке, что и ваш основной класс.
AutonomousApps,
1

FWIW - я использовал следующую задачу jar для сборки всех моих зависимостей компиляции в файл jar и использовал приведенную выше рекомендацию, чтобы правильно установить путь к классу

apply plugin: 'java-library'

jar {
  manifest {
    attributes(
      'Class-Path': configurations.compile.collect { it.getName() }.join(' '),
      'Main-Class': 'your.main.class.goes.here'
    )
  }

  // You can reference any part of the dependency configurations,
  // and you can have as many from statements as you need
  from configurations.compile  
  // I just copied them into the top of the jar, so it looks like the eclipse exported 
  // runnable jar, but you could designate a lib directory, and reference that in the 
  // classpath as "lib/$it.name" instead of it.getName()
  into ''   
}
Эрик Халландер
источник
0

Чтобы сделать jarфайл исполняемым (чтобы java -jarкоманда работала), укажите Main-Classатрибут в MANIFEST.MF.

В Gradle это можно сделать, настроив jarзадачу.

  • для Groovy DSL см. эти ответы ( [1] , [2] )
  • для Kotlin DSL вы можете использовать следующий фрагмент кода:
tasks.withType<Jar> {
    manifest {
        attributes["Main-Class"] = "com.caco3.Main"
    }
}

Почему mainClassNameне работает как положено?

Или почему mainClassNameне указывает атрибут в манифесте?

mainClassNameСвойство приходит из applicationплагина . Плагин:

позволяет легко запустить приложение локально во время разработки и упаковать приложение в виде TAR и / или ZIP, включая сценарии запуска, специфичные для операционной системы .

Таким образом, applicationплагин не преследует цель получения исполняемых jarсек

Когда mainClassNameсвойство установлено, то:

  1. $ ./gradlew runзапустит mainметод в классе, указанном в атрибуте
  2. zip/ tarархивирование построена с использованием distZip/ distTarзадач будет содержать скрипт, который будет запускать mainметод указанного ранее класса.

Вот строка сценария оболочки, устанавливающая основной класс:

$ grep Main2 gradletest
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLETEST_OPTS -classpath "\"$CLASSPATH\"" com.caco3.gradletest.Main2 "$APP_ARGS"
Денис Заведеев
источник