Boot jar kotlin gradle

preslavrachev / kotlin-gradle-executable-jars.md

Kotlin is great for creating small command-line utilities, which can be packaged and distributed as normal JAR files. This short tutorial will show you how to:

  • Set up a Gradle project that supports Kotlin
  • Add a starting function
  • Configure your build to call this function when you execute your JAR.

Setting up Kotlin dependencies

apply plugin: 'java' apply plugin: 'kotlin' //… other stuff, you typically find in a Gradle build file dependencies < // other dependencies … compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" > buildscript < ext.kotlin_version = '1.0.2' //. compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" >

You will also want your IDE (I assume you’re using IntelliJ or Android Studio) to mark the directory where your Kotlin source code resides as a source directory. Since Kotlin and Java are best friends, it is perfectly fine to keep the same package structure. It is a good practice though, to keep your Kotlin code physically separate from your Java one. Thus, you’d typically have two folders under src — src/main/java for Java classes, and src/main/kotlin for Kotlin ones. Same for tests. Again, in your build.gradle file, add the following:

sourceSets < main.java.srcDirs += 'src/main/kotlin/' test.java.srcDirs += 'src/test/kotlin/' >

Using IntelliJ, you could rely not he IDE to guide you with all of this, but I wanted to show you the basics, since one may not always rely on the comfort of an IDE. To see that everything is working as it should, go to your project directory and create a new build:

If everything has been set up correctly, you should be able to see a task named compileKotlin which the build has executed successfully.

Write your first Kotlin program

Unlike Java, Kotlin is friendlier with functions that reside outside of any class scope. You can create a Main class hosting a main() function, or you can create a top-level main() without necessarily wrapping it in a class. Perhaps, you wouldn’t be able to find any difference in a such a brief examaple, but I find the possibility to create top-level functions helpful in reducing boilerplate code.

Here is the mandatory HelloWorld example. Create a file with an arbitrary name (say Main ) and an extension .kt , and write simply:

fun main(args : ArrayString>) < println("Hello, world!") >

Note that adding a package is optional, as well as ending your lines with semicolons. In order to keep consistency with my Java code though, I’d usually add both, and expect that people I work with, do the same.

Configure your Gradle build to create an executable JAR

The main function we just added, is enough to test setting up an executable JAR, which one should then be able to call simply by executing:

java -jar MY_PROJECT_NAME>.jar

If you simply try to build your project and then execute the above command, we would get the following message:

no main manifest attribute PATH_TO_MY_PROJECT_JAR>.jar

This means that we have to configure jar task, which Java Gradle builds go through, and tell it which the starting point of our project is. In a Java project, this would be the path to the class where our main() function resides:

jar < manifest < attributes 'Main-Class': 'com.myname.myprojectname.Main' > >

Wait a minute? We have defined our main() function outisde of any class scope. That’s true and not entirely true at the same time. Actually, to keep things at the bytecode level consistent, and backwards-compatible with the JVM, the Kotlin compiler adds all top-level functions to respective classes. In our case, the class generated by the Kotlin compiler would have the same name the filename of the file where our function resides, plus the suffix Kt . This means, for example, that if our file is called Main.kt , the Kotlin compiler would generate a class with the name MainKt.class and add it to the generated JAR file. Knowing this, one could rewrite the Gradle configuration above, as follows:

jar < manifest < attributes 'Main-Class': 'com.myname.myprojectname.MainKt' > >

Note: You can specifiy the name this class should be compiled with, by adding a file-scope annotation on top of your file, even before the package decalration:

This new name can be used within the JAR manifest configuration, as shown above.

Even though we specified our main class correctly in our JAR manifest configuration, if we try to execute our main function using jar -jar , we will still see an error message:

Exception in thread "main" java.lang.NoClassDefFoundError: kotlin/jvm/internal/Intrinsics at com.preslavrachev.imdbparser.MainKt.main(Main.kt) Caused by: java.lang.ClassNotFoundException: kotlin.jvm.internal.Intrinsics at java.net.URLClassLoader.findClass(URLClassLoader.java:381) at java.lang.ClassLoader.loadClass(ClassLoader.java:424) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331) at java.lang.ClassLoader.loadClass(ClassLoader.java:357) . 1 more

Experienced Java developers will quickly recognize this type of exception. By default when Gradle (as well as Maven) packs some Java class files into a JAR file, it is assumed that this JAR file will be referenced by an application, where all of its dependencies are also accessible within the classpath of the loading application. To execute a JAR without having to specifiy the path to itse dependencies, one must tell the build system to take all of this JAR’s referenced dependencies and copy them as part of the JAR itself. In the Java community, this is known as a «fat JAR». In a «fat JAR» all of the dependencies end up within the class path of the loading application, so code can be executed without problems. The only downside to creating fat JARs is of course their growing file size (which kind of explains the name), though in most situations, it is not a big concern. In order to tell Gradle to copy all of a JAR’s dependencies, one should simply modify the abovementioned JAR task configuration, by adding the following piece of code:

jar < manifest < attributes 'Main-Class': 'com.preslavrachev.imdbparser.MainKt' > // This line of code recursively collects and copies all of a project's files // and adds them to the JAR itself. One can extend this task, to skip certain // files or particular types at will from < configurations.compile.collect < it.isDirectory() ? it : zipTree(it) > > >

Источник

How to use gradle script kotlin and spring boot gradle plugin to build a runnable jar

Here’s a task configuration assuming JVM application with embedded JS frontend from JS module: Solution 1: I spent 3 days trying to get the fat jar to work, below is the solution and what follows before the solution is clarification: ERRORS I MADE EARLYShouldn’t have rushed into docker, should’ve made fat jar work local first. Solution 3: Worked for me on Gradle 4.10.2: Solution: I refer to github and stackoverflow resources, and It seems the following way works and any problem please tell me to update: another way to be working: Solution 1:

How to add new sourceset with gradle kotlin-dsl

The answer of @s1m0nw1 is correct to add a new sourceset. But to just add a new source-folder in an existing sourceset, this can be used:

You should try the following:

java.sourceSets.create("src/gen/java") 

Worked for me on Gradle 4.10.2:

sourceSets.create("integrationTest") < java.srcDir("src/integrationTest/java") java.srcDir("build/generated/source/apt/integrationTest") resources.srcDir("src/integrationTest/resources") >

Build source jar with Gradle Kotlin DSL?, As of Gradle 6.0 this is a much easier and cleaner. All you need to do is: java < withSourcesJar () withJavadocJar () >Check out the documentation on the java extension, and its functions, withSourcesJar () and withJavadocJar () Share. answered Jan 12, 2020 at 10:10. Tom Hanley. Code sampleplugins repositories

How to use gradle script kotlin and spring boot gradle plugin to build a runnable jar

I refer to github and stackoverflow resources, and It seems the following way works and any problem please tell me to update:

import org.springframework.boot.gradle.plugin.SpringBootPlugin import org.springframework.boot.gradle.SpringBootPluginExtension buildscript < dependencies < classpath("org.springframework.boot:spring-boot-gradle-plugin:1.5.6.RELEASE") >repositories < jcenter() >> plugins < java eclipse id("org.springframework.boot") version "1.5.6.RELEASE" >repositories < maven < url=uri("http://clojars.org/repo") >> dependencies < compile ("commons-net:commons-net:2.0") compile ("log4j:log4j:1.2.17") compile ("javax.servlet:servlet-api:2.4") >configure  < setSourceCompatibility(1.7) setTargetCompatibility(1.7) if(project.hasProperty("env"))< var env = project.property("env"); sourceSets.getByName("main").resources.srcDirs("src/main/profile/" + env) >> configure("processResources") < if(project.hasProperty("env"))< exclude("src/main/profile/scripts") >> //apply() configure  < mainClass = "sample.HelloWolrd" >inline fun Project.configure(name: String, configuration: C.() -> Unit)

another way to be working:

import org.springframework.boot.gradle.SpringBootPluginExtension configure("processResources") < if(project.hasProperty("env"))< exclude("src/main/profile/scripts") >> springBoot < mainClass = "Application" >inline fun Project.configure(name: String, configuration: C.() -> Unit) < (this.tasks.getByName(name) as C).configuration() >/** * Retrieves or configures the [springBoot] [org.springframework.boot.gradle.SpringBootPluginExtension] project extension. */ fun Project.springBoot(configure: org.springframework.boot.gradle.SpringBootPluginExtension.() -> Unit = <>) = extensions.getByName("springBoot").apply

Building a jar with sources included with Gradle using the, 1 Answer. You should probably tweak the jar task, not the Java Plugin extension (the top-level java clause). Try this: tasks < withType < from (sourceSets ["main"].allSource) duplicatesStrategy = DuplicatesStrategy.EXCLUDE >> I tested it quickly in my project and it seems to work, but due to some quirks I …

Fat Jar expands dependencies with Gradle Kotlin DSL

Well you are using zipTree in that map part of the spec, and it behaves according to the documentation: it unzips the files that are not a directory.

If you want the jars in /lib , replace your from with:

from(configurations.runtimeClasspath)

In case anyone is using kotlin-multiplatform plugin, the configuration is a bit different. Here’s a fatJar task configuration assuming JVM application with embedded JS frontend from JS module:

afterEvaluate < tasks < create("jar", Jar::class).apply < dependsOn("jvmMainClasses", "jsJar") group = "jar" manifest < attributes( mapOf( "Implementation-Title" to rootProject.name, "Implementation-Version" to rootProject.version, "Timestamp" to System.currentTimeMillis(), "Main-Class" to mainClassName ) ) >val dependencies = configurations["jvmRuntimeClasspath"].filter < it.name.endsWith(".jar") >+ project.tasks["jvmJar"].outputs.files + project.tasks["jsJar"].outputs.files dependencies.forEach < from(zipTree(it)) >into("/lib") > > > 

Using Gradle to build a jar with dependencies with Kotlin, This will work: tasks.withType () < configurations ["compileClasspath"].forEach < file: File ->from (zipTree (file.absoluteFile)) > > There’s no need in copy < >, you should call from on the JAR task itself. Note: Gradle does not allow changing the dependencies after they have been …

Create fat jar from ktor Kotlin multiplatform project with Kotlin Gradle DSL

I spent 3 days trying to get the fat jar to work, below is the solution and what follows before the solution is clarification:

  • Shouldn’t have rushed into docker, should’ve made fat jar work local first.
  • withJava() was left out, this was the main waste of 36 man hours. WTF is the point of this function?
  • dependsOn(build): why the jar task type doesn’t know this already I do not understand.
  • main.compileDependencyFiles: I was using this for a time in place of the map from argument below.
  • main.output.classesDirs: was missing from other solutions and is what seems to include your actual code.

NOTE : No shadow plug in required, which is fantastic (gradle plugins tend not to play well together IMHO, ever).

NOTE : Versioning is important because this stack seems to change roughly 50 times faster than the documentation does in some cases, the following was used for this solution:

//Import variables from gradle.properties val environment: String by project val kotlinVersion: String by project val ktorVersion: String by project //Build File Configuration plugins < java kotlin("multiplatform") version "1.3.72" >group = "com.app" version = "1.0-SNAPSHOT" repositories < mavenCentral() jcenter() jcenter < url = uri("https://kotlin.bintray.com/kotlin-js-wrappers") >maven < url = uri("https://jitpack.io") >> //Multiplatform Configuration kotlin < jvm < withJava() compilations < val main = getByName("main") tasks < register("buildFatJar2") < group = "application" dependsOn(build) manifest < attributes["Main-Class"] = "com.app.BackendAppKt" >from(configurations.getByName("runtimeClasspath").map < if (it.isDirectory) it else zipTree(it) >, main.output.classesDirs) archiveBaseName.set("$-fat2") > > > > js < browser < >> sourceSets < SKIPPED FOR LENGTH >> 

I hope this saves someone 3 days, let me know if you find improvements (I’m still learning too). Kotlin, gradle, multiplatform, docker. all are very tough to deal with, they need to update the docs in parallel IMHO or jetbrains is doomed.

POTENTIAL IMPROVEMENTS :

  • The produced jar looks much bigger than it should be with tons of unnecessary stuff, suspect changing to the compile path instead of runtime path will fix that (CONFIRMED 30% size reduction).
  • More manifest attributes perhaps.
  • Also worth noting, I read an article aptly suggesting fatJars shouldn’t be deployed to docker, that the java dependencies should be built as part of the image.

@andylamax answer is pretty close but leads to the error that @cfnz was seeing

To fix that you need to add doFirst as in this example:

val jvm = jvm() < withJava() val jvmJar by tasks.getting(org.gradle.jvm.tasks.Jar::class) < doFirst < manifest < attributes["Main-Class"] = project.ext["mainClass"] >from(configurations.getByName("runtimeClasspath").map < if (it.isDirectory) it else zipTree(it) >) > > > 

It is working as expected in here with gradle jvmJar && java -jar build/libs/laguna-jvm.jar

Your groovy dsl can be written in kotlin as follows

kotlin < jvm < withJava() val jvmJar by tasks.getting(org.gradle.jvm.tasks.Jar::class) < manifest < attributes["Main-Class"] = "sample.MainKt" >from(configurations.getByName("runtimeClasspath").map < if (it.isDirectory) it else zipTree(it) >) > > > 

How to create a fat JAR with Gradle Kotlin script?, Create the JAR with the following command: ./gradlew jar The result JAR will be created in build/libs/ directory by default. After creating your JAR, copy your library JARs in libs/ sub-directory of where you put your result JAR.

Источник

Читайте также:  If else php да нет
Оцените статью