java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > jdk8升级jdk21 cxf报错的踩坑

关于jdk8升级jdk21 cxf报错的踩坑记录

作者:照猫画狐

在升级Java项目时,从JDK1.8和Spring2迁移到JDK21和Spring3后,遇到了JAXBException错误,原因是从JDK11开始移除了jaxb模块,而cxf在编译动态客户端时默认classpath不包含必要的类,解决方法是在jar包同级目录创建libs并添加jakarta.xml.bind-api

项目场景

听说jdk21有很多实用新特性,就想弄个玩玩,闲来无事把公司项目从spring2+jdk1.8直升到spring3+jdk21,折腾两天升级完了,本以为就这么简单结束了。

直到把项目发布到服务器测试调用第三方接口,一直报错:

jakarta.xml.bind.JAXBException: "com.xx.xx" 不包含 ObjectFactory.class 或 jaxb.index

各种百度,翻看源码,折腾两个星期也未能解决问题,一度想要放弃。

经过这么长时间折腾,我发现在IDEA中调用接口就不会报错,一旦打成jar使用java -jar执行就一定会报错,这一定是jvm环境问题!

我用jconsole连接两种不同场景下的jvm,经过自己反复对比调试,终于发现了问题所在。

问题描述

使用cxf创建动态客户端时报错:

jakarta.xml.bind.JAXBException: "com.xx.xx" 不包含 ObjectFactory.class 或 jaxb.index

// 创建动态客户端
JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();
Client client = dcf.createClient(addr);
client.invoke(methodName, param);

原因分析

从jdk11起移除了jaxb模块,cxf编译动态客户端代码时,默认的classpath为java.class.path

当打包成jar后,java.class.path指定的目录就是当前运行的jar

由于jdk11也移除了rt.jar、tool.jar,cxf编译动态客户端java文件时,会因为找不到依赖的jar包报错

解决方案

1. 在jar包同级目录下新建一个libs目录,放入jakarta.xml.bind-api-4.0.2.jar

2. 项目启动时,把cxf编译动态客户端所依赖的jar包添加到java.class.path中。

// 获取当前jar所在目录
String jarPath = (System.getProperty("user.dir")).replaceAll("\\\\", "/").replace("file:/", "/");
String classPath = jarPath + "/libs/jakarta.xml.bind-api-4.0.2.jar";

// 因为从jdk11起移除了jaxb模块,cxf编译动态客户端代码时,默认的classpath为java.class.path,由于jdk11也移除了rt.jar、tool.jar,会导致编译异常,报错:
// jakarta.xml.bind.JAXBException: "com.xx.xx" 不包含 ObjectFactory.class 或 jaxb.index
System.setProperty("java.class.path", System.getProperty("java.class.path") + ";" + classPath + ";");

上面提供的示例程序,仅供参考

参考链接

[CXF-7932] JaxWsDynamicClientFactory in Spring Boot fat JAR with JDK11 leads to JAXBException ... doesnt contain ObjectFactory.class or jaxb.index - ASF JIRA

[CXF-7925] Dynamic WSDL Client creation fails on JDK 11 because it cannot compile generated classes - ASF JIRA

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文