Above is a really stripped-down version of my code. Anyway, I used the above code to make serialized Test objects and deserialize them.
Then, more recently, and unintentionally, I got rid of the int evaluationMode and now it looks like the following code.
By the way, the only difference between the above code and the below code is that
public int evaluationMode = 0;
// public int evaluationMode = 0;
After I compiled the code below, it could deserialize Test objects fine. But that is what I am wondering about. Basically I deleted a non-transient field in a class description (the class called NamedProblem), and the serialized objects of the class could still be deserialized fine without an Exception.
I've done that kind of thing before a few times by accident, and got Exceptions every time. But this time I don't get any Exception. It seems that the evaluationMode value which exists in the serialized file is just ignored, but it does not cause an Exception.
My guess is that the newer versions of Java (this is Java 6) don't throw exceptions in this situation, even though older versions did. Is that right?
Imagine you create a class, instantiate it, and write it out to an object stream. That flattened object sits in the file system for some time. Meanwhile, you update the class file, perhaps adding a new field. What happens when you try to read in the flattened object?
Well, the bad news is that an exception will be thrown -- specifically, the java.io.InvalidClassException -- because all persistent-capable classes are automatically given a unique identifier. If the identifier of the class does not equal the identifier of the flattened object, the exception will be thrown. However, if you really think about it, why should it be thrown just because I added a field? Couldn't the field just be set to its default value and then written out next time?
Yes, but it takes a little code manipulation. The identifier that is part of all classes is maintained in a field called serialVersionUID. If you wish to control versioning, you simply have to provide the serialVersionUID field manually and ensure it is always the same, no matter what changes you make to the classfile. You can use a utility that comes with the JDK distribution called serialver to see what that code would be by default (it is just the hash code of the object by default).
Here is an example of using serialver with a class called Baz:
> serialver Baz
> Baz: static final long serialVersionUID = 10275539472837495L;
Simply copy the returned line with the version ID and paste it into your code. (On a Windows box, you can run that utility with the - show option to simplify the copy and paste procedure.) Now, if you make any changes to the Baz class file, just ensure that same version ID is specified and all will be well.
The version control works great as long as the changes are compatible. Compatible changes include adding or removing a method or a field. Incompatible changes include changing an object's hierarchy or removing the implementation of the Serializable interface. A complete list of compatible and incompatible changes is given in the Java Serialization Specification.