java - 来自外部 JAR 的 Minecraft 插件 ClassNotFound 错误

标签 java jar serial-port minecraft bukkit

我正在尝试为 Minecraft Spigot 服务器构建一个插件,最终我希望能够通过串行方式与连接到我的 PC 的设备进行通信(服务器也在 PC 上本地运行)。

我已经能够构建和运行插件并操纵游戏中的玩家/ block ,所以我知道我的基本插件的构建过程正在运行。当我开始尝试包含额外的依赖项时,我的麻烦就开始了:jSerialComm

我在 pom.xml 文件中添加了依赖项:

<dependency>
    <groupId>com.fazecast</groupId>
    <artifactId>jSerialComm</artifactId>
    <version>[2.0.0,3.0.0)</version>
    <scope>provided</scope>
</dependency>

我添加了一些基本代码来从 jSerialComm 导入类,并在我的插件的命令中使用它们执行一些基本操作:

import com.fazecast.jSerialComm.SerialPort;

public class CommandCheck implements CommandExecutor {

    @Override
    public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
        if (sender instanceof Player){
            System.out.println(SerialPort.getCommPorts());
        }
        return false;
    }
}

这构建得很好,我正在使用 InteliJ 并且它确实识别 SerialPort 类(没有红色下划线)。

但是当此命令在游戏中运行时,我收到“找不到类”错误:

org.bukkit.command.CommandException: Unhandled exception executing command 'check' in plugin MyFirstPlugin v1.0-SNAPSHOT
        at org.bukkit.command.PluginCommand.execute(PluginCommand.java:47) ~[spigot-api-1.18.1-R0.1-SNAPSHOT.jar:?]
        at org.bukkit.command.SimpleCommandMap.dispatch(SimpleCommandMap.java:149) ~[spigot-api-1.18.1-R0.1-SNAPSHOT.jar:?]
        at org.bukkit.craftbukkit.v1_18_R1.CraftServer.dispatchCommand(CraftServer.java:821) ~[spigot-1.18.1-R0.1-SNAPSHOT.jar:3380-Spigot-8965a50-0ba6b90]
        at net.minecraft.server.network.PlayerConnection.a(PlayerConnection.java:1939) ~[spigot-1.18.1-R0.1-SNAPSHOT.jar:3380-Spigot-8965a50-0ba6b90]
        at net.minecraft.server.network.PlayerConnection.a(PlayerConnection.java:1778) ~[spigot-1.18.1-R0.1-SNAPSHOT.jar:3380-Spigot-8965a50-0ba6b90]
        at net.minecraft.server.network.PlayerConnection.a(PlayerConnection.java:1759) ~[spigot-1.18.1-R0.1-SNAPSHOT.jar:3380-Spigot-8965a50-0ba6b90]
        at net.minecraft.network.protocol.game.PacketPlayInChat.a(PacketPlayInChat.java:46) ~[spigot-1.18.1-R0.1-SNAPSHOT.jar:3380-Spigot-8965a50-0ba6b90]
        at net.minecraft.network.protocol.game.PacketPlayInChat.a(PacketPlayInChat.java:1) ~[spigot-1.18.1-R0.1-SNAPSHOT.jar:3380-Spigot-8965a50-0ba6b90]
        at net.minecraft.network.protocol.PlayerConnectionUtils.lambda$0(PlayerConnectionUtils.java:30) ~[spigot-1.18.1-R0.1-SNAPSHOT.jar:3380-Spigot-8965a50-0ba6b90]
        at net.minecraft.server.TickTask.run(SourceFile:18) ~[spigot-1.18.1-R0.1-SNAPSHOT.jar:3380-Spigot-8965a50-0ba6b90]
        at net.minecraft.util.thread.IAsyncTaskHandler.c(SourceFile:151) ~[spigot-1.18.1-R0.1-SNAPSHOT.jar:3380-Spigot-8965a50-0ba6b90]
        at net.minecraft.util.thread.IAsyncTaskHandlerReentrant.c(SourceFile:23) ~[spigot-1.18.1-R0.1-SNAPSHOT.jar:3380-Spigot-8965a50-0ba6b90]
        at net.minecraft.server.MinecraftServer.b(MinecraftServer.java:1158) ~[spigot-1.18.1-R0.1-SNAPSHOT.jar:3380-Spigot-8965a50-0ba6b90]
        at net.minecraft.server.MinecraftServer.c(MinecraftServer.java:1) ~[spigot-1.18.1-R0.1-SNAPSHOT.jar:3380-Spigot-8965a50-0ba6b90]
        at net.minecraft.util.thread.IAsyncTaskHandler.y(SourceFile:125) ~[spigot-1.18.1-R0.1-SNAPSHOT.jar:3380-Spigot-8965a50-0ba6b90]
        at net.minecraft.server.MinecraftServer.bf(MinecraftServer.java:1137) ~[spigot-1.18.1-R0.1-SNAPSHOT.jar:3380-Spigot-8965a50-0ba6b90]
        at net.minecraft.server.MinecraftServer.y(MinecraftServer.java:1130) ~[spigot-1.18.1-R0.1-SNAPSHOT.jar:3380-Spigot-8965a50-0ba6b90]
        at net.minecraft.util.thread.IAsyncTaskHandler.c(SourceFile:134) ~[spigot-1.18.1-R0.1-SNAPSHOT.jar:3380-Spigot-8965a50-0ba6b90]
        at net.minecraft.server.MinecraftServer.x(MinecraftServer.java:1114) ~[spigot-1.18.1-R0.1-SNAPSHOT.jar:3380-Spigot-8965a50-0ba6b90]
        at net.minecraft.server.MinecraftServer.w(MinecraftServer.java:1038) ~[spigot-1.18.1-R0.1-SNAPSHOT.jar:3380-Spigot-8965a50-0ba6b90]
        at net.minecraft.server.MinecraftServer.lambda$0(MinecraftServer.java:304) ~[spigot-1.18.1-R0.1-SNAPSHOT.jar:3380-Spigot-8965a50-0ba6b90]
        at java.lang.Thread.run(Thread.java:833) [?:?]
Caused by: java.lang.NoClassDefFoundError: com/fazecast/jSerialComm/SerialPort
        at com.foamyguy.myfirstplugin.CommandCheck.onCommand(CommandCheck.java:21) ~[?:?]
        at org.bukkit.command.PluginCommand.execute(PluginCommand.java:45) ~[spigot-api-1.18.1-R0.1-SNAPSHOT.jar:?]
        ... 21 more
Caused by: java.lang.ClassNotFoundException: com.fazecast.jSerialComm.SerialPort
        at org.bukkit.plugin.java.PluginClassLoader.loadClass0(PluginClassLoader.java:147) ~[spigot-api-1.18.1-R0.1-SNAPSHOT.jar:?]
        at org.bukkit.plugin.java.PluginClassLoader.loadClass(PluginClassLoader.java:99) ~[spigot-api-1.18.1-R0.1-SNAPSHOT.jar:?]
        at java.lang.ClassLoader.loadClass(ClassLoader.java:520) ~[?:?]
        at com.foamyguy.myfirstplugin.CommandCheck.onCommand(CommandCheck.java:21) ~[?:?]
        at org.bukkit.command.PluginCommand.execute(PluginCommand.java:45) ~[spigot-api-1.18.1-R0.1-SNAPSHOT.jar:?]
        ... 21 more

我已经解压并查看了构建的 jar 文件,jSerialComm jar 文件已成功包含在我的插件 jar 中:

unzipped jar contents

我需要做什么才能从 Minecraft 插件内部成功使用外部 JAR 文件(特别是 jSerialComm)?或者,是否有一些内置的方法可以让我通过串行端口进行连接和通信,而不需要外部 JAR,因此不需要任何“特殊”的东西来工作?

最佳答案

即使 JAR 存在于您的插件中,JAR 的类也不会加载到类路径中,并且 Spigot 无法访问这些类。

您可以使用插件,例如 maven-shade-plugin ,它将所有类从 API-JAR 复制到您的插件 JAR。

首先,将范围从 provided 设置为 compile

<dependency>
    <groupId>com.fazecast</groupId>
    <artifactId>jSerialComm</artifactId>
    <version>[2.0.0,3.0.0)</version>
    <scope>compile</scope> <!-- -->
</dependency>

然后在 pom.xml 内的 build > plugins 下添加 maven-shade-plugin

<build>
    <!-- ... -->
    <plugins>
      <!-- ... -->
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-shade-plugin</artifactId>
        <version>3.1.0</version>
        <executions>
          <execution>
            <phase>package</phase>
            <goals>
              <goal>shade</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
      <!-- ... -->
    </plugins>
    <!-- ... -->
  </build>

如果您现在构建 jar(例如使用 man clean package),则 target/文件夹中应该有一个“fat-”jar 文件,其中包含 API 的类以及您的类。

之前插件的内容:

├ com
  ├ foamguy
    └ myfirstplugin
      └ ...
├ plugin.yml
└ jSerialComm-xxx.jar

之后的插件内容:

├ com
  ├ foamguy
    └ myfirstplugin
      └ ...
  └ fazecast
    └ jSerialComm
      └ ...
└ plugin.yml

关于java - 来自外部 JAR 的 Minecraft 插件 ClassNotFound 错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70544085/

相关文章:

java - Apache Ignite Cassandra 驱逐

java - 驱动器已满或空间不足的 IOException

java - Applet 需要花费大量时间来加载存档标记中提到的 Jar 文件

linux - 将物理USB端口关联到设备

linux - 使用socat同时嗅探多个串口

java - 通过每个项目的乐观锁定有效地将结果流存储在多个表中

java - 使用 java8 Streams 在列表中合并内部列表

java - 无法在 JDK_HOME 之外创建 jar 文件

java - 如何在 Wildfly/JBoss 的 war 中直接托管 .jar 文件?

linux - 识别从串行终端读取时\r 伪影的原因?