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

Include library for JAXB into JAR file without using Maven

我在 Eclipse 中有一个使用 javax.xml.bind.JAXB 类 的 Java 项目。 从 Eclipse 内部启动应用程序效果很好。 但是,当我将项目导出为 (运行nable) 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 库中,您就可以在所有 classes 中使用 import 关键字来使用新的 jar 文件。

但是,其他人必须在他们的计算机上执行相同的操作才能 运行 一个 class 将您自己的更新导入到 jdk。

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

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

中使用它一样

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

最后,将 classes 解压到这个新创建的文件夹中,并在依赖它的 classes 中使用 import 关键字,就像创建自己的 classes 一样.


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

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

    java -jar MyJar.jar

在命令行中。

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

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

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


问题作者编辑: 以上对我来说效果很好,除了我在两个库(Java 8 中的 javax.xml 和 3.0 版中的 jakarta.xml )处理 @XmlAttribute 注释的方式上遇到了一些小差异。在 javax.xml 中,我可以在 public getter 方法上放置一个注释而无需进一步的参数,例如

@XmlAttribute
public String getDescription() {
   return "";
}

这在 xml 文件中的属性名称为 description 时有效。但是,对于 jakarta.xml 我必须添加属性名称:

@XmlAttribute(name="description")
public String getDescription() {
   return "";
}

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