web-dev-qa-db-fra.com

comment exporter un fichier exécutable dans gradle, et ce fichier peut s'exécuter car il inclut des bibliothèques de référence

comment exporter un fichier exécutable dans gradle, et ce fichier peut s'exécuter car il inclut des bibliothèques de référence.

build.gradle

apply plugin: 'Java'

manifest.mainAttributes("Main-Class" : "com.botwave.analysis.LogAnalyzer")

repositories {
    mavenCentral()
}

dependencies {
    compile (
        'commons-codec:commons-codec:1.6',
        'commons-logging:commons-logging:1.1.1',
        'org.Apache.httpcomponents:httpclient:4.2.1',
        'org.Apache.httpcomponents:httpclient:4.2.1',
        'org.Apache.httpcomponents:httpcore:4.2.1',
        'org.Apache.httpcomponents:httpmime:4.2.1',
        'ch.qos.logback:logback-classic:1.0.6',
        'ch.qos.logback:logback-core:1.0.6',
        'org.slf4j:slf4j-api:1.6.0',
        'junit:junit:4.+'
    )
}

après avoir couru: gradle build

il crée le dossier de build, et j'exécute le pot dans build/libs/XXX.jar:

Version Java -jar/libs/XXX.jar

voici une exécution dit:

Exception in thread "main" Java.lang.NoClassDefFoundError: ch/qos/logback/core/joran/spi/JoranException

comment puis-je l'exécuter avec les bibliothèques de référence?

40
jychan

Vous pouvez y parvenir avec plugin d'application Gradle

17
erdi

J'espère que cela aide quelqu'un (car j'ai malheureusement passé pas mal de temps à essayer de trouver la solution). Voici la solution qui a fonctionné pour moi pour créer un fichier JAR exécutable. J'incorpore Jetty dans la méthode principale, Jetty 9 pour être spécifique et j'utilise Gradle 2.1.

Incluez le code suivant dans votre fichier build.gradle (si un sous-projet est le projet "principal" à partir duquel le pot doit être construit, puis ajoutez-le au sous-projet qui devrait démarrer comme ce projet (':') {insérer le code quelque part ici, après les dépendances.}.

De plus, vous devez ajouter le plugin Java pour que cela fonctionne: appliquez le plugin: 'Java'.

Ma tâche de pot se présente comme suit:

apply plugin: 'Java'

jar {

    archiveName = "yourjar.jar"

    from {

        configurations.runtime.collect {
            it.isDirectory() ? it : zipTree(it)
        }

        configurations.compile.collect {
            it.isDirectory() ? it : zipTree(it)
        }
    }

    manifest {
        attributes 'Main-Class': 'your.package.name.Mainclassname'
    }

    exclude 'META-INF/*.RSA', 'META-INF/*.SF','META-INF/*.DSA'
}

Et puis vous pouvez exécuter votre yourjar.jar via la ligne de commande:

Java -jar yourjar.jar

Les META-INF/. RSA, META-INF /. SF et META-INF/*. DSA doivent être exclus pour que cela fonctionne. Sinon, une SecurityException est levée.

Le problème semble résider avec Jetty intégrée, lorsque Jetty est passée à Eclipse et signe maintenant leurs JAR, ce qui, selon moi, devient problématique lorsque d'autres JAR non signés veulent charger ceux signés. N'hésitez pas à me renseigner si je me trompe, c'est exactement ce que j'ai lu.

Les fichiers JAR dont dépend le projet sont définis dans les dépendances comme suit:

dependencies {

    // add the subprojects / modules that this depends on
    compile project(':subproject-1')
    compile project(':subproject-2')

    compile group: 'org.Eclipse.jetty', name: 'jetty-server', version: '9.2.6.v20141205'
    compile group: 'org.Eclipse.jetty', name: 'jetty-servlet', version: '9.2.6.v20141205'
    compile group: 'org.Eclipse.jetty', name: 'jetty-http', version: '9.2.6.v20141205'

}

EDIT: Avant, au lieu de juste

configurations.runtime.collect{...}

j'ai eu

configurations.runtime.asFileTree.files.collect{...}

Cela a provoqué un comportement étrange dans un projet plus grand dans une construction propre. Lorsque vous exécutez le bocal après avoir exécuté la génération de nettoyage propre de Gradle pour la première fois (après avoir nettoyé manuellement le répertoire de construction), il lèverait une exception NoClassDefFoundException (dans notre projet avec de nombreux sous-projets), mais exécuter le bocal après avoir exécuté la génération de nettoyage propre de Gradle une deuxième fois (sans vider le répertoire de construction manuellement), pour une raison quelconque, il avait toutes les dépendances. Cela ne s'est pas produit si asFileTree.files a été omis.

Je dois également noter que toutes les dépendances de compilation sont incluses dans l'exécution, mais toutes les exécutions ne sont pas incluses dans la compilation. Donc, si vous utilisez simplement la compilation

        configurations.compile.collect {
            it.isDirectory() ? it : zipTree(it)
        }

Ensuite, n'oubliez pas que s'il y a une exception NoClassDefFoundException levée, aucune classe n'est trouvée au moment de l'exécution, ce qui signifie que vous devez également inclure ceci:

        configurations.runtime.collect {
            it.isDirectory() ? it : zipTree(it)
        }
16
flamingo

Réponse rapide

  1. Ajoutez ce qui suit à votre build.gradle:

    apply plugin: 'application'
    
    mainClassName = 'org.example.app.MainClass'
    
    jar {
        manifest {
            attributes 'Main-Class': mainClassName,
                       'Class-Path': configurations.runtime.files.collect {"$it.name"}.join(' ')
        }
    }
    
  2. Dans le répertoire du projet, exécutez gradle installDist
  3. Courir Java -jar build/install/<appname>/lib/<appname>.jar

Je recommande d'ajouter la version de l'application à votre build.gradle également, mais ce n'est pas obligatoire. Si vous le faites, le nom du bocal intégré sera <appname>-<version>.jar.

Remarque: j'utilise le grade 2.5


Détails

Afin de créer un pot exécutable autonome que vous pouvez simplement exécuter avec:

Java -jar appname.jar

tu auras besoin de:

  1. votre pot pour inclure un fichier MANIFEST pointant vers la classe principale de votre application
  2. toutes vos dépendances (classes de jars en dehors de votre application) à inclure ou accessibles d'une manière ou d'une autre
  3. votre fichier MANIFEST pour inclure le chemin de classe correct

Comme le soulignent d'autres réponses, vous pouvez utiliser un plugin tiers pour y parvenir, comme shadow ou one-jar .

J'ai essayé l'ombre, mais je n'ai pas aimé le fait que toutes mes dépendances et leurs ressources ont été vidées à plat dans le pot construit avec mon code d'application. Je préfère également minimiser l'utilisation de plugins externes.

Une autre option serait d'utiliser le plugin d'application gradle comme @erdi a répondu ci-dessus. Fonctionnement gradle build construira un pot pour vous et le regroupera joliment avec toutes vos dépendances dans un fichier Zip/tar. Vous pouvez également exécuter simplement gradle installDist pour ignorer la fermeture éclair.

Cependant , comme @jeremyjjbrown l'a écrit dans un commentaire, le plugin ne le fait pas créer un fichier exécutable en soi. Il crée un jar et un script qui construit le chemin de classe et exécute une commande pour exécuter la classe principale de votre application. Vous ne pourrez pas exécuter Java -jar appname.jar.

Pour tirer le meilleur parti des deux mondes, suivez les étapes ci-dessus qui créent votre pot avec toutes vos dépendances en tant que pots séparés et ajoutez les valeurs correctes à votre MANIEST.

10
elanh

Toutes ces réponses sont erronées ou obsolètes.

L'OP demande ce qu'on appelle un "gros pot". C'est un pot exécutable qui contient toutes les dépendances de sorte qu'il ne nécessite aucune dépendance extérieure pour fonctionner (sauf pour un JRE bien sûr!).

La réponse au moment de la rédaction est le plugin Gradle Shadow Jar, expliqué assez clairement à Shadow Plugin User Guide & Examples .

J'ai un peu lutté. Mais cela fonctionne:

mettez toutes ces lignes quelque part dans votre fichier build.gradle (je les mets près du haut):

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.github.jengelman.gradle.plugins:shadow:1.2.4' 
    }
}
apply plugin: 'com.github.johnrengelman.shadow'
shadowJar {
    baseName = 'shadow'
    classifier = null
    version = null
}
jar {
    manifest {
        attributes 'Class-Path': '/libs/a.jar'
        attributes 'Main-Class': 'core.MyClassContainingMainMethod'
    }
}

PS ne vous inquiétez pas des autres lignes de "référentiels", de "dépendance" ou de "plugin" ailleurs dans votre fichier de construction, et ne laissez les lignes ainsi à l'intérieur de ce bloc "buildscript" (je ne sais pas pourquoi vous devez le faire).

PPS the Shadow Plugin Guide de l'utilisateur et exemples est bien écrit mais ne vous dit pas d'inclure la ligne

attributes 'Main-Class': 'core.MyClassContainingMainMethod'

où je l'ai mis dessus. Peut-être parce que l'auteur suppose que vous êtes moins ignorant que moi, et vous l'êtes probablement. Je ne sais pas pourquoi on nous dit de mettre un étrange attribut "Class-Path" comme ça, mais s'il n'est pas cassé, ne le réparez pas.

Quand tu pars

> gradle shadowjar

Nous espérons que Gradle construira un gros pot exécutable sous/build/libs (nom par défaut "shadow.jar") que vous pouvez exécuter en faisant ceci:

> Java -jar shadow.jar
5
mike rodent

J'ai vérifié pas mal de liens pour la solution, j'ai finalement fait les étapes mentionnées ci-dessous pour le faire fonctionner. J'utilise Gradle 2.9.

Apportez les modifications suivantes dans votre build, fichier gradle:

1. Mentionnez le plugin:

apply plugin: 'eu.appsatori.fatjar'

2. Fournissez le Buildscript:

buildscript {
  repositories {
    jcenter()
   }

dependencies {
  classpath "eu.appsatori:gradle-fatjar-plugin:0.3"
  }
}

3. Fournissez la classe principale:

fatJar {
  classifier 'fat'
  manifest {
     attributes 'Main-Class': 'my.project.core.MyMainClass'
  }
  exclude 'META-INF/*.DSA', 'META-INF/*.RSA', 'META-INF/*.SF'
}

4. Créez le fatjar:

./gradlew clean fatjar

5. Exécutez le fatjar depuis/build/libs /:

Java -jar MyFatJar.jar
1
Sandeep Sarkar