views:

67

answers:

3

Lets say that I have a program that for some reason need to handle old versions of serialized objects.

Eg: when deserializing, one of these versions may be encountered.

class Pet {
    private static final long serialVersionUID = 1L;
    int paws;
}

class Pet {
    private static final long serialVersionUID = 2L;
    long paws; // handle marsian centipedes
    boolean sharpTeeth;
}

Lets assume that it's (logically) possible to convert an old object to a new object using some clever strategy to set nonexistant fields etc etc, but:

How do I arrange my source code? I would probably need both versions in the same source tree when writing a converter, but how do I handle that in , say, eclipse.

Should I do deserialization in one class loader, and if that fails try using another class loader that uses an older version (and so on), or are there better ways?

What's the best strategy?

+1  A: 

You do not have to maintain multiple version of the class. The latest version should be sufficient. See the link 5 things you don't know about Serialization specifically "Refactoring Serialized Class"

Baski
that's a good article, but doesn't answer the queston
Bozho
Good answer and pointer to the article.
KarlP
+1  A: 

Unfortunately, changing field types is not allowed. Supporting two (ten, hundred?) different versions would be too much of an effort. So you can utilize the readObject(ObjectInputStream in) method. And set a fixed serialVersionUID. If you haven't set it initially, use your IDE or the JDK serialver to get it, so that it appears you have only one version of the class.

If you want to change the type of a field, change its name as well. For example paws > pawsCount. The deserialization mechanism doesn't even get to the readObject(..) method if there is a type mismatch in the fields.

For the above example, a working solution would be:

class Pet implements Serializable {
    private static final long serialVersionUID = 1L;
    long pawsCount; // handle marsian centipedes
    boolean sharpTeeth;

    private void readObject(java.io.ObjectInputStream in)
        throws IOException, ClassNotFoundException {

        in.defaultReadObject();
        GetField fields = in.readFields();
        int paws = fields.get("paws", 0); // the 0 is a default value 
        this.pawsCount = paws;
    }
}

The fields that were added later will be set to their default values.

Btw, it might be a bit easier to use java.beans.XMLEncoder (if it is not too late for your project)

Bozho
Good answer! It's not too late at all, as it's not a project... I'm actually thinking of some of the problems with implementing and using pure object databases,... :-)
KarlP
+1  A: 

Should I do deserialization in one class loader, and if that fails try using another class loader that uses an older version (and so on), or are there better ways?

What's the best strategy?

Serialization really shouldn't be used for long term storage.

The best strategy here is to make use of a database instead: store your objects in a Pets table, then as you change fields on your table, all of your old data gets updated too, every object has the same and most up-to-date schema.

This is really the best way to maintain data for longterm storage, and updates to your old objects to fill in null fields is really easy.

Juliet
Good answer, even though not exactly what I was fishing for. If I had asked the question you where answering, I think I would have used Hibernate :-)
KarlP