Good day, I try to build .jar file for my server c...
# server
s
Good day, I try to build .jar file for my server code to launch it on the virtual machine. Jar, built as artifact is launched with error
Copy code
java -jar server.jar 
Exception in thread "main" java.lang.NoClassDefFoundError: kotlin/jvm/internal/Intrinsics
...
I googled, that the problem is in kotlin library, which should be packed into the jar in a specific way. Documentation here https://www.jetbrains.com/help/idea/create-your-first-kotlin-app.html?section=Gradle%20Groovy tells me, that I should add special code in build.gradle. There is my code on the picture. As you can see, "from" is grey... And I get next error for Gradle
Copy code
* Exception is:
org.gradle.api.GradleScriptException: A problem occurred evaluating root project 'server'.
<131 internal calls>
Caused by: org.gradle.internal.metaobject.AbstractDynamicObject$CustomMessageMissingMethodException: Could not find method jar() for arguments [build_c5anurhkrrlxlaf3i7moe4k0u$_run_closure5@7f80db22] on task set of type org.gradle.api.internal.tasks.DefaultTaskContainer.
	at org.gradle.internal.metaobject.AbstractDynamicObject.methodMissingException(AbstractDynamicObject.java:182)
	at org.gradle.internal.metaobject.AbstractDynamicObject.invokeMethod(AbstractDynamicObject.java:166)
	at org.gradle.api.internal.tasks.DefaultTaskContainer_Decorated.invokeMethod(Unknown Source)
	at build_c5anurhkrrlxlaf3i7moe4k0u.run(/Users/stask/projects/motionLearning/chat/kotlinServer/server/build.gradle:100)
	at org.gradle.groovy.scripts.internal.DefaultScriptRunnerFactory$ScriptRunnerImpl.run(DefaultScriptRunnerFactory.java:91)
	... 130 more
Could you help me, how to fix the build?
v
I strongly recommend not building a fat jar due to many reasons, some of them being that they are a bad practice abuse of Java functionality that can easily be done wrongly and in some cases even cannot work properly. Instead you should use the Gradle
application
plugin to build a proper distribution archive with everything you need (your code, your libs, generated start scripts for Windows and *nix, ...) by just applying one plugin and setting one propertyk https://docs.gradle.org/current/userguide/application_plugin.html
👌🏽 1
s
Thank you, it is a usefull link. I started to understand building process.
@Vampire I read the article, and as I understand, I should add into build.gradle lines
Copy code
application {
    mainClass = 'broccole.Server'
    executableDir = 'out/bin'
}
and run from cmd
gradle distZip
Am I right?
v
If you want the start scripts in
out/bin
in the final archive, then yes
s
In fact nothing was produced. I has default kotlin multiplatform build.gradle script, The folder remains empty
Little strange, that the default task runs server localy successfully. And that task depends on jvmJar task
Copy code
jvmJar {
    dependsOn(jsBrowserProductionWebpack)
    from(new File(jsBrowserProductionWebpack.entry.name, jsBrowserProductionWebpack.outputPath))
}

task run(type: JavaExec, dependsOn: [jvmJar]) {
    group = "application"
    main = "broccole.Server"
    classpath(configurations.jvmRuntimeClasspath, jvmJar)
    args = []
}
@Vampire So, runnable jar is building on my laptop. I just want to upload the jar on virtual machine and launch it there. The simplest way for me - is to find the jar and command to launch, which gradle use on my laptop. But gradle is not transparent, and I don't see its command line log. Could you advice, how to see gradle log?
Eventually found the solution here: https://stackoverflow.com/questions/57168853/create-fat-jar-from-kotlin-multiplatform-project Answer from Julian Schubert works for me. The problem is in kotlin multiplatform, application plugin does not work out of the box @Vampire thank you for your answers!
✔️ 1
Working solution is next
Copy code
kotlin {
jvm() {
    withJava()
    jvmJar {
        manifest {
            attributes 'Main-Class': 'broccole.Server'
        }
        from { configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } }
    }
}
...
v
Ah, sorry, didn't think the multiplatform plugin is made so incompatible with the
application
plugin. To build a proper distribution with the
application
plugin you indeed need a little bit more boilerplate. But I would still prefer that anytime over building a fat jar. I just tried and this should work fine:
Copy code
application {
    mainClass = 'broccole.Server'
}

def runtimeClasspath = files()
runtimeClasspath.from(configurations.jvmRuntimeClasspath)
runtimeClasspath.from(jvmJar)

run {
    classpath = runtimeClasspath
}

startScripts {
    classpath = runtimeClasspath
}

distributions {
    main {
        contents {
            into('lib') {
                from(runtimeClasspath)
            }
        }
    }
}
It fixes up the
run
task, the
startScripts
generation task and the distribution copy spec and thus the
installDist
,
distZip
and
distTar
tasks.
👍 1
✔️ 1
s
@Vampire thank you, I will try your solution and write feedback here.
👍 1
@Vampire I placed you code fragment after jvmJar task, and everything works. Command "gradle assemble" built server.tar file for me. I unpacked it and ran server/bin/server successfully. Thank you!
👌 1