Reputation: 73731
I created a small mqtt application using eclipse paho mqtt library in kotlin with Gradle in Intellij IDE. it runs fine when running it through Intellij but when I build it and run the jar file that gets created I get a NoClassDefFoundError
error.
From other questions I have seen about this it looks like it has something to do with the class path but I am not sure what needs to be done if that is indeed the issue because I am using gradle and not jar files for libraries.
I was following this tutorial
Here is my gradle file
plugins {
id 'org.jetbrains.kotlin.jvm' version '1.4.31'
id 'application'
}
group = 'me.package'
version = '1.0-SNAPSHOT'
repositories {
mavenCentral()
maven {
url "https://repo.eclipse.org/content/repositories/paho-snapshots/"
}
}
dependencies {
implementation 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.2.5'
testImplementation 'org.jetbrains.kotlin:kotlin-test-junit'
}
test {
useJUnit()
}
compileKotlin {
kotlinOptions.jvmTarget = '1.8'
}
compileTestKotlin {
kotlinOptions.jvmTarget = '1.8'
}
application {
mainClassName = 'com.publisher.MainKt'
}
tasks.jar {
manifest {
attributes 'Main-Class': 'com.publisher.MainKt'
}
from {
configurations.compile.collect {
it.isDirectory() ? it : zipTree(it)
}
}
}
And my MainKt file
package com.publisher
import org.eclipse.paho.client.mqttv3.*
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence
import java.io.File
fun main(args: Array<String>) {
val client = MqttClient("tcp://192.168.0.55:1883","publisher", MemoryPersistence())
val connOpts = MqttConnectOptions()
connOpts.isCleanSession = false
connOpts.isAutomaticReconnect = true
client.setCallback(object: MqttCallback {
override fun connectionLost(cause: Throwable?) {
println("Connection lost")
println(cause!!.message)
}
override fun messageArrived(topic: String?, message: MqttMessage?) {
println("Message Received for topic: $topic")
println("Message: ${message!!.payload}")
}
override fun deliveryComplete(token: IMqttDeliveryToken?) {
println("Message delivered")
}
})
try{
client.connect(connOpts)
println("Connected")
client.subscribe("config/+", 1) { topic, message ->
println("Getting configuration for $message")
val path = System.getProperty("user.dir")
val file = File("$path/${message}.json")
if(file.exists()){
client.publish("/devices/ + $message + /config", MqttMessage(file.readBytes()))
}
}
}catch (e: MqttException){
println("Error: ${e.localizedMessage}")
e.printStackTrace()
}
}
Upvotes: 2
Views: 911
Reputation: 403
You could consider the Shadow plugin, as it is straightforward to use. Your build.gradle
would look something like this:
plugins {
id 'org.jetbrains.kotlin.jvm' version '1.4.31'
// Shadow plugin
id 'com.github.johnrengelman.shadow' version '6.1.0'
id 'java'
}
group = 'me.package'
version = '1.0-SNAPSHOT'
repositories {
mavenCentral()
maven {
url "https://repo.eclipse.org/content/repositories/paho-snapshots/"
}
}
dependencies {
implementation 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.2.5'
testImplementation 'org.jetbrains.kotlin:kotlin-test-junit'
}
test {
useJUnit()
}
compileKotlin {
kotlinOptions.jvmTarget = '1.8'
}
compileTestKotlin {
kotlinOptions.jvmTarget = '1.8'
}
application {
mainClassName = 'com.publisher.MainKt'
}
tasks.jar {
manifest {
attributes 'Main-Class': 'com.publisher.MainKt'
}
}
So your fat JAR is generated in the /build/libs
directory with all the dependencies included.
Upvotes: 0
Reputation: 2365
The way you start your application does not include the dependencies, meaning your MQTT driver and the Kotlin dependencies are not included.
Do the following:
gradle distZip
# alternatively
gradle distTar
This will create a zip/tar file containing all the dependencies and a start script. Use that to start your application.
Upvotes: 3