如何在OSGi中反序列化实现类
在基于 eRCP OSGi 的应用程序中,用户可以按下按钮并转到类似于 Windows 或 Mac OS X 的锁定屏幕。发生这种情况时,应用程序的当前状态将序列化到文件中,并将控制权移交给锁屏。在这个移动应用程序中,内存非常紧张,因此当锁屏出现时,我们需要摆脱原始视图/控制器。
这工作正常,我们最终得到一个二进制序列化文件。用户重新登录后,将再次读入文件并恢复应用程序的原始状态。这也可以正常工作,除非被序列化的控制器包含对来自不同包的对象的引用。在我的具体案例中,原始控制器(来自捆绑包 A)可以调用 Web 服务并返回结果。没什么花哨的,只是简单的值持有者类中的一些字符串和数字。然而,控制器仅将其视为 Result
接口;实际的运行时对象 (ResultImpl
) 在不同的包(包 B,Web 服务客户端实现)中定义和创建,并通过服务调用返回。
当反序列化现在尝试从文件中解冻控制器时,它会抛出 ClassNotFound
异常,抱怨无法反序列化结果对象,因为反序列化是从包 A 调用的,而它无法看到 <来自包 B 的 code>ResultImpl 类。
关于如何解决这个问题有什么想法吗?我唯一能想到的就是将所有单独的值克隆到控制器包中定义的另一个对象中,但这似乎很麻烦。
In an eRCP OSGi based application the user can push a button and go to a lock screen similar to that of Windows or Mac OS X. When this happens, the current state of the application is serialized to a file and control is handed over to the lock screen. In this mobile application memory is very tight, so we need to get rid of the original view/controller when the lock screen comes up.
This works fine and we end up with a binary serialized file. Once the user logs back in, the file is read in again and the original state of the application restored. This works fine as well, except when the controller that was serialized contained a reference to an object which comes from a different bundle. In my concrete case the original controller (from bundle A) can call a web service and gets a result back. Nothing fancy, just some Strings and Numbers in a simple value holder class. However the controller only sees this as a Result
interface; the actual runtime object (ResultImpl
) is defined and created in a different bundle (bundle B, the webservice client implementation) and returned via a service call.
When the deserialization now tries to thaw the controller from the file, it throws a ClassNotFound
exception, complaining about not being able to deserialize the result object, because deserialization is called from bundle A, which cannot see the ResultImpl
class from bundle B.
Any ideas on how to work around that? The only thing I could come up with is to clone all the individual values into another object, defined in the controller's bundle, but this seems like quite a hassle.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
使用序列化通常很脆弱,您不应该使用它来持久存储数据,因为随着时间的推移,类的更改可能会导致这些图像损坏。如果您可以将信息保存为中性存储格式(文本、XML、json),然后您可以使用该信息在运行时重新创建所需的类和绑定,那就更好了。这还为您的捆绑包和布局提供了更大的灵活性,因为您不再受特定实现的束缚。
也就是说,您收到这些错误的原因是因为默认(反)序列化使用当前类加载器在加载时解析类,并且并非所有类都在同一个包中(因此类加载器)。即使您有两个名称和包完全相同的类,如果从不同的类加载器加载它们,最终也会得到不同的(不兼容的)类,这就是这里发生的情况。
Using serialization is generally fragile, and you shouldn't be using it to store data persistently, since changes in classes over time can cause these images to be broken. It would be better if you could persist the information into a neutral storage format (text, XML, json) and then you can use that information to recreate the required clases and bindings at run-time. This also gives you greater flexibility in your bundles and layouts, since you are no longer tied to a specific implementation.
That said, the reason you are getting these errors is because the default (de)serialization uses the current classloader to resolve classes upon load, and not all classes are in the same bundle (and therefore classloader). Even if you have two classes with exactly the same name and package, you end up with different (incompatible) classes if they are loaded from different classloader, which is what's happening here.
您需要编写 ObjectInputStream 提供了 resolveClass 能够从 OSGi 类加载器检索定义。
You need to write a subclass of ObjectInputStream which provides an implementation of resolveClass able to retrieve definitions from the OSGi classloaders.