3

Background

I have a class, which has no serialization features overriden, and no serialVersionUID, but which still is serialized, stored, later deserialized. This is a configuration object, and when changing configuration, data is actually read from configuration UI, then object is created normally "from scratch" and serialized for storage. Only when it is used, object gets created by deserialization.

Now two fields got added to this class, which should not have been serialized, but were... This of course lead to some deserialization problems (NullPointerException when the fields were left null after default deserialization, breaking class invariants), solved by opening configuration UI and saving configuration, thus saving correct serialized form of the object.

Question

Now, what happens in deserialisation of object from saved configuration data, if I modify the class in one of these ways, to do a quick fix:

  1. remove these fields, and saved data is new version, with these fields in it?
  2. change these fields to transient, and saved data is new version, with these fields in it?
  3. change these fields to transient, and saved data is old version, without these fields?

To make this more concrete, let's say the added field is:

private final Map<String, String> extraProperties = new HashMap<String, String>(); 

And this is either removed from this class, or changed to private final transient field.

PS. No need to tell me, that custom serialization code should probably be added, and then the whole thing should probably be refactored, to separate persistent and transient data to different classes...

hyde
  • 60,639
  • 21
  • 115
  • 176
  • 1
    you could add a serialVersionUID to your new class that matches the (implicit) version it had before. this was done in some JDK classes like Vector to maintain backwards compatibility with older versions. then you could implement custom deserialization logic – radai Jan 11 '13 at 08:29
  • You need to find out the `serialVersionUID` used in your existing data, and add that to your class if you want to continue to use the default serialization code. – Thilo Jan 11 '13 at 08:30
  • Yeah, I know what to do to fix it properly. IOW, I know which chapter from *Effective Java* I need to re-read ;). But I did not readily find conclusive answers to my specific questions. – hyde Jan 11 '13 at 08:33
  • Ok, found a very related question: http://stackoverflow.com/questions/3960546/to-initialize-a-transient-field-what-is-the-most-simple-solution – hyde Jan 11 '13 at 08:45
  • Java Serialization is particularly poor at handling changes to data structure. If you need support for this I suggest one of the text based serialization e.g. XStream or JSon or something of your own. – Peter Lawrey Jan 11 '13 at 08:49

1 Answers1

2

Remove (or make transient) these redundant fields you do not want to serialize. Then try to deserialize loading the old version where the non transient field, now removed, have been present. This will result an error of course, as the class serialVersionUID is now different. However both old and new serialVersionUID should be included in the message.

Now just define private static long serialVersionUID = in your class, setting it to old, previous value. The class content with excess fields in the file will be loaded, and the values of these excess fields will be ignored.

However you now have another problem: you probably have saved files of the two different types: old an new version. These will have different serialVersionUID so we can load one or another but not both. serialVersionUID is final, but maybe you can still set and probe different values as described here.

From the view point of serialization, changing field to transient is the same as field removal. It will not be stored and will not be loaded. However declaring the previously non transient field as transient will change the serialVersionUID if it is not fixed.

If item by item, if the serialVersionUID is now hardcoded and matches the serialVersionUID in the file, the answer to your question is:

  1. Nothing.
  2. Nothing.
  3. Nothing.

As "nothing" I mean that the class is deserialized without assigning values to the transient fields (if these are present) and no error is reported.

In case serialVersionUID's do not match, an exception is thrown, even if the rest of class matches.

Community
  • 1
  • 1
Audrius Meškauskas
  • 20,936
  • 12
  • 75
  • 93