Local class incompatible error when only a method

2019-07-20 13:46发布

I just came across "WTF" sort of error: I updated one of my classe's methods and added one method too. After running my program, this is what popped our when program tried to open and unserialize recently saved data (before the methods changes):

java.io.InvalidClassException: cz.autoclient.settings.Settings; local class incompatible: stream classdesc serialVersionUID = 2404650814140543454, local class serialVersionUID = 4256355437298300223

According to what java documentation says about that, java methods are not being serialized. So why does the serialVersionUID take class methods in account too?

Since Java programmers seem to be so mad about using getters and setters literally everywhere, why is it not possible to create getter for serialVersionUID so that I can implement my own algorithm that only calculates the properties?

The serialVersionUID can be overriden, but only with static final long serialVersionUID value which would require me to remember to change it when I change class's properties.

2条回答
Juvenile、少年°
2楼-- · 2019-07-20 14:34

The Oracle docs indicate that if you do not provide a serialVersionUID, the compiler will generate one for you.

If a serializable class does not explicitly declare a serialVersionUID, then the serialization runtime will calculate a default serialVersionUID value for that class based on various aspects of the class, as described in the Java(TM) Object Serialization Specification. However, it is strongly recommended that all serializable classes explicitly declare serialVersionUID values, since the default serialVersionUID computation is highly sensitive to class details that may vary depending on compiler implementations, and can thus result in unexpected InvalidClassExceptions during deserialization. Therefore, to guarantee a consistent serialVersionUID value across different java compiler implementations, a serializable class must declare an explicit serialVersionUID value. It is also strongly advised that explicit serialVersionUID declarations use the private modifier where possible, since such declarations apply only to the immediately declaring class--serialVersionUID fields are not useful as inherited members. Array classes cannot declare an explicit serialVersionUID, so they always have the default computed value, but the requirement for matching serialVersionUID values is waived for array classes.

And according to the Java Object Serialization Specification section 5.1

Versioning raises some fundamental questions about the identity of a class, including what constitutes a compatible change. A compatible change is a change that does not affect the contract between the class and its callers.

What's happening here is that the compiler has decided the difference between the two versions of your code warrant a new serialVersionUID. If you feel that the state contained in an instance of Object(1) and Object(2) are interchangeable, you should manage this by setting the serialVersionUID manually and keeping it the same between those changes.

Yes, you will have to manually manage this, and change it when you make changes to the mechanisms which manage the internal state of the class.

As a note though, if the public methods have changed, you should consider if the original version of the class meets the same expectations as the new version. If you would like the data contained in the previously-serialized state to be loaded into a new version of the class, perhaps use a static constructor method to initialize the new version (new behavior) with the compatible, old state.

查看更多
Juvenile、少年°
3楼-- · 2019-07-20 14:36

Based on the documentation for java, they recommend to use custom serialVersionUID as much as possible, because the default algorithm will take class implementation details and the result is said to vary from JVM implementation to another.

The default algorithm used by Java to generate the serialVersionUID seems to be considering the non-private methods (step 7) as well. Which explains the exception if you were using the default serialVersionUID in your implementation.

EDIT: As you suggested, it would be great if we can have our own implementation of a method to do this, rather than overriding the serialVersionUID as a static final long. But I guess they don't allow that because if it were allowed, wrong implementations of such a method could invalidate the whole purpose of the serialVersionUID.

查看更多
登录 后发表回答