Alibaba Development Manual, (IV) OOP protocol, article 13 explains as follows:

[Mandatory] Do not modify the serialVersionUID field when serializing new attributes of the class to avoid anti-sequence failure; Change the serialVersionUID value if the upgrade is completely incompatible to avoid deserialization clutter. Note: Note that inconsistent serialVersionUID throws a serialization runtime exception.

First of all, it’s important to explain this rule. It’s not that you can’t change it, but that you can change it as you see fit. Let’s take a look at what the serialVersionUID is for.

serialization

Serialization is the process of converting a Java object into another form of data that can be used for storage or transmission. Since Java objects are stored in memory and there is no way to store or transfer them directly, deserialization resolves this problem by converting morphic data back to Java objects. Of course, this form can be a variety of formats, such as the well-known JSON, Byte, or our custom form, such as k-V form, as shown in the following figure.


Java Default serialization

Speaking of serialVersionUID, we have to refer to Java’s default serialization, which provides a serialization method by default in order to provide the storage and outgoing described above. As long as the serialized class implements the Java.io.Serializable interface, then you can do serialization and deserialization. I’ve briefly outlined the code to make it more intuitive (with some cuts).

User.java

public class User implements java.io.Serializable {
    private String name;
    public User(String name) {
        this.name = name;
    }
    @Override
    public String toString(a) {
        returnname; }}Copy the code

SerializerTest.java

User user = new User("Code Maker's Notes.");
FileOutputStream fo = new FileOutputStream("user.bytes");
ObjectOutputStream so = new ObjectOutputStream(fo);
so.writeObject(user);
FileInputStream fi = new FileInputStream("user.bytes");
ObjectInputStream si = new ObjectInputStream(fi);
user = (User) si.readObject();
Copy the code

The code is pretty straightforward,UserTo achieve theSerializableInterface, throughObjectOutputStreamConvert the class to bytecode and store ituser.bytesAnd then use it againObjectInputStreamTake the bytecode fromuser.bytesRead into memory.That’s pretty easy to doJavaIs it really useful? Of course, for exampleJavaBuilt-in remote call componentRMI.

serialVersionUID

Finally, why can’t you easily change the serialVersionUID? The serialVersionUID is not set in the code above. So let’s tweak the example and test it again. User.java

public class User implements java.io.Serializable {
    private String name;
    public User(String name) {
        this.name = name;
    }
    @Override
    public String toString(a) {
        returnname; }}Copy the code

UserSerializeTest.java

public class UserSerializeTest {
    public static void main(String[] args) throws Exception {
        User user = new User("Code Maker's Notes.");
        FileOutputStream fo = new FileOutputStream("user.bytes");
        ObjectOutputStream so = newObjectOutputStream(fo); so.writeObject(user); so.close(); }}Copy the code

User.java

public class User implements java.io.Serializable {
    private String name;
    private String desc;
    public User(String name) {
        this.name = name;
    }
    @Override
    public String toString(a) {
        returnname; }}Copy the code

UserDeserializeTest.java

public class UserDeserializeTest {
    public static void main(String[] args) throws Exception {
        FileInputStream fi = new FileInputStream("user.bytes");
        ObjectInputStream si = newObjectInputStream(fi); User user = (User) si.readObject(); System.out.println(user); si.close(); }}Copy the code

In the code above, we run UserSerializeTest. Java, modify user.java, add a property desc, and run the code again. Did it go wrong?

Exception in thread "main" java.io.InvalidClassException: 
com.github.codedrinker.p1413.User; 
local class incompatible: 
stream classdesc serialVersionUID = 6360520658036414457, 
local class serialVersionUID = -3025746955499933156
Copy the code

It shows that serialVersionUID is different, deserialization failed, but we did not define serialVersionUID why? All at the end of the source text (access) king stepped in, it is time for source code. We check the Java IO. ObjectStreamClass# writeNonProxy, if the current class (User) is not defined serialVersionUID, It invokes the Java. IO. ObjectStreamClass# computeDefaultSUID generate the default serialization only. We simply look at the code and find that its generation rule is based on the hash value generated by the class name, result, method and attribute, so we add desc attribute to User, so the corresponding serialVersionUID will definitely change.


This is explained in the JVM specification [1]

The stream-unique identifier is 
a 64-bit hash of the class name, 
interface class names, 
methods, and fields. 
Copy the code

To verify this, use the JDK’s serialver tool, which uses the same rules as the JDK’s default serialVersionUID.

serialver com.github.codedrinker.p1413.User
Copy the code

You can get the serialVersionUID before and after adding desc, as shown below

 // desc was not added
 private static final long serialVersionUID 
 = 6360520658036414457L;
 / / added desc
 private static final long serialVersionUID 
 = -3025746955499933156L;
Copy the code

Okay, so if we look at this we can fix this problem by modifying one place. Manually define a serialVersionUID code as follows user.java

public class User implements java.io.Serializable {
    private static final long serialVersionUID = 1L;
    private String name;
    public User(String name) {
        this.name = name;
    }
    @Override
    public String toString(a) {
        returnname; }}Copy the code

Repeat the above steps to deserialize successfully.


Here we all understand why the documentation states that serialVersionUID cannot be easily changed. However, 1L at a time is not an option, so you can configure IDEA so that the prompt will be generated automatically when creating classes.



Other serialization methods

The manual only mentions the Java default serialization method, but there are many serialization methods that perform well, such as JSON or byte stream, as mentioned above, such as the popular ones: Hessian, Kryo, Fastjson, ProtoBuf, Jackson, etc., all have their advantages and disadvantages. Here are performance comparisons of JVP-Serializers [2] for limited reference in your choices.


The author

More wonderful articles can be scanned to follow the author’s wechat subscription number “Code maker notes”, receive wonderful tweets every day.

Source code & Manual

Link: https://pan.baidu.com/s/1psiy00_0XeDk6RpsKFFKMA to extract the code: VFTP source: https://github.com/codedrinker/Head-First-Java-Alibaba-Coding-Guidelines

The resources

[1]

The JVM specification: https://docs.oracle.com/javase/6/docs/platform/serialization/spec/class.html#4100


[2]

jvm-serializers: https://github.com/eishay/jvm-serializers/wiki