使用Maven javafx:jlink时出现com.sun.jna.Callback类找不到错误的原因
问题:JavaFX jlink打包后运行出现
ClassNotFoundException: com.sun.jna.Callback 开发JavaFX应用(基于OpenJFX 19 + OpenJDK 11),使用javafx-maven-plugin的javafx:jlink命令打包,应用依赖非模块化的org.pcap4j(该库又依赖com.sun.jna)。手动为两个jar注入module-info.class后jlink执行成功,但运行生成的镜像时出现java.lang.ClassNotFoundException: com.sun.jna.Callback错误,调整模块声明和依赖关系无效,使用requires transitive时还出现Native层崩溃。
相关配置与操作
pom.xml中的JavaFX插件配置
<plugin> <groupId>org.openjfx</groupId> <artifactId>javafx-maven-plugin</artifactId> <version>0.0.8</version> <executions> <execution> <id>default-cli</id> <configuration> <mainClass>${mainclass}</mainClass> <launcher>app</launcher> <jlinkZipName>app</jlinkZipName> <jlinkImageName>app</jlinkImageName> <noManPages>true</noManPages> <stripDebug>true</stripDebug> <noHeaderFiles>true</noHeaderFiles> <stripDebug>true</stripDebug> <compress>2</compress> <launcher>${jlink-image-name}</launcher> <jlinkImageName>${jlink-image-name}</jlinkImageName> <mainClass>${mainclass}</mainClass> </configuration> </execution> </executions> </plugin>
pom.xml中的依赖配置
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <!-- groupId etc. --> <properties> <classifier>linux</classifier> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <javafx-graphics.version>19</javafx-graphics.version> <!-- etc. --> </properties> <!-- Openjfx --> <dependency> <groupId>org.openjfx</groupId> <artifactId>javafx-graphics</artifactId> <version>${javafx-graphics.version}</version> <classifier>${classifier}</classifier> </dependency> <dependency> <groupId>org.openjfx</groupId> <artifactId>javafx-controls</artifactId> <version>${javafx-graphics.version}</version> <classifier>${classifier}</classifier> </dependency> <!-- Pcap4j (non-modular) --> <dependency> <groupId>org.pcap4j</groupId> <artifactId>pcap4j-core</artifactId> <version>1.7.4</version> </dependency> <!-- com.sun.jna needed for Pcap4j (non-modular) --> <dependency> <groupId>net.java.dev.jna</groupId> <artifactId>jna</artifactId> <version>4.0.0</version> </dependency> <!-- logging etc. --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.8.0-beta2</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-simple</artifactId> <version>1.8.0-beta2</version> <scope>test</scope> </dependency> <!-- ... --> </project>
将JNA转为模块化的操作
# 进入项目目录(IntelliJ IDEA) jdeps --generate-module-info target //.../net/java/dev/jna/jna/4.0.0/jna-4.0.0.jar javac --patch-module jna=//.../net/java/dev/jna/jna/4.0.0/jna-4.0.0.jar target/jna/module-info.jna # 进入包含module-info.class的目录 jar uf //.../net/java/dev/jna/jna/4.0.0/jna-4.0.0.jar module-info.class
将Pcap4j转为模块化的操作
# 进入项目目录 jdeps --module-path //path/to/jna-4.0.0.jar://path/to/pcap4j-core-1.7.4-sources.jar ://path/to/slf4j-simple-1.8.0-beta2.jar ://path/to/slf4j-api-1.8.0-beta2.jar --generate-module-info target //path/to/pcap4j-core-1.7.4.jar javac --module-path //path/to/jna-4.0.0.jar ://path/to/slf4j-simple-1.8.0-beta2.jar ://path/to/pcap4j-core-1.7.4-sources.jar ://path/to/slf4j-api-1.8.0-beta2.jar ://path/to/pcap4j-core-1.7.4.jar --patch-module pcap4j.core=//path/to/pcap4j-core-1.7.4.jar target/pcap4j.core/module-info.java # 进入包含module-info.class的目录 jar uf //path/to/pcap4j-core-1.7.4.jar module-info.class
运行应用时的错误
解压app.zip后执行./bin/app,报错如下:
SLF4J: No SLF4J providers were found. SLF4J: Defaulting to no-operation (NOP) logger implementation Exception in Application start method Exiting java.lang.reflect.InvocationTargetException at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.base/java.lang.reflect.Method.invoke(Unknown Source) at javafx.graphics@19/com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(Unknown Source) at javafx.graphics@19/com.sun.javafx.application.LauncherImpl.launchApplication(Unknown Source) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.base/java.lang.reflect.Method.invoke(Unknown Source) at java.base/sun.launcher.LauncherHelper$FXHelper.main(Unknown Source) Caused by: java.lang.RuntimeException: Exception in Application start method at javafx.graphics@19/com.sun.javafx.application.LauncherImpl.launchApplication1(Unknown Source) at javafx.graphics@19/com.sun.javafx.application.LauncherImpl.lambda$launchApplication$2(Unknown Source) at java.base/java.lang.Thread.run(Unknown Source) Caused by: java.lang.NoClassDefFoundError: com/sun/jna/Callback at java.base/java.lang.ClassLoader.defineClass1(Native Method) at java.base/java.lang.ClassLoader.defineClass(Unknown Source) at java.base/java.lang.ClassLoader.defineClass(Unknown Source) at java.base/java.security.SecureClassLoader.defineClass(Unknown Source) at java.base/jdk.internal.loader.BuiltinClassLoader.defineClass(Unknown Source) at java.base/jdk.internal.loader.BuiltinClassLoader.findClassInModuleOrNull(Unknown Source) at java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(Unknown Source) at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(Unknown Source) at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(Unknown Source) at java.base/java.lang.ClassLoader.loadClass(Unknown Source) at pcap4j.core/org.pcap4j.core.PcapHandle$Builder.build(Unknown Source) etc.etc. at javafx.graphics@19/com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(Unknown Source) at javafx.graphics@19/com.sun.javafx.application.PlatformImpl.lambda$runAndWait$12(Unknown Source) at javafx.graphics@19/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(Unknown Source) at java.base/java.security.AccessController.doPrivileged(Native Method) at javafx.graphics@19/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(Unknown Source) at javafx.graphics@19/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(Unknown Source) at javafx.graphics@19/com.sun.glass.ui.gtk.GtkApplication._runLoop(Native Method) at javafx.graphics@19/com.sun.glass.ui.gtk.GtkApplication.lambda$runLoop$11(Unknown Source) ... 1 more Caused by: java.lang.ClassNotFoundException: com.sun.jna.Callback at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(Unknown Source) at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(Unknown Source) at java.base/java.lang.ClassLoader.loadClass(Unknown Source)
JavaFX应用的module-info
module MyApp { requires javafx.controls; requires com.google.gson; requires org.slf4j; requires java.desktop; requires static com.sun.jna; requires pcap4j.core; opens ch.my.app to javafx.graphics, com.google.gson; exports ch.my.app; exports ch.my.app.xx; export etc.etc.; }
已尝试的解决思路
- 调整JNA模块名为
com.sun.jna,同步修改pcap4j.core的requires static jna为requires static com.sun.jna,无效。 - 在pcap4j.core的module-info中使用
requires transitive jna,导致Native层崩溃:
# # A fatal error has been detected by the Java Runtime Environment: # # SIGSEGV (0xb) at pc=0x00007fa9f0807604, pid=192519, tid=192548 # # JRE version: OpenJDK Runtime Environment (11.0.19+7) (build 11.0.19+7-post-Ubuntu-0ubuntu118.04.1) # Java VM: OpenJDK 64-Bit Server VM (11.0.19+7-post-Ubuntu-0ubuntu118.04.1, mixed mode, tiered, compressed oops, g1 gc, linux-amd64) # Problematic frame: # C [jna10034915907313375652.tmp+0x7604] # # Core dump will be written. Default location: Core dumps may be processed with "/usr/share/apport/apport -p%p -s%s -c%c -d%d -P%P -u%u -g%g -- %E" (or dumping to /path/to/app/core.192519) # # An error report file with more information is saved as: # /path/to/app/hs_err_pid192519.log # Aborted (core dumped)
问题原因与解决方案
原因分析
- 模块导出缺失:自动生成的JNA module-info未导出
com.sun.jna等核心包,导致pcap4j运行时无法访问相关类。 requires static误用:requires static仅保证编译期依赖,运行时不会自动包含该模块,但pcap4j运行时必须依赖JNA,因此该声明不适用。- JNA版本兼容性:JNA 4.0.0版本过旧,与Java模块系统兼容性差,易出现Native层加载崩溃问题。
解决方案
1. 修正JNA的module-info
手动编写JNA的module-info,确保导出所有必要包并开放给pcap4j访问:
module com.sun.jna { exports com.sun.jna; exports com.sun.jna.ptr; exports com.sun.jna.platform; opens com.sun.jna to pcap4j.core; opens com.sun.jna.ptr to pcap4j.core; requires java.base; }
重新编译该文件,用jar uf注入到JNA jar中。
2. 修正pcap4j.core的module-info
将依赖声明改为requires transitive com.sun.jna,确保依赖传递到应用模块:
module pcap4j.core { requires transitive com.sun.jna; requires org.slf4j; exports org.pcap4j.core; opens org.pcap4j.core to MyApp; }
重新编译并注入到pcap4j-core jar中。
3. 修正应用的module-info
移除requires static com.sun.jna,通过pcap4j.core的requires transitive自动引入JNA:
module MyApp { requires javafx.controls; requires com.google.gson; requires org.slf4j; requires java.desktop; requires pcap4j.core; opens ch.my.app to javafx.graphics, com.google.gson; exports ch.my.app; exports ch.my.app.xx; // 其他导出/声明 }
4. 升级JNA版本
将JNA版本升级到5.x及以上(如5.13.0),新版本原生支持模块系统,无需手动注入module-info,且能避免Native层崩溃:
<dependency> <groupId>net.java.dev.jna</groupId> <artifactId>jna</artifactId> <version>5.13.0</version> </dependency>
5. 调整javafx-maven-plugin配置
添加modulePath配置,明确依赖模块路径:
<plugin> <groupId>org.openjfx</groupId> <artifactId>javafx-maven-plugin</artifactId> <version>0.0.8</version> <executions> <execution> <id>default-cli</id> <configuration> <mainClass>${mainclass}</mainClass> <launcher>app</launcher> <jlinkZipName>app</jlinkZipName> <jlinkImageName>app</jlinkImageName> <noManPages>true</noManPages> <stripDebug>true</stripDebug> <noHeaderFiles>true</noHeaderFiles> <compress>2</compress> <modulePath> <modulePathElement>${maven.dependency.classpath}</modulePathElement> </modulePath> </configuration> </execution> </executions> </plugin>
6. 重新执行打包命令
清理缓存后重新构建打包:
mvn clean mvn javafx:jlink
内容的提问来源于stack exchange,提问作者Ayame4
相关产品推荐
相关产品推荐

