在不使用 Maven 的情况下将 JAXB 库包含到 JAR 文件中

问题描述

我在 Eclipse 中有一个使用 javax.xml.bind.JAXB 类的 Java 项目。 从 Eclipse 内部启动应用程序可以完美运行。 但是,当我将项目导出为(可运行的)jar 文件并使用 java -jar myfile.jar 运行它时,它会以 java.lang.NoClassDefFoundError: javax/xml/bin/JAXBException 终止。

还在 Eclipse Runnable JAR 文件规范(提取、包、子文件夹)中处理库处理的三个选项也不能解决问题 - 事实上,在任何情况下都没有导出库。

似乎 JAXB 的库(似乎是 rt.jar)不被认为是包含在 jar 文件中的必需库。但是,运行jar文件时,仍然没有找到。 我读过必须将库添加到类路径中,但这对我来说似乎很奇怪,因为 rt.jar 是标准库的一部分。这个库有什么特别之处吗?

目前,我不使用 Maven 或类似的东西来进行依赖和构建管理,如果可能的话,我希望将来避免使用它。我想,也一定有没有Maven的方法

我在 SO 和 Google 上找到了几篇帖子,但无法为我找到解决方案。

非常感谢!

解决方法

最简单的方法是使用嵌入了所需 jaxb 库的 JDK 8(或更旧的 JDK)。困难的方法要求您将 CLASSPATH 变量设置为指向每个所需的 jaxb jar 文件。

根据 https://javaee.github.io/jaxb-v2/doc/user-guide/release-documentation.html#a-2-3-0 的规范,使用 Java 版本 11 或更高版本需要以下 jar。

  • jaxb-api.jar
  • jaxb-core.jar
  • jaxb-impl.jar

关于这个问题的一篇好文章是https://www.jesperdj.com/2018/09/30/jaxb-on-java-9-10-11-and-beyond/

,

我自己也考虑过这个,因为我是 Java 新手。

java 教程 (SE) 中有对扩展机制的描述,但由于 Oracle 已弃用,因此不再使用。看,只是为了知道我在说什么:https://docs.oracle.com/javase/tutorial/ext/index.html

简而言之,这个扩展是什么:只需将您的 jar 文件放入 jdk 库中,您就可以在所有类中使用 import 关键字来使用新的 jar 文件。

然而,其他人必须在他们的计算机上做同样的事情来运行一个类,将你自己的更新导入到 jdk。

Maven 做类似上面的事情。当您构建应用程序时,它会在 pom 文件中搜索其他 jar 文件应包含在您的 jar 中。因此,它可以在任何地方运行。

查看此问题的另一种方法是您应该尝试做的答案。 在没有 pom 结构的情况下执行 Maven 所做的更笨拙的方法是在 src 文件夹中创建一个新文件夹并复制 jakarta.xml.bind-api.jar。就像你创建一个对象(aJavaBean)并需要在另一个类中使用它一样。

您需要包含在库中的文件位于: https://repo1.maven.org/maven2/com/sun/xml/bind/jaxb-ri/3.0.0/jaxb-ri-3.0.0.zip

最后,提取这个新创建的文件夹中的类,并在依赖它的类中使用 import 关键字,就像创建自己的类一样。


您应该尝试的另一件事是在制作 jar 时使用清单文件。 https://docs.oracle.com/javase/tutorial/deployment/jar/manifestindex.html

本教程展示了如何将类路径包含到您需要作为依赖项运行的文件中。确保您需要的一切都在新创建的 jar 文件中。 此外,在清单中设置入口点,这样您的应用程序就可以使用

    java -jar MyJar.jar

在命令行中。

,

如评论中所述,Eclipse 可能使用与您的系统不同的 Java 版本(默认情况下)。 JRE 11 中不提供 JAXB API 和实现。

要处理所有版本的 Java,最好的选择是:

  • 下载 JAXB RI 发行版。现在我将选择 3.0 版(它与 Java 8 中的二进制文件不兼容,因为它使用 jakarta.xml 而不是 javax.xml 作为包名称),如 Juliano 的回答:

https://repo1.maven.org/maven2/com/sun/xml/bind/jaxb-ri/3.0.0/jaxb-ri-3.0.0.zip

  • jakarta.activation.jar 文件夹中的 jakarta.xml.bind-api.jarjaxb-core.jarjaxb-impl.jarmod 4 个文件复制到您项目的库文件夹中(假设 {{ 1}}),
  • 将 4 个库添加到项目的“构建路径”
  • 确保在整个代码中使用 JAXB 3.0(注释和类的包以 lib 开头)
  • 在 Eclipse 中运行应用程序一次,因此它会更新运行配置(或自己更新运行配置的类路径),
  • 将项目导出为 JAR 文件。

在 Eclipse 提出的三个导出选项中:“提取所需的库” 将创建一个所谓的胖 jar(所有内容都在一个 JAR 文件中)。它可以工作,但会删除 JAXB jar 中的许可证通知(因此无法分发)。 “复制所需的库” 是您最好的选择,但是您必须将 jar 文件与子文件夹一起移动。 _"。"package required libraries" 将不起作用,因为 jar 中的 jar 不会被 JVM 读取(与 WAR 包中的 JAR 不同)。


问题作者编辑: 除了我在两个库(Java 8 中的 javax.xml 和 3.0 版中的 jakarta.xml)处理 jakarta.xml 注释的方式上遇到了一些细微的差异之外,以上对我来说效果很好。在 javax.xml 中,我可以在公共 getter 方法上放置一个没有更多参数的注释,例如

@XmlAttribute

这在 xml 文件中的属性名称为 @XmlAttribute public String getDescription() { return ""; } 时有效。但是,使用 jakarta.xml 我必须添加属性的名称:

description

以防万一,其他人也遇到同样的问题。