Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java serialization with static initialization

In Java, static and transient fields are not serialized. However, I found out that initialization of static fields causes the generated serialVersionUID to be changed. For example, static int MYINT = 3; causes the serialVersionUID to change. In this example, it makes sense because different versions of the class would get different initial values. Why does any initialization change the serialVersionUID? For example, static String MYSTRING = System.getProperty("foo"); also causes the serialVersionUID to change.

To be specific, my question is why does initialization with a method cause the serialVersionUID to change. The problem I hit is that I added a new static field that was initialized with a system property value (getProperty). That change caused a serialization exception on a remote call.

like image 947
David G Avatar asked Sep 03 '08 11:09

David G


2 Answers

You can find some information about that in the bug 4365406 and in the algorithm for computing serialVersionUID. Basically, when changing the initialization of your static member with System.getProperty(), the compiler introduces a new static property in your class referencing the System class (I assume that the System class was previously unreferenced in your class), and since this property introduced by the compiler is not private, it takes part in the serialVersionUID computation.

Morality: always use explicit serialVersionUID, you'll save some CPU cycles and some headaches :)

like image 148
Damien B Avatar answered Oct 20 '22 11:10

Damien B


Automatic serialVersionUID is calculated based on members of a class. These can be shown for a class file using the javap tool in the Sun JDK.

In the case mentioned in the question, the member that is added/removed is the static initialiser. This appears as ()V in class files. The contents of the method can be disassembled using javap -c. You should be able to make out the System.getProperty("foo") call and assignment to MYSTRING. However an assignment with a string literal (or any compile-time constant as defined by the Java Language Specification) is supported directly by the class file, so removing the need for a static initialiser.

A common case for code targeting J2SE 1.4 (use -source 1.4 -target 1.4) or earlier is static fields to old Class instances which appear as class literals in source code (MyClass.class). The Class instance is looked up on demand with Class.forName, and the stored in a static field. It is this static field that disrupts the serialVersionUID. From J2SE 5.0, a variant of the ldc opcode gives direct support for class literals, removing the need for the synthetic field. Again, all this can be shown with javap -c.

like image 39
Tom Hawtin - tackline Avatar answered Oct 20 '22 11:10

Tom Hawtin - tackline