views:

246

answers:

5

I have a simple Java class that I need to serialize to be stored as a value in an RDBMS or a key-value store. The class is just a collection of properties of simple types (native types or Maps/Lists of native types). The issue is that the class will likely be evolving over time (likely: adding new properties, less likely but still possible: renaming a property, changing the type of a property, deleting a property).

I'd like to be able to gracefully handle changes in the class version. Specifically, when an attempt is made to de-serialize an instance from an older version, I'd like to be able to specify some sort of handler for managing the transition of the older instance to the newest version.

I don't think Java's built-in serialization is appropriate here. Before I try to roll my own solution, I'm wondering if anyone knows of any existing libraries that might help? I know of a ton of alternative serialization methods for Java, but I'm specifically looking for something that will let me gracefully handle changes to a class definition over time.

Edit:

For what it's worth, I ended up going with Protocol Buffer (http://code.google.com/p/protobuf/) serialization, since it's flexible to adding and renaming fields, while being on less piece of code I have to maintain (in reference to the custom Java serialization using readObject/writeObject).

+2  A: 

Java serialisation allows customising of the serial form by providing readObject and writeObject methods. Together with ObjectInputStream.readFields, ObjectOutputStrean.putFields and defining serialPersistentFields, the serialised form can be unrelated to the actual fields in the implementation class.

However, Java serialisation produces opaque data that is not amenable to reading and writing through other techniques.

Tom Hawtin - tackline
I wasn't aware of the readFields and putFields methods, so thanks for that.
Brian Ferris
A: 

I had a similar problem. I found out Java's serialVersionUID doesn't help much when you have multiple versions of objects. So I rolled out my own.

Here is what I do to save our user sessions,

  1. In my DB, besides the BLOB field for serialized objects, I added a version column.
  2. Whenever we change the session object, I save the old class, for example SessionV3.
  3. Session is always written to the DB with current version number.
  4. When reading the session, it's deserialized into session object directly if version is current. Otherwise, it's deserialized into old object and manually copied into current session object (SessionV3 => Session).
  5. Once a while, we run a DB script to remove real old session versions so we can clean out old sessions from code. If we care about the old sessions, we can choose to convert them also.

There might be easier way to do this but our approach gives us most flexibility.

ZZ Coder
A: 

Never tired it but you may be able to do something with a custom bootloader to load the correct version of the class file at runtime for the object being deserialized.

Chris Nava
+1  A: 

Perhaps you should map your Java class into the relational model. Dumping some language serialized blob into a database column is a horrible approach.

Lispnik
I don't want to use a standard object relational mapping for a couple reasons:1) My serialized class has a number of properties that are Lists and Maps of values. While it's possible to represent these in SQL, it increases the complexity of the db schema, especially when it comes to gracefully handling changes to the class schema.2) I'd like to stay flexible enough to switch to a key-value store model, where the value is just my serialized class.
Brian Ferris
A: 

This is pretty straightforward using read and write object.

Try setting serialversionuid to a fixed value, then define a static final field for your version. The readobject can then use a switch statement to construct the fields depending on the version. We use this to store historical data on our file system. It's very quick on retrieval- so much so that users can't tell the difference.

Fortyrunner