ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

JBoss和Resteasy:反序列化java序列化对象时的ClassNotFoundException

2019-07-03 00:01:19  阅读:345  来源: 互联网

标签:java serialization jboss resteasy activiti


上下文:我们使用Activiti作为流程引擎,Activiti-Rest作为其应用程序的接口.由于问题与返回由Java序列化的对象的REST服务有关,我没有将其添加到标题中.

场景:我们有一个JBoss Wildfly实例,它包含一个带有模块的EAR(让我们称之为X作为参考),它包含一个类“ProcessContext”. Activiti在这个EAR中运行,而ServiceTasks(从进程中调用Java-snippets来做一些工作)依赖于该类.他们使用此类来实例化流程变量并向其添加一些数据.

我们有第二个部署(一个WAR,当前在同一个Wildfly实例上但稍后在远程服务器上),它通过其REST api访问Activiti,现在我们需要访问“ProcessContext”数据.此WAR还依赖于X,其类加载器可以毫无问题地解析“ProcessContext”.

好的.这样做似乎很简单.呼叫:

GET history/historic-process-instances/{processInstanceId}/variables/{variableName}/data

这将返回MediaType“application / x-java-serialized-object”的响应,并使用调试器检查它似乎很好.但是当我试图反序列化对象时,我收到了这个错误:

Caused by: java.lang.ClassNotFoundException: xxx.commons.metadata.ProcessMetadata from [Module "org.jboss.resteasy.resteasy-jaxrs:main" from local module loader @103f852 (finder: local module finder @587c290d (roots: /opt/wildfly/modules,/opt/wildfly/modules/system/layers/base))]
at org.jboss.modules.ModuleClassLoader.findClass(ModuleClassLoader.java:213) [jboss-modules.jar:1.3.3.Final]
at org.jboss.modules.ConcurrentClassLoader.performLoadClassUnchecked(ConcurrentClassLoader.java:459) [jboss-modules.jar:1.3.3.Final]
at org.jboss.modules.ConcurrentClassLoader.performLoadClassChecked(ConcurrentClassLoader.java:408) [jboss-modules.jar:1.3.3.Final]
at org.jboss.modules.ConcurrentClassLoader.performLoadClass(ConcurrentClassLoader.java:389) [jboss-modules.jar:1.3.3.Final]
at org.jboss.modules.ConcurrentClassLoader.loadClass(ConcurrentClassLoader.java:134) [jboss-modules.jar:1.3.3.Final]
at java.lang.Class.forName0(Native Method) [rt.jar:1.8.0_20]
at java.lang.Class.forName(Class.java:340) [rt.jar:1.8.0_20]
at java.io.ObjectInputStream.resolveClass(ObjectInputStream.java:626) [rt.jar:1.8.0_20]
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1613) [rt.jar:1.8.0_20]
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1518) [rt.jar:1.8.0_20]
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1774) [rt.jar:1.8.0_20]
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351) [rt.jar:1.8.0_20]
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:371) [rt.jar:1.8.0_20]
at org.jboss.resteasy.plugins.providers.SerializableProvider.readFrom(SerializableProvider.java:76) [resteasy-jaxrs-3.0.10.Final.jar:]
... 131 more

想知道它我发现用于反序列化对象的类加载器,如果Resteasy模块的Module-Classloader而不是我的本地(模块)类加载器.

一种解决方案可能是编写一个包含“ProcessContext”的模块,并使其在JBoss中全局知晓,但这是项目负责人拒绝的一些基础设施决策.

难道Resteasy不应该使用调用者的类加载器而不是模块类加载器吗?调用者知道它所需的类,如果我可以得到响应内部输入流,我可以自己反序列化它没有任何问题.我真的很想知道这是一个错误还是一个功能.

任何想法如何解决这个问题?

解决方法:

好的,最后我通过编写自己的提供程序并以编程方式将其注册到Resteasy客户端来找到解决方案.我也试过通过web.xml做这个,但是这不起作用,我会解释.

对于其他有类似问题的人,我的解决方案.邮件正文提供者:

@Provider
@Consumes("application/x-java-serialized-object")
public class ActivitiObjectMessageBodyReader implements MessageBodyReader<ProcessMetadata> {

@Override
public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
    return (type == ProcessMetadata.class && "application/x-java-serialized-object".equals(mediaType.toString()));
}

@Override
public ProcessMetadata readFrom(Class<ProcessMetadata> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, String> httpHeaders, InputStream entityStream) throws IOException, WebApplicationException {

    BufferedInputStream bis = new BufferedInputStream(entityStream);
    ObjectInputStream ois = new ObjectInputStream(bis);
    try {
        return ProcessMetadata.class.cast(ois.readObject());
    } catch (ClassNotFoundException e) {
        throw new WebApplicationException(e);
    }
}

}

我知道,由于注释,我可能不需要isReadable中的整个表达式但是…

程序化注册看起来像这样:

ResteasyProviderFactory factory = new ResteasyProviderFactory();
factory.register(new ActivitiObjectMessageBodyReader());
Configuration configuration = new ClientConfiguration(factory);

现在我可以使用这样的配置:

Client client = ClientBuilder.newClient(configuration);

哇,通过REST检索Java对象变量.

—–你可以在这里停止阅读,除非你想知道我认为是什么问题的原因—–

问题与重新安装内的提供商工厂的加载有关.我调试了它,并看到它交换提供程序对配置的提供程序,如下所示:

Providers current = ResteasyProviderFactory.getContextData(Providers.class);
ResteasyProviderFactory.pushContext(Providers.class, configuration);

使用web.xml或RegisterBuiltin.register(factory)全局注册我的提供程序时,可以在上述调用之后找到当前提供程序,但当前不用于反序列化.相反,使用了配置,并且它有一系列父工厂,导致工厂在Resteasy模块中初始化,由于它自己的类加载器,它不包含我的提供者并且找不到我的类.
是的,我有例如在web.xml中启用了resteasy.scan,但它没有帮助.

当将工厂提供给客户端时,它会将其注入响应构造函数,现在提供程序在序列化时可用,使用我自己的模块的类加载器(因为它被注册为bean),这会产生所需的反序列化对象.

标签:java,serialization,jboss,resteasy,activiti
来源: https://codeday.me/bug/20190702/1361218.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有