Based on other answers here I am using this Gradle build to create a fat/uber/shaded Jar with my command line tool and a number of JDBC drivers:
import org.gradle.jvm.tasks.Jar
dependencies {
api(project(":db2xls"))
api("ch.qos.logback:logback-classic:1.2.3")
api("com.h2database:h2:1.4.200")
api("org.postgresql:postgresql:42.2.16")
api("mysql:mysql-connector-java:8.0.21")
api("com.microsoft.sqlserver:mssql-jdbc:8.4.1.jre11")
}
val fatJar = task("fatJar", type = Jar::class) {
manifest {
attributes["Implementation-Title"] = "DB2XLS Bundle"
attributes["Implementation-Version"] = "0.1-SNAPSHOT"
attributes["Main-Class"] = "de.peterbecker.xls.Db2XlsKt"
}
from(
configurations.compile.get().map { if (it.isDirectory) it else zipTree(it) },
configurations.runtimeClasspath.get().map { if (it.isDirectory) it else zipTree(it) }
)
with(tasks.jar.get() as CopySpec)
}
tasks {
"build" {
dependsOn(fatJar)
}
}
The build produces a JAR file that looks ok when inspecting with a ZIP tool, but it fails to execute:
$ java -jar db2xls-bundle-0.1-SNAPSHOT.jar
Error: Could not find or load main class de.peterbecker.xls.Db2XlsKt
Caused by: java.lang.ClassNotFoundException: de.peterbecker.xls.Db2XlsKt
The same goes if I use a classpath instead:
$ java -cp db2xls-bundle-0.1-SNAPSHOT.jar de.peterbecker.xls.Db2XlsKt
Error: Could not find or load main class de.peterbecker.xls.Db2XlsKt
Caused by: java.lang.ClassNotFoundException: de.peterbecker.xls.Db2XlsKt
The class file seems to be there, though:
$ jar -t --file db2xls-bundle-0.1-SNAPSHOT.jar | grep Db2XlsKt
de/peterbecker/xls/Db2XlsKt$logger$1.class
de/peterbecker/xls/Db2XlsKt$processQuery$1.class
de/peterbecker/xls/Db2XlsKt$toLists$$inlined$use$lambda$1.class
de/peterbecker/xls/Db2XlsKt.class
And the normal JAR seems to find load the class as expected (then failing on the lack of a depdency):
$ java -cp db2xls-0.1-SNAPSHOT.jar de.peterbecker.xls.Db2XlsKt
Error: Unable to initialize main class de.peterbecker.xls.Db2XlsKt
Caused by: java.lang.NoClassDefFoundError: kotlin/NoWhenBranchMatchedException
What am I doing wrong?
The full code is available at https://github.com/peterbecker/xls-utils/tree/fat_jar
Related
I developed a simple project using ktor
here is my Application.kt
fun main() {
embeddedServer(
factory = CIO, port = 8080, host = "0.0.0.0"
) {
configDependencyInjection()
configSerialization()
configJwtAuthentication()
configStatusPages()
configRequestValidation()
configUserRouting()
Database.connect(
url = "jdbc:postgresql://localhost:5432/coffeehouse",
driver = "org.postgresql.Driver",
user = "postgres",
password = "74279744fz"
)
transaction {
SchemaUtils.drop(Users, CoffeeHouses)
SchemaUtils.create(Users, CoffeeHouses)
}
}.start(wait = true)
}
and here is my build.gradle.kts
val ktorVersion: String by project
val kotlinVersion: String by project
val logbackVersion: String by project
val exposedVersion: String by project
val koinVersion: String by project
val postgresVersion: String by project
plugins {
application
kotlin("jvm") version "1.7.20"
id("io.ktor.plugin") version "2.1.2"
id("org.jetbrains.kotlin.plugin.serialization") version "1.7.20"
}
group = "ir.coffee"
version = "0.0.1"
application {
mainClass.set("ir.coffee.ApplicationKt")
val isDevelopment: Boolean = project.ext.has("development")
applicationDefaultJvmArgs = listOf("-Dio.ktor.development=$isDevelopment")
}
repositories {
mavenCentral()
}
tasks.withType<Jar> {
manifest {
attributes["Main-class"] = application.mainClass
}
}
dependencies {
implementation("io.ktor:ktor-server-content-negotiation-jvm:$ktorVersion")
implementation("io.ktor:ktor-server-core-jvm:$ktorVersion")
implementation("io.ktor:ktor-serialization-kotlinx-json-jvm:$ktorVersion")
implementation("io.ktor:ktor-server-cio-jvm:$ktorVersion")
implementation("io.ktor:ktor-server-auth:$ktorVersion")
implementation("io.ktor:ktor-server-auth-jwt:$ktorVersion")
implementation("io.ktor:ktor-server-request-validation:$ktorVersion")
implementation("io.ktor:ktor-server-status-pages:$ktorVersion")
implementation("ch.qos.logback:logback-classic:$logbackVersion")
implementation("org.jetbrains.exposed:exposed-core:$exposedVersion")
implementation("org.jetbrains.exposed:exposed-dao:$exposedVersion")
implementation("org.jetbrains.exposed:exposed-jdbc:$exposedVersion")
implementation("org.postgresql:postgresql:$postgresVersion")
implementation("io.insert-koin:koin-ktor:$koinVersion")
implementation("io.insert-koin:koin-logger-slf4j:$koinVersion")
testImplementation("io.ktor:ktor-server-tests-jvm:$ktorVersion")
testImplementation("org.jetbrains.kotlin:kotlin-test-junit:$kotlinVersion")
}
when I run the project, it works fine and i can make a jar file with
./gradlew installDist command.
but when I try to run the jar file with java -jar ir.coffee-0.0.1.jar command
i get this error:
Exception in thread "main" java.lang.NoClassDefFoundError: io/ktor/server/cio/CIO
at ir.coffee.ApplicationKt.main(Application.kt:16)
at ir.coffee.ApplicationKt.main(Application.kt)
Caused by: java.lang.ClassNotFoundException: io.ktor.server.cio.CIO at
java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:581)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
... 2 more
any suggestion how can I fix this?
The installDist task packs the project's class files in a JAR without dependencies. So to solve your problem you can either specify paths to the dependencies via the -classpath flag while executing java or pack all dependencies in a JAR (Gradle Shadow plugin).
...obviously some necessary things are not included from the dependencies.
Once it reaches a call to an external library, it breaks, either with ClassNotFoundException, or without a word.
I started with this skeleton project.
Relevant changes in build.gradle:
application {
mainClassName = 'net.laca.FoKt'
}
(my main function is in fo.kt)
dependencies {
//...
compile "com.sparkjava:spark-core:2.9.3"
implementation 'com.google.code.gson:gson:2.8.6'
implementation fileTree('libs') { include '*.jar' }
}
jar {
archiveBaseName = 'csira'
// Uncommend the last two lines to build a "fat" jar with `./gradlew jar`,
// and run it without Gradle's help: `java -jar build/libs/skeleton.jar`
manifest { attributes 'Main-Class': 'net.laca.FoKt' }
from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
}
versions: Kotlin 1.4.20, Java 11, Gradle 6.7.1
Allegedly it should work this way. As it does if I start it with gradle run.
But when I start it with java -jar build/libs/csira.jar after gradle jar, it doesn't.
Relevant parts of fo.kt:
package net.laca
import spark.Spark.*
import com.google.gson.GsonBuilder
fun main(args: Array<String>) {
before("/*")
{ req, res ->
res.type("application/json")
println("hívás: ${req.requestMethod()} ${req.pathInfo()} " + req.queryString())
println(GsonBuilder().create().toJson(req.queryMap().toMap())) //line 14
//...
}
At GsonBuilder it breaks:
java.lang.NoClassDefFoundError: com/google/gson/GsonBuilder
at net.laca.FoKt$main$1.handle(fo.kt:14)
at spark.FilterImpl$1.handle(FilterImpl.java:73)
at spark.http.matching.BeforeFilters.execute(BeforeFilters.java:48)
at spark.http.matching.MatcherFilter.doFilter(MatcherFilter.java:133)
at ...
...
Caused by: java.lang.ClassNotFoundException: com.google.gson.GsonBuilder
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:602)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
... 19 more
And when I take/comment out the 14th line, and it reaches a call to my own jar in /libs:
get("/whatever")
{
println("before")
com.zz.app.MyScalaClass.apply().myFun()
println("after")
}
then the last thing I see is before, the rest is silence.
It happens because your jar task is configured incorrectly. To understand why, look at your dependencies:
dependencies {
//...
compile "com.sparkjava:spark-core:2.9.3"
implementation 'com.google.code.gson:gson:2.8.6'
implementation fileTree('libs') { include '*.jar' }
}
You are using both the compile and implementation configurations. The former is deprecated and should not be used by the way.
Then look at the jar task:
jar {
archiveBaseName = 'csira'
// Uncommend the last two lines to build a "fat" jar with `./gradlew jar`,
// and run it without Gradle's help: `java -jar build/libs/skeleton.jar`
manifest { attributes 'Main-Class': 'net.laca.FoKt' }
from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
}
The from part instructs Gradle to collect all dependencies from the compile configuration only, and this will ignore the implementation configuration completely.
While you could change "compile" to "implementation" everywhere, the correct way to construct a fat jar is to actually collect from the runtimeClasspath configuration. This one extends other configurations like compile and implementation, but also runtimeOnly which you might find handy in the future.
There is actually also an example of how to do this in the Gradle user guide. To adapt it for your project, it should look like:
jar {
archiveBaseName = 'csira'
manifest { attributes 'Main-Class': 'net.laca.FoKt' }
dependsOn configurations.runtimeClasspath
from {
configurations.runtimeClasspath.findAll { it.name.endsWith('jar') }.collect { zipTree(it) }
}
}
The extra dependsOn line ensures that the runtimeClasspath configuration is completely resolved before trying to use it. Another difference is that it only collects jar files.
I wrote a simple kotlin helloworld program
hello.kt
fun main(args: Array<String>) {
println("Hello, World!")
}
Then I compiled it with kotlinc
$kotlinc hello.kt -include-runtime -d hello.jar
there was no errors and hello.jar was generated.
when I ran it
$java -jar hello.jar
it said there is no main manifest attribute in hello.jar
$no main manifest attribute, in hello.jar
I couldn't figure out this problem.
My kotlin version is 1.3.40, JDK version is 1.8.0
I came accross this answer while having the same issue with Kotlin and gradle. I wanted to package to get the jar to work but kept on pilling errors.
With a file like com.example.helloworld.kt containing your code:
fun main(args: Array<String>) {
println("Hello, World!")
}
So here is what the file build.gradle.kts would look like to get you started with gradle.
import org.gradle.kotlin.dsl.*
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
application
kotlin("jvm") version "1.3.50"
}
// Notice the "Kt" in the end, meaning the main is not in the class
application.mainClassName = "com.example.MainKt"
dependencies {
compile(kotlin("stdlib-jdk8"))
}
tasks.withType<KotlinCompile> {
kotlinOptions.jvmTarget = "1.8"
}
tasks.withType<Jar> {
// Otherwise you'll get a "No main manifest attribute" error
manifest {
attributes["Main-Class"] = "com.example.MainKt"
}
// To avoid the duplicate handling strategy error
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
// To add all of the dependencies otherwise a "NoClassDefFoundError" error
from(sourceSets.main.get().output)
dependsOn(configurations.runtimeClasspath)
from({
configurations.runtimeClasspath.get().filter { it.name.endsWith("jar") }.map { zipTree(it) }
})
}
So once you gradle clean build you can either do:
gradle run
> Hello, World!
Assuming your projector using the jar in build/libs/hello.jar assuming that in your settings.gradle.kts you have set rootProject.name = "hello"
Then you can run:
java -jar hello.jar
> Hello, World!
Try to upgrade to version 1.3.41 and using JDK 1.11+.
I'm trying to build a Kotlin application but, even with successfully build, I face with the error bellow. What I'm doing wrong?
▶ java -jar build/libs/app-0.1.jar
22:10:02.122 [main] INFO io.micronaut.runtime.Micronaut - No embedded container found. Running as CLI application
Here is my build status:
▶ ./gradlew assemble
BUILD SUCCESSFUL in 3s
14 actionable tasks: 1 executed, 13 up-to-date
That is the part of my gradle.build file:
apply from: "dependencies.gradle"
apply from: "protobuf.gradle"
version "0.1"
group "app"
mainClassName = "app.Application"
dependencies {
compile "ch.qos.logback:logback-classic:1.2.3"
}
jar {
manifest {
attributes "Main-Class": mainClassName
}
from {
configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
}
}
I had a similar issue:
I was able to run code from IDE, but failed to run Docker container with the app
And had compile 'io.micronaut:micronaut-http-server-netty:1.1.0' in my build.gradle.
Also I was using shadowJar plugin and there was the issue. Adding:
shadowJar {
mergeServiceFiles()
}
solved the problem. It transforms entries in META-INF/services resources into a single resource. My shadowed jar file contained a lot of entries in this folder.
It is difficult to say for sure without seeing the project but one thing that could cause that issue would be not having a dependency on io.micronaut:micronaut-http-server-netty. A newly created app will have something like this in build.gradle...
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:${kotlinVersion}"
compile "org.jetbrains.kotlin:kotlin-reflect:${kotlinVersion}"
compile "io.micronaut:micronaut-runtime"
compile "io.micronaut:micronaut-http-client"
// Make Sure You Have This...
compile "io.micronaut:micronaut-http-server-netty"
kapt "io.micronaut:micronaut-inject-java"
kapt "io.micronaut:micronaut-validation"
kaptTest "io.micronaut:micronaut-inject-java"
runtime "ch.qos.logback:logback-classic:1.2.3"
runtime "com.fasterxml.jackson.module:jackson-module-kotlin:2.9.4.1"
testCompile "org.junit.jupiter:junit-jupiter-api:5.1.0"
testCompile "org.jetbrains.spek:spek-api:1.1.5"
testRuntime "org.junit.jupiter:junit-jupiter-engine:5.1.0"
testRuntime "org.jetbrains.spek:spek-junit-platform-engine:1.1.5"
}
I try to run "gradle test", and get error
My test is
class HelperTest extends ro.gd.Test {
Plugin o;
void setUp() {
o = new Plugin();
}
void testGetIdeaDeps() {
def r = o.ideaDeps
asrHaveVal r
}
}
when i run gradle test, it raise:
junit.framework.AssertionFailedError: Exception in constructor: testGetIdeaDeps (java.lang.NoClassDefFoundError: Could not initialize class groovy.lang.GroovySystem
at org.codehaus.groovy.reflection.ClassInfo.isValidWeakMetaClass(ClassInfo.java:221)
at org.codehaus.groovy.reflection.ClassInfo.getMetaClassForClass(ClassInfo.java:191)
at org.codehaus.groovy.reflection.ClassInfo.getMetaClass(ClassInfo.java:236)
at ro.gd.idea.HelperTest.$getStaticMetaClass(HelperTest.groovy)
at ro.Test.<init>(Test.groovy)
at ro.gd.Test.<init>(Test.groovy)
at ro.gd.idea.HelperTest.<init>(HelperTest.groovy)
...
Here is my full code
I fix this question. the reason is "groovy.lang.GroovyRuntimeException: Conflicting module versions", for detail, following is my build.gradle
compile 'org.codehaus.groovy:groovy-all:+'
compile gradleApi()
I guess gradleApi() will auto "compile localGroovy()", and this groovy version is 2.3.6, but latest version is 2.4.3
I find this error message in one test report
the solution is to specify groovy version like following
compile 'org.codehaus.groovy:groovy-all:2.3.6'
and you check your groovy version with 'gradle dependencies|grep groovy'