如何解决如何从osgi中的字节反序列化对象
这实际上听起来像是反序列化的严重缺陷?体面的反序列化器应使用导致加载的类的类加载器。给定的类加载器应仅用于顶级对象,因为还没有父对象。
因此,在这种情况下,给定的类加载器用于加载PageData。PageData的加载器用于加载TableData,而TableData的加载器必须用于加载TestObject。除非您使用的解串器确实被人脑损坏,否则没有逻辑上的原因导致失败的原因,因为这是VM用来加载类的模型。我很惊讶Java反序列化器会这样做,我认为此行为是一个严重的错误,因为它使用的规则与VM不同。
串行化是Osgi中的一个问题,因为模块化是关于隐藏实现类的。反序列化趋向于要访问这些私有类,这是模块化的对立面。但是,对此有很好的解决方案(不包括Dynamic- ImportPackage,它以比使用纯Java更复杂,更昂贵的方式恢复到JAR地狱)。基本技巧是从公共API获得一个根对象,该根对象可以访问私有/临时需要的类。嗯,这听起来不像服务吗?
解
看看人们对此有何看法,这是一个小示例,说明如何使用Java序列化解决问题(即ObjectInputStream和ObjectOutputStream)。在您的问题中,您提到了ObjectDecoderInputStream,这是我不熟悉的类。
设置为:
Bundle A: class a.A { B b; } (import b)
Bundle B: class b.B { C c; } (import c)
Bundle C: class c.C { }
因此,让我们首先序列化一个对象:
ByteArrayOutputStream bous = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bous);
oos.writeObject(this);
oos.close();
现在是困难的部分。我们重写resolveObject方法,这使我们有机会实际进行适当的类加载…
ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(bous.toByteArray())) {
Set<ClassLoader> lhs = new LinkedHashSet<ClassLoader>();
{
// Keep a set if discovered class loaders
lhs.add(getClass().getClassLoader());
}
@Override
protected Class< ? > resolveClass(ObjectStreamClass desc)
throws ClassNotFoundException, IOException {
for (ClassLoader cl : lhs) try {
Class< ? > c = cl.loadClass(name);
// we found the class, so we can use its class loader,
// it is in the proper class space if the uses constraints
// are set properly (and you're using bnd so you should be ok)
lhs.add(c.getClassLoader());
// The paranoid among us would check
// the serial uuid here ...
// long uuid = desc.getSerialVersionUID();
// Field field = c.getField("serialVersionUID");
// assert uuid == field.get(null)
return c;
} catch (Exception e) {
// Ignore
}
// Fallback (for void and primitives)
return super.resolveClass(desc);
}
};
// And Now we've successfully read the object ...
A clone = (A) in.readobject();
请注意,这仅在正确导出瞬态图的情况下才有效。即,如果您可以这样做,new
TableData
那么这也应该起作用。一个不起作用的示例是,例如,如果您从接口获取实现。接口类未连接到impl。类。即,如果您具有扩展了TableData的TableDataimpl,那么您将被搞砸。在这些情况下,您需要一些服务来找到实现的“域”。
祝好运。
解决方法
在我的OSGi应用程序我有三捆,travel.api
,table.api
和utils
。travel.api
取决于table.api
取决于utils
。请注意,travel.api
这并不直接取决于utils
。我使用aQute
Bnd生成清单,并且我相信它工作正常。清单如下所示。
有一个名为PageData
的类TableData
,它具有类型字段,而该字段又具有类型字段TestObject
。PageData
位于travel.api
,TableData
位于table.api
和TestObject
位于utils
。装入捆绑包时,所有这些工作正常。当我收到代表PageData
对象的字节数组时,就会出现问题。我必须在travel.api
捆绑包中反序列化它。这应该不是问题,因为它是在此处定义的。我使用org.jboss.netty.handler.codec.serialization.ObjectDecoderInputStream
并从travel.api
捆绑包中传入类加载器。抛出了以下所示的异常,但基本上说:
Caused by: java.lang.ClassNotFoundException: com.openaf.utils.TestObject not
found by travel.api [9].
现在,这是有道理的,因为如果你看Import-
Package
的travel.api
,你会看到com.openaf.utils
(其中TestObject
位于)未列出。如果我添加了这个软件包,那么它将被正确地反序列化。但是,这似乎不是一个很好的通用解决方案,因为我将不得不遍历PageData
使用并确保将其全部导入此模块的每个字段,并递归遍历那些字段等包含的每个字段。
我在这里做错什么吗?
使用OSGi时反序列化对象的最佳方法是什么?
如果我做得正确,并且必须指定所有“深度”导入,是否有办法让Bnd进行“深度”生成?
任何帮助将不胜感激!
我正在使用felix v4作为我的osgi库。
Manifest-Version: 1
Bnd-LastModified: 1355404320862
Bundle-ManifestVersion: 2
Bundle-Name: travel.api
Bundle-SymbolicName: travel.api
Bundle-Version: 0
Created-By: 1.7.0_07 (Oracle Corporation)
Export-Package: com.openaf.travel.api;uses:="scala.runtime,scala,scala.c
ollection,com.openaf.pagemanager.api,scala.reflect,com.openaf.table.api
";version="0.0.0"
Import-Package: com.openaf.pagemanager.api,com.openaf.table.api,sc
ala.collection,scala.runtime
Tool: Bnd-1.44.0
Manifest-Version: 1
Bnd-LastModified: 1355404158858
Bundle-ManifestVersion: 2
Bundle-Name: table.api
Bundle-SymbolicName: table.api
Bundle-Version: 0
Created-By: 1.7.0_07 (Oracle Corporation)
Export-Package: com.openaf.table.api;uses:="scala.runtime,scala.co
llection,scala.collection.immutable,scala.collection.gene
ric,com.openaf.utils";version="0.0.0"
Import-Package: com.openaf.utils,scala.collection,scala.collection
.generic,scala.runtime
Tool: Bnd-1.44.0
Manifest-Version: 1
Bnd-LastModified: 1355404158801
Bundle-ManifestVersion: 2
Bundle-Name: utils
Bundle-SymbolicName: utils
Bundle-Version: 0
Created-By: 1.7.0_07 (Oracle Corporation)
Export-Package: com.openaf.utils;uses:="scala.runtime,scala.collec
tion,scala.reflect";version="0.0.0"
Import-Package: scala,scala.runtime
Tool: Bnd-1.44.0
java.io.InvalidClassException: failed to read class descriptor
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1585)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1514)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1750)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1347)
at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1964)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1888)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1771)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1347)
at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1964)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1888)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1771)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1347)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:369)
at org.jboss.netty.handler.codec.serialization.ObjectDecoderInputStream.readObject(ObjectDecoderInputStream.java:115)
at com.openaf.rmi.common.DefaultObjectEncoder$.decode(RMICommon.scala:33)
at com.openaf.rmi.client.ClientHandler.messageReceived(ClientPipelineFactory.scala:43)
at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:296)
at org.jboss.netty.handler.codec.frame.FrameDecoder.unfoldAndFireMessageReceived(FrameDecoder.java:363)
at org.jboss.netty.handler.codec.frame.FrameDecoder.callDecode(FrameDecoder.java:345)
at org.jboss.netty.handler.codec.frame.FrameDecoder.messageReceived(FrameDecoder.java:211)
at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:268)
at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:255)
at org.jboss.netty.channel.socket.nio.NioWorker.read(NioWorker.java:94)
at org.jboss.netty.channel.socket.nio.AbstractNioWorker.processSelectedKeys(AbstractNioWorker.java:372)
at org.jboss.netty.channel.socket.nio.AbstractNioWorker.run(AbstractNioWorker.java:246)
at org.jboss.netty.channel.socket.nio.NioWorker.run(NioWorker.java:38)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
at java.lang.Thread.run(Thread.java:722)
Caused by: java.lang.ClassNotFoundException: com.openaf.utils.TestObject not found by travel.api [9]
at org.apache.felix.framework.BundleWiringImpl.findClassOrResourceByDelegation(BundleWiringImpl.java:1460)
at org.apache.felix.framework.BundleWiringImpl.access$400(BundleWiringImpl.java:72)
at org.apache.felix.framework.BundleWiringImpl$BundleClassLoader.loadClass(BundleWiringImpl.java:1843)
at java.lang.ClassLoader.loadClass(ClassLoader.java:356)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:264)
at org.jboss.netty.handler.codec.serialization.ClassLoaderClassResolver.resolve(ClassLoaderClassResolver.java:30)
at org.jboss.netty.handler.codec.serialization.CachingClassResolver.resolve(CachingClassResolver.java:39)
at org.jboss.netty.handler.codec.serialization.CompactObjectInputStream.readClassDescriptor(CompactObjectInputStream.java:55)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1583)
... 28 more
谢谢,尼克。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。