Java8迁移至Java11及JEE转JakartaEE时JAXB相关故障求助
Java 8→Java11+JEE→JakartaEE+Tomcat10迁移JAXB问题解决方案
你遇到的运行时javax.xml.bind类找不到、双JAXB依赖冲突的核心原因是Spring 4.3以及对应版本的Spring OXM、Spring WS均未提供Jakarta EE原生支持,所有XML绑定相关的逻辑硬编码依赖javax.xml.bind包路径。
1. 底层依赖未支持Jakarta EE的适配方案
- 方案一:降级过渡适配
放弃源码层面直接全量替换为jakarta.xml.bind的操作,先仅完成Java 8到Java 11的迁移,仍保留javax.xml.bind的全套依赖,待升级到支持Jakarta EE的Spring版本后再做包名迁移。
具体操作:- 回退自研代码中所有
javax.xml.bind到jakarta.xml.bind的import修改 - 用javax版的xjc重新生成XSD对应的类文件
- 引入Java 11缺失的javax.xml.bind相关依赖:
<!-- JAXB API --> <dependency> <groupId>javax.xml.bind</groupId> <artifactId>jaxb-api</artifactId> <version>2.3.1</version> </dependency> <!-- JAXB实现 --> <dependency> <groupId>com.sun.xml.bind</groupId> <artifactId>jaxb-impl</artifactId> <version>2.3.6</version> <scope>runtime</scope> </dependency> <!-- xjc相关依赖如果需要编译期生成代码 --> <dependency> <groupId>com.sun.xml.bind</groupId> <artifactId>jaxb-xjc</artifactId> <version>2.3.6</version> <scope>provided</scope> </dependency> - 完成Java 11适配运行正常后,先将Spring全家桶升级到支持Jakarta EE的版本:Spring Framework 6+、Spring WS 4+,该版本已经全量替换为
jakarta.xml.bind依赖,之后再做全量包名迁移适配Tomcat 10。
- 回退自研代码中所有
- 方案二:桥接适配(无需升级Spring版本)
使用开源的javax-jakarta桥接包,将Spring OXM调用javax.xml.bind的请求转发到jakarta.xml.bind实现上,同时避免双JAXB包的冲突。
具体操作:- 排除所有传递引入的
javax.xml.bind相关依赖 - 引入兼容桥接包:
org.eclipse.persistence:org.eclipse.persistence.moxy作为JAXB实现,该实现同时支持javax和jakarta两种包名的注解扫描 - 保留已生成的jakarta包名的XSD类文件,在Spring OXM的JAXB上下文配置中指定扫描的包路径,避免Spring自动扫描到重复的ObjectFactory:
@Bean public Jaxb2Marshaller marshaller() { Jaxb2Marshaller marshaller = new Jaxb2Marshaller(); // 仅指定你自己生成的jakarta包路径下的XSD类所在包,不要包含其他路径 marshaller.setPackagesToScan("com.yourcompany.generated.jakarta"); // 强制指定使用MOXy作为JAXB实现 Map<String, Object> props = new HashMap<>(); props.put(javax.xml.bind.JAXBContext.JAXB_CONTEXT_FACTORY, "org.eclipse.persistence.jaxb.JAXBContextFactory"); marshaller.setJaxbContextProperties(props); return marshaller; }
- 排除所有传递引入的
2. 遗漏的迁移步骤说明
你目前的操作确实缺少两个核心环节:
- 没有做依赖树的全量排查:Spring 4.3全家桶本身内置依赖
javax.xml.bind,你直接替换为jakarta版本的JAXB后,Spring的硬编码调用找不到对应类,这是报错的直接诱因 - 没有做JAXB上下文的显式配置:同时引入两个版本的JAXB后,Spring WS默认会扫描全类路径下的ObjectFactory,没有指定包路径的情况下会把两个版本的实现都加载,才会报同命名空间下的类型冲突
3. 该场景下的代码迁移建议
- 优先选择升级Spring版本的方案,Spring 4.3已经停止维护多年,本身存在大量安全漏洞,升级到Spring 6+、Spring WS 4+是长期稳定的方案,升级完成后所有jakarta包的适配都是官方原生支持,不需要额外的桥接配置
- 如果暂时无法升级Spring版本,不要同时引入两套JAXB依赖,使用MOXy作为统一的JAXB实现,显式指定JAXB上下文的扫描范围,避免类冲突
- 迁移过程中可以用
mvn dependency:tree(Maven)或gradlew dependencies(Gradle)排查所有传递引入的javax.xml.bind相关依赖,全部做排除处理,避免重复引入
内容的提问来源于stack exchange,提问作者Markus
相关产品推荐
相关产品推荐

