简体   繁体   中英

ClassNotFoundException When running jar file but runs fine in Intellij

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()
    }
} 

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM