web-dev-qa-db-fra.com

Construire un pot auto-exécutable avec Gradle et Kotlin

J’ai écrit un simple fichier source Kotlin pour commencer, et un fichier de script Gradle . Mais je ne sais pas comment ajouter la fonction principale au manifeste, pour que le fichier jar puisse être auto-exécutable. .

Voici mon script build.gradle:

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:0.9.66'
    }
}
apply plugin: "kotlin"
repositories {
    mavenCentral()
}
dependencies {
    compile 'org.jetbrains.kotlin:kotlin-stdlib:0.9.66'
}

jar {
    manifest {
        attributes 'Main-Class': 'com.loloof64.kotlin.exps.ExpsPackage'
    }
}

Voici mon com.loloof64.kotlin.exps.Multideclarations.kt

package com.loloof64.kotlin.exps

class Person(val firstName: String, val lastName: String) {
    fun component1(): String {
        return firstName
    }
    fun component2(): String {
        return lastName
    }
}

fun main(args: Array < String > ) {
    val(first, last) = Person("Laurent", "Bernabé")
    println("First name : $first - Last name : $last")
}

Lorsque je lance le fichier jar depuis le terminal (Java -jar MYJar.jar), la pile suivante est générée. Elle me dit que les classes de la bibliothèque de réflexions kotlin sont manquantes et qu'elles n'ont pas été ajoutées au fichier. Il semble que je manque les classes d'artefacts kotlin-compiler du dernier fichier, ainsi que les sources kotlin-stdlib, mais je ne sais pas comment adapter la construction de gradle.

$> Java -jar build/libs/kotlin_exps.jar 

Exception in thread "main" Java.lang.NoClassDefFoundError: kotlin/reflect/jvm/internal/InternalPackage
    at com.loloof64.kotlin.exps.ExpsPackage.<clinit>(MultiDeclarations.kt)
Caused by: Java.lang.ClassNotFoundException: kotlin.reflect.jvm.internal.InternalPackage
    at Java.net.URLClassLoader$1.run(URLClassLoader.Java:372)
    at Java.net.URLClassLoader$1.run(URLClassLoader.Java:361)
    at Java.security.AccessController.doPrivileged(Native Method)
    at Java.net.URLClassLoader.findClass(URLClassLoader.Java:360)
    at Java.lang.ClassLoader.loadClass(ClassLoader.Java:424)
    at Sun.misc.Launcher$AppClassLoader.loadClass(Launcher.Java:308)
    at Java.lang.ClassLoader.loadClass(ClassLoader.Java:357)
    ... 1 more

J'utilise Kotlin 0.9.66 et la version 2.1

36
loloof64

J'ai trouvé la solution de contournement (merci à site Web MkYong )

  1. Le script Gradle avait besoin de l'artefact kotlin-compiler comme dépendance
  2. Le script gradle avait besoin d’un moyen de collecter tous les fichiers kotlin et de les mettre dans le pot.

Donc, je reçois avec le script de gradle suivant:

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
       classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.0.1-2'
    }
}

apply plugin: "kotlin"

repositories {
    mavenCentral()
}

dependencies {
    compile 'org.jetbrains.kotlin:kotlin-stdlib:1.0.1-2'
}

jar {
    manifest {
        attributes 'Main-Class': 'com.loloof64.kotlin.exps.MultideclarationsKT'
    }

    // NEW LINE HERE !!!
    from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
}
24
loloof64

Ajoutez le plugin application, puis définissez la mainClassName comme

mainClassName = '[your_namespace].[your_arctifact]Kt'

Par exemple, supposons que vous ayez placé le code suivant dans un fichier nommé main.kt:

package net.mydomain.kotlinlearn

import kotlin
import Java.util.ArrayList

fun main(args: Array<String>) {

    println("Hello!")

}

votre build.gradle devrait être:

apply plugin: 'kotlin'
apply plugin: 'application'

mainClassName = "net.mydomain.kotlinlearn.MainKt"

En fait, Kotlin est en train de construire une classe pour encapsuler votre fonction principale portant le même nom que votre fichier, avec Title Case.

28
Guildenstern70

Merci, pour moi cela a fonctionné en ajoutant la section pot

jar {
    manifest {
        attributes 'Main-Class': 'com.photofiles.Application'
    }

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

Pas besoin du plugin d'application.

1
paucls

Au cas où tu serais idiot, comme moi:

Ne créez pas votre configuration d'exécution IntelliJ en tant qu'application. IntelliJ assumera que c'est Java et cela ne fonctionnera jamais. Au lieu de cela, utilisez l'entrée "Kotlin".

0
Tim Keating

Si vous utilisez Gradle avec KotlinDSL, mon duplicate question a la réponse suivante:

import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar

plugins {
    kotlin("jvm") version "1.2.51"
    id("com.github.johnrengelman.shadow") version "2.0.4"
}

group = "xxx.yyy"
version = "1.0-SNAPSHOT"

repositories {
    mavenCentral()
}

dependencies {
    implementation(kotlin("stdlib-jdk8"))
}

tasks.withType<KotlinCompile> {
    kotlinOptions.jvmTarget = "1.8"
}

tasks.withType<ShadowJar> {

    manifest.attributes.apply {
        put("Implementation-Title", "Gradle Jar File Example")
        //put("Implementation-Version" version)
        put("Main-Class", "HelloKotlinWorld.App")
    }

Quelle est, je pense, la solution la plus simple. Oh, vous utilisez peut-être juste la variable Kotlin et non la variable DSL.

0
Thufir