Gradle - sem atributo de manifesto principal

98

Estou criando um arquivo JAR com o Gradle. Quando tento executá-lo, recebo o erro

nenhum atributo de manifesto principal, em RxJavaDemo.jar

Eu tentei manipular a propriedade Manifest, mas acho que estou esquecendo de adicionar as dependências ou algo assim. O que exatamente estou fazendo de errado?

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
fonte

Respostas:

146

Tente alterar seus atributos de manifesto como:

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

E então apenas mude 'hello.helloWorld'para '<your packagename>.<the name of your Main class>'(onde sua classe Main tem um método principal). Nesse caso, você cria em seu manifesto um atributo, que aponta para esta classe, e então um jar está em execução.

Stanislav
fonte
1
O valor @Stanislav 'Main-Class' é a classe principal? O que são hello e helloWorld em seu exemplo?
Daniela Maia
2
@DanielaMaia é apenas um nome de classe totalmente qualificado, com certeza deve ser escrito como hello.HelloWorld, onde hello é o pacote onde a classe HelloWorld está localizada
Stanislav
9
Eu precisava remover a collect {}parte para fazê-la funcionar para mim. Seu código assume que todas as dependências estão na mesma pasta que sua classe principal.
AutonomousApps de
4

Para tornar o jararquivo executável (para que o java -jarcomando funcione), especifique o Main-Classatributo em MANIFEST.MF.

No Gradle, você pode fazer isso configurando a jartarefa.

  • para Groovy DSL veja estas respostas ( [1] , [2] )
  • para Kotlin DSL, você pode usar o seguinte snippet de código:
tasks.withType<Jar> {
    manifest {
        attributes["Main-Class"] = "com.caco3.Main"
    }
}

Por mainClassNameque não funciona como esperado?

Ou por mainClassNameque não especifica o atributo no manifesto?

A mainClassNamepropriedade vem do applicationplugin . O plugin:

torna mais fácil iniciar o aplicativo localmente durante o desenvolvimento e empacotar o aplicativo como TAR e / ou ZIP, incluindo scripts de início específicos do sistema operacional .

Assim, o applicationplugin não visam produzir executáveis jars

Quando uma mainClassNamepropriedade é definida, então:

  1. $ ./gradlew runirá lançar o mainmétodo na classe especificada no atributo
  2. o zip/ tararchive construído usando distZip/ distTartasks conterá um script, que iniciará o mainmétodo da classe especificada anteriormente.

Esta é a linha do script de shell definindo a classe principal:

$ grep Main2 gradletest
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLETEST_OPTS -classpath "\"$CLASSPATH\"" com.caco3.gradletest.Main2 "$APP_ARGS"
Denis Zavedeev
fonte
1

FWIW - Usei a seguinte tarefa jar para montar todas as minhas dependências de compilação no arquivo jar e usei a recomendação acima para obter o caminho da classe definido corretamente

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 ''   
}
Eric Hallander
fonte