com.aliyun.mns.common.ClientException: Cannot invoke "java.lang.reflect.Method.invoke(Object, Obj...

背景

使用了阿里云的MNS服务的sdk,将项目从 Java8 升级到 Java17,MNS拉取消息时出现该报错。

com.aliyun.mns.common.ClientException: Cannot invoke "java.lang.reflect.Method.invoke(Object, Object[])" because "com.sun.xml.bind.v2.runtime.reflect.opt.Injector.defineClass" is null
    at com.aliyun.mns.common.http.ExceptionResultParser.parse(ExceptionResultParser.java:66) ~[aliyun-sdk-mns-1.1.10.jar:na]
    at com.aliyun.mns.common.http.ExceptionResultParser.parse(ExceptionResultParser.java:31) ~[aliyun-sdk-mns-1.1.10.jar:na]
    at com.aliyun.mns.common.http.HttpCallback.handleResult(HttpCallback.java:165) ~[aliyun-sdk-mns-1.1.10.jar:na]
    at com.aliyun.mns.common.http.HttpCallback.buildResponseMessage(HttpCallback.java:138) ~[aliyun-sdk-mns-1.1.10.jar:na]
    at com.aliyun.mns.common.http.HttpCallback.completed(HttpCallback.java:99) ~[aliyun-sdk-mns-1.1.10.jar:na]
    at com.aliyun.mns.common.http.HttpCallback.completed(HttpCallback.java:44) ~[aliyun-sdk-mns-1.1.10.jar:na]
    at org.apache.http.concurrent.BasicFuture.completed(BasicFuture.java:122) ~[httpcore-4.4.13.jar:4.4.13]
......

分析

从 Java8 升级到 Java17 后,javax 的相关内容都已经从 JDK 中移除,所以推测该问题为 JAXB 实现找不到。通过阿里云的 MNS文档 找到了相关提示内容

如果您使用的Java版本是Java 9及以上的版本,则需要添加以下JAXB相关依赖。

<dependency>
   <groupId>javax.xml.bind</groupId>
   <artifactId>jaxb-api</artifactId>
   <version>2.3.1</version>
</dependency>
<dependency>
   <groupId>javax.activation</groupId>
   <artifactId>activation</artifactId>
   <version>1.1.1</version>
</dependency>
<dependency>
   <groupId>org.glassfish.jaxb</groupId>
   <artifactId>jaxb-runtime</artifactId>
   <version>2.3.9</version>
</dependency>

根据该提示添加 runtimeOnly("org.glassfish.jaxb:jaxb-runtime:2.3.9") 后,部署测试环境测试确实报错消失,但是更新到正式环境后却再次出现相同报错。

通过debug找到了JAXB在运行时查找实现类的源码位置 javax.xml.bind.ContextFinder#find,发现可以通过系统属性 javax.xml.bind.JAXBContextFactoryjavax.xml.bind.context.factory 直接指定运行时的JAXB工厂实现类。所以解决方案可以是添加一个系统属性来指定JAXB的工厂实现类。

解决

为了避免和原来的实现冲突,这里我使用了 moxy 库来作为JAXB的实现,moxy 是 EclipseLink 所使用的JAXB实现。
build.gradle 文件中添加

runtimeOnly("org.eclipse.persistence:org.eclipse.persistence.moxy:2.7.12")

然后在Java代码中添加

System.setProperty("javax.xml.bind.JAXBContextFactory", "org.eclipse.persistence.jaxb.JAXBContextFactory");

放在 main 方法的第一行即可。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容