How to deserialize implementation classes in OSGi

java, osgi, serialization

Solution

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.

Problem

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.

Original source