views:

37

answers:

2

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.

+1  A: 

You need to write a subclass of ObjectInputStream which provides an implementation of resolveClass able to retrieve definitions from the OSGi classloaders.

Damien B
+1  A: 

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.

AlBlue
@AlBlue, Well Said. In my previous experience, object serialization only leads to badness. I avoid it in all situations now, not just storing data.
James Branigan
I know about the issue with the class loaders. The data is not stored persistently, it will be deleted as soon as the VM quits or even earlier. It is just stored for a single process, because memory is of the essence and I need to be able to restore the app to a previous state. Otherwise I share the objections against serialization.
Daniel Schneller
On the other hand, writing that state to a file works whilst serialization doesn't :-)
AlBlue