【问题标题】:ClassNotFoundException When running jar file but runs fine in IntellijClassNotFoundException 运行 jar 文件但在 Intellij 中运行良好
【发布时间】:2021-06-12 05:26:22
【问题描述】:

我使用 Kotlin 中的 eclipse paho mqtt library 和 Intellij IDE 中的 Gradle 创建了一个小型 mqtt 应用程序。通过 Intellij 运行它时它运行良好,但是当我构建它并运行创建的 jar 文件时,我收到 NoClassDefFoundError 错误。

从我看到的其他问题来看,它看起来与类路径有关,但我不确定如果这确实是问题需要做什么,因为我使用的是 gradle 而不是库的 jar 文件.

我关注了这个tutorial

这是我的 gradle 文件

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

还有我的 MainKt 文件

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

【问题讨论】:

  • 你应该试试 gradle 的应用插件,构建一个包含所需库的应用程序包。
  • @dpr 在我正在关注的教程中(我在上面链接了它,因为我忘了提及它)并没有说什么。我确实快速浏览了插件的文档,但我没有立即看到任何关于包含其他依赖项/库的信息
  • jar文件的内容是什么?您可以使用任何 zip 工具(如 7zip)打开它或在命令行上解压缩。你是如何开始你的申请的?使用 java -jar ?
  • @JensBaitinger jar 文件包含MainKt$main$1.classMainKt$main$2.classMainKt.class 文件以及带有清单的META_INF 文件夹和.kotlin_module 文件。目前我只是通过右键单击 intellij 中的文件并选择运行来运行 jar 文件,但是在执行 java -jar &lt;jar-file-name&gt;.jar 时会发生同样的事情
  • 是 MainKt 在正确的文件夹中(根据它的包)还是在根目录中?

标签: java kotlin gradle intellij-idea jar


【解决方案1】:

您启动应用程序的方式不包括依赖项,这意味着您的 MQTT 驱动程序和 Kotlin 依赖项不包括在内。

执行以下操作:

gradle distZip
# alternatively
gradle distTar

这将创建一个包含所有依赖项和启动脚本的 zip/tar 文件。使用它来启动您的应用程序。

【讨论】:

  • 我查看了错误的文件夹,在分布文件夹中,我现在看到一个包含所有 kotlin 和 paho 库的 .zip 文件。当我提取 zip 文件并运行 bat 文件时,它可以工作
  • 最终目标是在树莓派上运行这个我还能做到吗?
  • 只要您安装了正确版本的 JRE,该 zip 中的所有内容都可以运行。
【解决方案2】:

您可以考虑使用Shadow 插件,因为它使用起来很简单。你的 build.gradle 看起来像这样:

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'
    }
}

因此,您的胖 JAR 将在 /build/libs 目录中生成,其中包含所有依赖项。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-01-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多