如何解决java.lang.NoClassDefFoundError: javax/xml/bind/JAXBException?

1233
我有一些代码,使用了作为Java 6/7/8 JDK的一部分提供的JAXB API类。当我在Java 9中运行相同的代码时,运行时会出现指示找不到JAXB类的错误。
JAXB类自Java 6以来已经作为JDK的一部分提供,那么为什么Java 9找不到这些类了呢?

2
这个回答中的附加部分与这些API的迁移有关。 - Naman
10
使用Java 8构建代码可以让你的代码编译通过,但是当你尝试在Java 9+上运行已编译的代码时,会因为缺少JAX-B而失败。 - Andy Guibert
2
对于Java 11,本文的解决方案是最新的:https://crunchify.com/java-11-and-javax-xml-bind-jaxbcontext/ - Eric
请参见 http://wiki.bitplan.com/index.php/Java8 上的 Java 8 相关编程内容。 - Wolfgang Fahl
这个回答解决了你的问题吗?使用Java EE API替换已弃用的JPMS模块 - 9ilsdx 9rvj 0lo
显示剩余2条评论
45个回答

1782

JAXB API被视为Java EE API,因此在Java SE 9中不再包含在默认类路径中。在Java 11中,它们完全从JDK中删除。

Java 9引入了模块的概念,默认情况下,java.se聚合模块可在类路径(或者说模块路径)上使用。正如其名称所示,java.se聚合模块不包括传统上随Java 6/7/8捆绑的Java EE API。

幸运的是,JDK 6/7/8中提供的这些Java EE API仍然存在于JDK中,但默认情况下不在类路径上。以下模块提供了额外的Java EE API:

java.activation
java.corba
java.transaction
java.xml.bind  << This one contains the JAXB APIs
java.xml.ws
java.xml.ws.annotation

快速而简单的解决方案:(仅适用于JDK 9/10)

为了在运行时使JAXB API可用,请指定以下命令行选项:

--add-modules java.xml.bind

但我仍然需要使用Java 8!!!

如果你尝试使用较旧的JDK指定 --add-modules ,它将失败,因为它是一个无法识别的选项。我建议采取以下两种方法之一:

  1. 您可以使用 JDK_JAVA_OPTIONS 环境变量设置任何仅适用于Java 9+的选项。这个环境变量会被Java 9+的java启动器 自动读取
  2. 您可以添加-XX:+IgnoreUnrecognizedVMOptions以使JVM静默地忽略未识别的选项,而不是崩溃。但要小心!您使用的任何其他命令行参数将不再由JVM验证。此选项适用于Oracle/OpenJDK和IBM JDK(截至JDK 8sr4)。

替代快速解决方案:(仅适用于JDK 9/10)

请注意,您可以通过指定--add-modules java.se.ee选项在运行时使所有上述Java EE模块可用。 java.se.ee模块是一个聚合模块,包括java.se.ee以及上述Java EE API模块。请注意,这在Java 11上不起作用,因为java.se.ee在Java 11中已被删除。


适当的长期解决方案:(JDK 9及以上版本)

上述Java EE API模块都标有@Deprecated(forRemoval=true),因为它们在Java 11计划删除。因此,在Java 11中,--add-module方法将不再默认工作。

在Java 11及其后续版本中,您需要在类路径或模块路径中包含自己的Java EE API副本。例如,您可以像这样将JAX-B API添加为Maven依赖项:

<!-- API, java.xml.bind module -->
<dependency>
    <groupId>jakarta.xml.bind</groupId>
    <artifactId>jakarta.xml.bind-api</artifactId>
    <version>2.3.2</version>
</dependency>

<!-- Runtime, com.sun.xml.bind module -->
<dependency>
    <groupId>org.glassfish.jaxb</groupId>
    <artifactId>jaxb-runtime</artifactId>
    <version>2.3.2</version>
</dependency>

更多有关JAXB的详细信息,请查看JAXB参考实现页面

有关Java模块化的完整详情,请参阅JEP 261: 模块系统

截至2022年7月,bind-api和jaxb-runtime的最新版本为4.0.0。因此,您也可以使用

    <version>4.0.0</version>

如果您选择使用这些依赖关系条款,那么包名称已从javax.xml.bind...更改为jakarta.xml.bind...。您需要修改源代码以使用这些JAR的后续版本。

对于Gradle或Android Studio开发人员:(JDK 9及以上)

将以下依赖项添加到您的build.gradle文件中:

dependencies {
    // JAX-B dependencies for JDK 9+
    implementation "jakarta.xml.bind:jakarta.xml.bind-api:2.3.2"
    implementation "org.glassfish.jaxb:jaxb-runtime:2.3.2"
}

9
如果Java EE API模块被标记为弃用,那么这是否意味着在Java 10中运行时将不再可用JAXB?这似乎是一步倒退。我们将不得不回到包含JAXB作为依赖项的6之前的做法。 - Michael
4
使用 --add-modules java.se.ee 或 --add-modules ALL-SYSTEM 作为解决方法并不被建议,根据迁移指南(https://docs.oracle.com/javase/9/migrate/)中的 Modules Shared with Java EE Not Resolved by Default --> point 1 部分。 - justMe
7
随着Java 10的正式发布,我们可以确认add-modules方法仍将起作用。根据JEP-320,javax.xml.bind和其他JavaEE类将在Java 11中被移除。 - Joep Weijers
14
现在Java 11已经发布,java.se.ee模块已被移除,所以--add-modules的解决方案不再适用。取而代之的是使用推荐的解决方案:将JAXB作为单独的依赖项添加。 - Jesper
53
我已经添加了这些依赖项,但仍然出现相同的错误。你有什么想法为什么会这样? - João Vieira
显示剩余30条评论

405
在我的情况下(Spring Boot fat jar),我只需在pom.xml中添加以下内容。
<dependency>
    <groupId>javax.xml.bind</groupId>
    <artifactId>jaxb-api</artifactId>
    <version>2.3.1</version>
</dependency>

14
仅供参考 https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-with-Java-9 - Tuno
10
像这样添加 Gradle 依赖 testCompile('javax.xml.bind:jaxb-api') 对我有效。 - pamcevoy
6
像 @pamcevoy 提到的那样,在使用Spring Boot时不需要指定jaxb-api的版本。Boot会自动管理版本。 - Marcel Overdijk
4
我建议在这种情况下使用<scope>runtime</scope> - VladS
7
@Tuno提供的链接对我来说无效,修复后的链接是:https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-with-Java-9-and-above - Cisco
显示剩余4条评论

114

JDK版本 >= 9 的清洁解决方案

您需要将两个依赖项添加到构建中:

  • jaxb-api
  • jaxb 实现

作为实现,我选择使用 glassfish 的参考实现来摆脱旧的 com.sun 类/库。因此,在我的 Maven 构建中添加了以下内容:

<dependency>
  <groupId>javax.xml.bind</groupId>
  <artifactId>jaxb-api</artifactId>
  <version>2.3.1</version>
</dependency>

<dependency>
  <groupId>org.glassfish.jaxb</groupId>
  <artifactId>jaxb-runtime</artifactId>
  <version>2.3.1</version>
</dependency>

请注意,从2.3.1版本开始,您无需再添加javax.activation。(请参见https://github.com/eclipse-ee4j/jaxb-ri/issues/1222)。


javax.xml.bind 模块真的是必要的吗?我的 JDK 11 代码在没有它的情况下运行正常。 - k.liakos
@k.liakos 我不确定。 jaxb-runtime jar 和 api-jar 不共享相同的类/包。我猜这取决于你的代码。如果你的代码没有使用 'javax.xml.bind' 包中的类,则可能不需要它。本主题的讨论是找不到 'javax/xml/bind/JAXBException';这个类只在 jaxb-api 中。 - Sebastian Thees
2
在Java 12中,多模块项目可以完美运行。 - Heril Muratovic
5
适用于JDK 11。 - Hrvoje T
在我的项目中,可写的pom.xml文件在哪里?我的所有pom.xml文件都是只读的。我需要创建另一个吗?如果需要,我应该在哪里创建它? @SebastianThees - Surajkaran Meghwanshi

89

对我来说,这些解决方案在最近的JDK 9.0.1中都不起作用。

我发现这个依赖项列表足以实现适当的功能,因此您不需要显式指定--add-module(尽管它在这些依赖项的pom中已经被指定)。唯一需要做的就是指定这个依赖项列表:

<dependencies>
    <dependency>
        <groupId>javax.xml.bind</groupId>
        <artifactId>jaxb-api</artifactId>
        <version>2.3.0</version>
    </dependency>
    <dependency>
        <groupId>com.sun.xml.bind</groupId>
        <artifactId>jaxb-impl</artifactId>
        <version>2.3.0</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jaxb</groupId>
        <artifactId>jaxb-runtime</artifactId>
        <version>2.3.0</version>
    </dependency>
    <dependency>
        <groupId>javax.activation</groupId>
        <artifactId>activation</artifactId>
        <version>1.1.1</version>
    </dependency>
</dependencies>

2
对于JDK 8,请从上述中删除jaxb-core和jaxb-impl。 - foo
4
@Anil,这是Maven配置的pom.xml文件。如果你不知道它是什么,最好从头开始学起。 - Andremoniy
8
发生了非法的反射访问操作 警告:com.sun.xml.bind.v2.runtime.reflect.opt.Injector(file:/C:/Users/eis/.m2/repository/com/sun/xml/bind/jaxb-impl/2.3.0/jaxb-impl-2.3.0.jar)对java.lang.ClassLoader.defineClass(java.lang.String,byte [],int,int)方法进行了非法反射访问 警告:请考虑向com.sun.xml.bind.v2.runtime.reflect.opt.Injector的维护者报告此问题 警告:使用--illegal-access=warn来启用更多非法反射访问操作的警告 警告:在将来的版本中,所有非法访问操作都将被拒绝 - Stefan
1
这对我在JDK 9.0.4上有效(我通过Maven插件调用了与JAXB相关的代码,使用的是Maven 3.5.3)。虽然我会将<dependency>中的javax.activation-api作为最后一个依赖项。 - scrutari
2
太棒了!我遇到了这样的情况——一个Spring Boot应用在Mac上IntelliJ CE可以运行但在Eclipse上不能,在Win10上的Eclipse却可以,但在IntelliJ CE上不能。能够在两个平台上使用一个IDE是一种优势。 - kometen
显示剩余7条评论

49

这对我起作用:

<dependency>
    <groupId>javax.xml.bind</groupId>
    <artifactId>jaxb-api</artifactId>
    <version>2.3.0</version>
</dependency>
<dependency>
    <groupId>org.eclipse.persistence</groupId>
    <artifactId>eclipselink</artifactId>
    <version>2.7.0</version>
</dependency>

更新

如@Jasper所建议的那样,为了避免依赖整个EclipseLink库,您也可以只依赖EclipseLink MOXy:

Maven

<dependency>
    <groupId>org.eclipse.persistence</groupId>
    <artifactId>org.eclipse.persistence.moxy</artifactId>
    <version>2.7.3</version>
</dependency>

Gradle

compile group: 'org.eclipse.persistence', name: 'org.eclipse.persistence.moxy', version: '2.7.3'
作为我的Java 8应用程序的依赖项,它可以生成一个*.jar文件,该文件可以在JRE 8或JRE 9上运行而无需任何其他参数。
另外,在使用JAXB API之前需要在某个地方执行此操作:
System.setProperty("javax.xml.bind.JAXBContextFactory", "org.eclipse.persistence.jaxb.JAXBContextFactory");

目前为止,作为一种解决方法表现良好。但看起来并不完美...


6
仅为获取JAXB API而添加 org.eclipse.persistence:eclipselink 是一种非常重的依赖,除非您已经在使用eclipselink? - Andy Guibert
4
是的,它很重(约9MB),而且我已经在使用它了。我提到过这只是一个备选解决方案,适用于那些可能暂时需要在相同的jar/war中同时使用8和9 JRE,而不提供命令行参数的人。 - Mikhail Kholodkov
2
为了在JDK 8和9之间实现互操作性,我建议使用-XX:+IgnoreUnrecognizedVMOptions命令行选项(已更新我的答案,包含详细信息)。 - Andy Guibert
System.setProperty("javax.xml.bind.JAXBContextFactory", "org.eclipse.persistence.jaxb.JAXBContextFactory"); 对我不起作用。 - David Brossard
1
为避免依赖整个EclipseLink库,您也可以仅依赖于EclipseLink MOXy:groupId org.eclipse.persistence,artifactId org.eclipse.persistence.moxy - Jesper
显示剩余4条评论

39

这是因为您使用的是JDK 9或更高版本,只需将以下内容添加到您的pom文件中即可解决该问题。

<dependency>
  <groupId>javax.xml.bind</groupId>
  <artifactId>jaxb-api</artifactId>
  <version>2.3.0</version>
</dependency>

2
我在Spring Boot指南中经常遇到这个问题...非常感谢。 - masterxilo
2
@Cesar Rodriguez T,我尝试了一个Swagger示例,并且编译成功了,但是运行时出现了错误。我使用了所选答案,其中包括更多的依赖项,这样就可以正常运行了。 - PatS
在您的项目的pom.xml文件中 - Cesar Rodriguez
在我的项目中,我发现了两个 pom.xml 文件,但它们只能以可读格式而不能被写入,我应该怎么办?@CesarRodriguez - Surajkaran Meghwanshi

32
为了解决这个问题,我在我的项目中导入了一些JAR文件:
  • javax.activation-1.2.0.jar

http://search.maven.org/remotecontent?filepath=com/sun/activation/javax.activation/1.2.0/javax.activation-1.2.0.jar

  • jaxb-api-2.3.0.jar

http://search.maven.org/remotecontent?filepath=javax/xml/bind/jaxb-api/2.3.0/jaxb-api-2.3.0.jar

  • jaxb-core-2.3.0.jar

http://search.maven.org/remotecontent?filepath=com/sun/xml/bind/jaxb-core/2.3.0/jaxb-core-2.3.0.jar

  • jaxb-impl-2.3.0.jar

http://search.maven.org/remotecontent?filepath=com/sun/xml/bind/jaxb-impl/2.3.0/jaxb-impl-2.3.0.jar

  1. 下载上述文件并将它们复制到项目中的libs文件夹中
  2. 在Java Build Path中添加导入的JAR文件

4
请注意,com.sun.xml.bind 依赖项已经过时,仅提供向后兼容性。建议使用等效的 org.glassfish.jaxb 依赖项,正如其他答案中所提到的那样。 - Jesper
这对我没用。它抛出了一个错误,并说找不到特定的类。 - RamenChef
1
当我在Mint 19.2 (Ubuntu 18.04基础)中部署Grails 3.4.10应用程序时,将它们放入tomcat9 / lib文件夹下对我有用。 - Mohamad Fakih
没有起作用,反而引发了更多的错误,需要包含其他几个jar文件。我的是针对jdk8的。 - vibhor vaish

20
在编译和运行时,添加开关--add-modules java.xml.bind
javac --add-modules java.xml.bind <java file name>

java --add-modules java.xml.bind <class file>

您还可以在以下链接中了解有关JDK 9模块的良好介绍: https://www.youtube.com/watch?v=KZfbRuvv5qc


18

在我的Debian 10上开发Java项目时,我遇到了这个问题。

每次启动应用程序时,日志文件中都会抛出以下错误:

java.lang.NoClassDefFoundError: javax/xml/bind/JAXBException

以下是解决方法:

这个问题通常是由于类路径中缺少JAXB库(Java Architecture for XML Binding)引起的。JAXB包含在Java SE 10或更早版本中,但从Java 11或新版本中删除 - 移至Jakarta EE项目的Java EE下。

所以,我使用以下命令检查了我的Java版本:

java --version

然后它给了我这个输出结果

openjdk 11.0.8 2020-07-14
OpenJDK Runtime Environment (build 11.0.8+10-post-Debian-1deb10u1)
OpenJDK 64-Bit Server VM (build 11.0.8+10-post-Debian-1deb10u1, mixed mode, sharing)
我遇到了 JAXBException 错误,因为我使用的是 Java 11,而该版本不包含 JAXB 库(Java Architecture for XML Binding)。为了解决这个问题,我需要将 JAXB API 库添加到我的 Tomcat 安装目录下的 lib (/opt/tomcat/lib) 目录中。
sudo wget https://repo1.maven.org/maven2/javax/xml/bind/jaxb-api/2.4.0-b180830.0359/jaxb-api-2.4.0-b180830.0359.jar

然后我将其从jaxb-api-2.4.0-b180830.0359.jar重命名为jaxb-api.jar

sudo mv jaxb-api-2.4.0-b180830.0359.jar jaxb-api.jar

注意:确保更改权限以允许Tomcat访问该文件,并将所有权更改为tomcat

sudo chown -R tomcat:tomcat /opt/tomcat
sudo chmod -R 777 /opt/tomcat/

然后我重新启动了tomcat服务器:

sudo systemctl restart tomcat

资源: [已解决] java.lang.NoClassDefFoundError: javax/xml/bind/JAXBException

就这些。


15

我也在使用Java 11时遇到了ClassNotFoundException:javax.xml.bind.DatatypeConverter。

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.1</version>
</dependency>

我尝试了所有添加javax.xml.bind:jaxb-api或spring boot jakarta.xml.bind-api的方法...我在jjwt版本0.10.0中找到了修复方法的提示...但最重要的是,现在jjwt包已经被拆分!

因此,请参考这个链接:https://github.com/jwtk/jjwt/issues/510

简单说,如果你使用:

Java11和 jjwt 0.9.x并且 你面对ClassNotFoundException:javax.xml.bind.DatatypeConverter问题,

请使用

jjwt版本0.11.x,但使用已拆分的包:https://github.com/jwtk/jjwt#install

由于它们拆分了包,你的Maven将无法找到jjwt依赖的更高版本。

干杯。


使用 io.jsonwebtoken 版本 0.9.1 的 jjwt 在 Java 16 中也导致了相同的错误。根本原因与 Java 11 相同。在此处使用版本为 0.10.7 的 jjwt-api 和 jjwt-impl(来自 io.jsonwebtoken)解决了该问题。 - Luciano Brum

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接