你如何从OSGi的字节反序列化对象(How do you deserialize an object

2019-07-05 04:35发布

在我的OSGi应用程序我有三捆, travel.apitable.apiutilstravel.api取决于table.api取决于utils 。 需要注意的是travel.api并不直接依赖于utils 。 我用aQute BND生成清单,我相信这是工作的罚款。 该清单显示如下。

有一类叫做PageData有类型的字段TableData ,这反过来又类型的字段TestObjectPageData位于travel.apiTableData位于table.apiTestObject位于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-Packagetravel.api你会看到com.openaf.utils (其中TestObject所在地)没有列出。 如果我加入这个包,那么它是正确的反序列化。 然而,这似乎不是一个好的解决方法,因为我将不得不通过各个领域PageData使用,并确保它们都在此模块中的进口,以及递归地对这些领域等包含各个领域

我做的东西完全错在这里?

什么是使用OSGi当反序列化对象的最佳方式?

如果我做正确,我必须指定所有的“深”的进口,有没有办法让BND做“深”的一代?

任何帮助将不胜感激!

我使用的是菲利克斯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,scala,sc
 ala.collection,scala.reflect,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,scala.co
 llection,scala.reflect,scala.collection.immutable,scala.collection.gene
 ric,com.openaf.utils";version="0.0.0"
Import-Package: com.openaf.utils,scala,scala.collection,scala.collection
 .generic,scala.collection.immutable,scala.reflect,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,scala.collec
 tion,scala.reflect";version="0.0.0"
Import-Package: scala,scala.collection,scala.reflect,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

谢谢,尼克。

Answer 1:

这实际上听起来像在反序列化一个严重的缺点? 一个体面的解串器应使用导致加载类的类加载器。 该定类加载器应该只因为没有父对象尚未被用于顶级对象。

因此,在这种情况下给定类加载用于加载PageData。 PageData装载机用于加载资料表和资料表的装载必须用于加载的TestObject, 没有逻辑理由,除非你使用的解串器是真的大脑受损,因为这是虚拟机使用加载类的模型中,这应该失败。 我很惊讶的是,Java的解串器做到这一点,我认为这种行为严重的错误,因为它使用的是与虚拟机不同的规则。

序列化是在OSGi的一个问题,因为模块化是有关隐藏实现类; 反序列化必须要访问这些私有类,模块化的对立面的倾向。 不过,也有这很好的解决方案(不包括动态ImportPackage,即恢复到JAR地狱比只使用普通的Java更复杂和昂贵的方式)。 基本的技巧是有从具有访问私有/瞬时需要的类公共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。 类。 也就是说,如果你有这样的扩展资料表,你会被拧紧一个TableDataImpl。 在这种情况下,你需要一些服务,找到了实现的“域”。

祝好运。



Answer 2:

有没有其他办法该怎么做AFAIK。

你必须明确说明所有依赖性的反序列化对象树包含在捆绑,你正在试图做到这一点。

你可以尝试把所有的域对象到一个包,假设模型 ,然后让所有其他包依赖于它。



Answer 3:

是的,这是一个棘手的一个。 在许多情况下,这个问题更是雪上加霜,甚至都不知道这束将需要反序列化的流。 对于这些,编译时间依赖是不一样的运行时依赖。

为了解决这些情况,我已经使用,也可以DynamicImports,包装或使用BundleWiring API 。 都工作得非常好,动态进口更容易,但。

我想说隔离需要这个类装载尽可能多的,你可以在一个单独的包中的一部分,并有捆绑使用DynamicImport。

祝你好运,弗兰克



文章来源: How do you deserialize an object from bytes in osgi