当前位置: 首页 > 知识库问答 >
问题:

反序列化Java序列化对象时的JBoss和resteasy:ClassNotFoundException

端木宏盛
2023-03-14

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

场景:我们有一个JBoss Wildfly实例,它包含一个EAR和一个包含类“ProcessContext”的模块(为了参考,我们将其称为X)。Activiti在这个EAR中运行,ServiceTasks(从进程中调用Java代码片段来完成一些工作)依赖于该类。他们使用这个类来实例化一个流程变量,并向其中添加一些数据

我们有第二个部署(一个WAR,目前在同一个Wildfly实例上,但后来在远程服务器上),它通过Activiti的REST api访问Activiti,现在我们需要访问“ProcessContext”数据。这个WAR还依赖于X,它的classloader可以毫无问题地解决“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而不是我的本地(模块)类装入器。

有什么想法可以解决这个问题吗?

共有1个答案

慕阳
2023-03-14

好了,最后我找到了一个解决方案,编写了一个自己的提供者,并以编程方式向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);
    }
}

}

ResteasyProviderFactory factory = new ResteasyProviderFactory();
factory.register(new ActivitiObjectMessageBodyReader());
Configuration configuration = new ClientConfiguration(factory);
Client client = ClientBuilder.newClient(configuration);

问题与Resteasy内部提供商工厂的装载有关。我对它进行了调试,看到它将提供程序与配置的提供程序进行交换,如下所示:

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

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

当向客户机提供工厂时,它将它注入到响应构造函数中,现在提供程序在序列化时可用,使用我自己模块的classloader(因为它已注册为bean),这将产生所需的反序列化对象。

 类似资料:
  • 本文向大家介绍java对象的序列化和反序列化,包括了java对象的序列化和反序列化的使用技巧和注意事项,需要的朋友参考一下 本文实例为大家分享了java对象的序列化和反序列化,供大家参考,具体内容如下 1. 什么是序列化        将对象转换为字节流保存起来,比如保存到文件里,并在以后还原这个对象,这种机制叫做对象序列化。(补充一句:把对象保存到永久存储设备上称为持久化) 2. 怎么实现序列化

  • 错误: java.lang.ClassNotFoundException:testprocedure.tp$3在java.net.URLClassLoader$1上运行(未知源)在java.net.URLClassLoader上运行(未知源)在java.security.accessController.doprivileged(本机方法)在java.net.URLClassLoader.find

  • 本文向大家介绍详解Java 对象序列化和反序列化,包括了详解Java 对象序列化和反序列化的使用技巧和注意事项,需要的朋友参考一下 之前的文章中我们介绍过有关字节流字符流的使用,当时我们对于将一个对象输出到流中的操作,使用DataOutputStream流将该对象中的每个属性值逐个输出到流中,读出时相反。在我们看来这种行为实在是繁琐,尤其是在这个对象中属性值很多的时候。基于此,Java中对象的序列

  • 我已经开始将一个项目从使用Java标准日期迁移到Joda DateTime。 我的项目使用XML序列化将对象保存到XML文件中。在这个特殊的例子中,我有一个Item类,它有一个DateTime属性。 在某个时候,我正在初始化对象,包括像这样的DateTime属性: 我使用XMLEncoder使用辅助类序列化项目: 显然,日期时间被保存在xml中。。。但毫无价值: 显然,它没有保存任何东西,但不,它

  • 其中备注是对象内部的vavr列表字段。 现在,如果尝试将相同的值反序列化到对象中,则会出现错误: 当尝试反序列化时,为什么serified JSON文本不起作用? 在Java代码中有没有其他方法可以将vavr对象打印成文本格式并将其转换回POJO?

  • 主要内容:1 Java序列化和反序列化,2 Java序列化的优点,3 java.io.Serializable接口,4 Java ObjectOutputStream,5 Java ObjectInputStream,6 Java序列化的例子,7 Java反序列化的例子1 Java序列化和反序列化 Java中的序列化是一种将对象状态写入字节流的机制。它主要用于Hibernate,RMI,JPA,EJB和JMS技术。 序列化的反向操作称为反序列化,其中字节流被转换为对象。序列化和反序列化过程与平台