将OWL API JAR打包进可执行JAR后运行触发空指针异常
OWL API v5.1.19打包可执行JAR后运行抛出NullPointerException的解决办法
问题描述
开发基于OWL API(v5.1.19)的Java应用,在Eclipse中运行正常,但打包为可执行JAR后运行时,出现如下异常:
Exception in thread "main" 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 org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader.main(JarRsrcLoader.java:61) Caused by: java.lang.NullPointerException at java.base/java.util.Objects.requireNonNull(Unknown Source) at java.base/java.util.Optional.<init>(Unknown Source) at java.base/java.util.Optional.of(Unknown Source) at java.base/java.util.stream.FindOps$FindSink$OfRef.get(Unknown Source) at java.base/java.util.stream.FindOps$FindSink$OfRef.get(Unknown Source) at java.base/java.util.stream.FindOps$FindOp.evaluateSequential(Unknown Source) at java.base/java.util.stream.AbstractPipeline.evaluate(Unknown Source) at java.base/java.util.stream.ReferencePipeline.findAny(Unknown Source) at org.semanticweb.owlapi.utilities.Injector.getImplementation(Injector.java:246) at org.semanticweb.owlapi.apibinding.OWLManager.createOWLOntologyManager(OWLManager.java:119) at utils.OntologyUtils.loadOntology(OntologyUtils.java:251) at persistence.OntologyDAO.loadWholeOntology(OntologyDAO.java:31) at application.OntologyHandler.<init>(OntologyHandler.java:21) at application.RecommendationAlgorithm.<init>(RecommendationAlgorithm.java:42) at ui.MainPage.<init>(MainPage.java:37) at ui.TestUI.main(TestUI.java:9)
已确认所有OWL API依赖都已打包进JAR。
问题根源
这个空指针异常是OWL API的Injector类查找实现类时触发的,核心原因是打包过程中丢失了OWL API的SPI配置文件或同名SPI文件被错误覆盖。OWL API依赖Java SPI(服务提供者接口)加载各类实现类,这些配置文件存放在META-INF/services目录下。Eclipse自带的打包工具(如Jar-in-Jar Loader)在合并多个依赖的SPI文件时,会直接覆盖而非追加内容,导致Injector找不到对应的实现类,最终抛出空指针。
解决方案
方案1:用Maven/Gradle打包(推荐)
构建工具能自动处理SPI文件合并,避免手动操作的失误:
Maven配置(maven-shade-plugin)
在pom.xml中添加插件配置:
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.4.1</version> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <transformers> <!-- 合并所有SPI配置文件 --> <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/> <!-- 指定主类路径 --> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <mainClass>ui.TestUI</mainClass> </transformer> </transformers> </configuration> </execution> </executions> </plugin> </plugins> </build>
执行mvn package命令,生成的shaded JAR即可正常运行。
Gradle配置
在build.gradle中添加:
plugins { id 'java' id 'application' } application { mainClass = 'ui.TestUI' } jar { duplicatesStrategy = DuplicatesStrategy.INCLUDE from { configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } } manifest { attributes 'Main-Class': 'ui.TestUI' } // 合并META-INF/services下的SPI文件 into('META-INF/services') { from { configurations.runtimeClasspath.collect { zipTree(it).matching { include 'META-INF/services/**' } } } eachFile { duplicatesStrategy = DuplicatesStrategy.INCLUDE } } }
执行gradle build,在build/libs目录下获取可执行JAR。
方案2:手动修复Eclipse打包的JAR
如果必须用Eclipse打包,需要手动合并SPI文件:
- 解压打包好的JAR,进入
META-INF/services目录。 - 找出所有
org.semanticweb.owlapi.*开头的配置文件,比如org.semanticweb.owlapi.model.OWLOntologyManagerFactory。 - 将各个依赖JAR中对应的同名SPI文件内容追加到同一个文件中(不要覆盖原有内容)。
- 重新压缩JAR,确保合并后的SPI文件处于正确路径。
方案3:手动指定OWL API实现类
绕过SPI机制,直接创建OWL API实例:
// 替换原有的OWLManager.createOWLOntologyManager() OWLOntologyManager manager = new OWLManagerImpl(); // 手动添加所需组件 manager.addOntologyProvider(new FileDocumentSourceProvider()); manager.addOntologyProvider(new StreamDocumentSourceProvider()); // 注册需要的本体格式 manager.getOntologyFormatRegistry().registerFormat(new RDFXMLDocumentFormatFactory()); manager.getOntologyFormatRegistry().registerFormat(new OWLXMLDocumentFormatFactory()); // 根据需求添加其他格式或组件
这种方式无需依赖SPI,但需要手动配置所有用到的OWL API组件,适合功能简单的项目。
内容的提问来源于stack exchange,提问作者Basma Moukhtar Hussein
相关产品推荐
相关产品推荐

