Most people learn about serialVersionUID after they write their first serializable object (I know I did). You add ‘implements Serializable’ and in the next moment your IDE starts complaining… so what’s up?
Lets look at a simple example to see what meaning that variable has. In the example we will use the class SerializeMe shown below:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: |
class SerializeMe implements Serializable {
private static final long serialVersionUID = 1L;
private int data;
public SerializeMe (int data) {
this.data = data;
}
public int getData() {
return data;
}
}
|
Field data represents some information stored in the class. Class implements the Serializable interface, so my IDE automatically offered me to declare the serialVersionUID field. Lets start with value 1 set there.
We will also need some class that will serialize and deserialize the SerializeMe class. Here it is:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: |
public class UIDTester {
public static void main(String... strings) throws Exception {
File file = new File("out.ser");
FileOutputStream fos = new FileOutputStream(file);
ObjectOutputStream oos = new ObjectOutputStream(fos);
SerializeMe serializeMe = new SerializeMe(1);
oos.writeObject(serializeMe);
oos.close();
FileInputStream fis = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(fis);
SerializeMe dto = (SerializeMe) ois.readObject();
System.out.println("data : " + dto.getData());
ois.close();
}
}
|
This code will serialize an instance of class SerializeMe to a file and then deserialize it back. Now let’s run the main function! You should get output that says:
data : 1 |
It means that our object was properly serialized and deserialized. Note that the file “out.ser” was created on disk and it is still there even after the program finished. Let’s see if we can read that file once again, this time without creating it first. To do that, comment out lines from 4 to 9 in the UIDTester class:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: |
public class UIDTester {
public static void main(String... strings) throws Exception {
File file = new File("out.ser");
//FileOutputStream fos = new FileOutputStream(file);
//ObjectOutputStream oos = new ObjectOutputStream(fos);
//SerializeMe serializeMe = new SerializeMe(1);
//oos.writeObject(serializeMe);
//oos.close();
FileInputStream fis = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(fis);
SerializeMe dto = (SerializeMe) ois.readObject();
System.out.println("data : " + dto.getData());
ois.close();
}
}
|
This way, the main method starts right away with reading the file from the disk and deserializing data stored in it. As the file is exactly the same and our class didn’t changed either, we should get exactly the same output:
data : 1 |
Now, let’s see what happens, when we change the serialVersionUID value and try to deserialize once again our file. Change the line 2 in the class SerializeMe so that serialVersionUID contains now 2 instead of 1:
2: |
private static final long serialVersionUID = 2L;
|
Now let’s run again our program (just like one step before, with commented out lines writing the file). We should get an exception like this:
Exception in thread "main" java.io.InvalidClassException: SerializeMe; local class incompatible: stream classdesc serialVersionUID = 1, local class serialVersionUID = 2 |
As you can see, this time the deserialization didn’t go well. ObjectInputStream complained about the serialVersionUID being changed. How does he know that it changed? If serialVersinUID is static, then it should not have been serialized in the first place, and there should be no information about the previous value 1 during the deserialization, right? Well, serialVersionUID is an exception to the rule that “static fields don’t get serialized”. ObjectOutputStream writes every time the value of serialVersionUID to the output stream. ObjectInputStream reads it back and if the value read from the stream does not agree with the serialVersionUID value in the current version of the class, then it throws the InvalidClassException. Moreover, if there is no serialVersionUID officially declared in the class to be serialized, compiler automatically adds it with a value generated based on the fields declared in the class.
So what is it for after all? Let’s suppose that there is some file storing a serialized object of some class A. The deserialization of that object does not necessarily have to occur exactly after serialization. It can occur after a few months or on a completely different JVM (i.e. sending an object through net using serialization). In both cases, there is a chance that the class declaration has changed between serialization and deserialization. It would be nice to have some kind of versioning system for every serializable class – and serialVersionUID does exactly that. It checks if the data read from the input stream is compatible with the current definition of the class.
If so, then why is it recommended to specify your own serialVersionUID ? It gives us simply more control. Default rules for generating serialVersionUID can be too strict in some cases. For example when the visibility of a field changes, the serialVersionUID changes too. Value generated automatically can differ between various Java implementations. There is a chance that some object serialized on one Java implementation will not deserialize on some other Java implementation, even if the class definition is exactly the same. Furthermore, sometimes you just want for some reason to forbid deserialization of old serialized objects, and in this case you just have to change the serialVersionUID.
Now that you know that specifying your own serialVersionUID is recommended, you might tend to write it once for every serializable class ( or have it generated by the IDE ) and forget about it. WRONG !!! If you write it once and don’t take care to update it when necessary, you loose all the merits of serialVersionUID. All your classes will get deserialized without exceptions even when using outdated data. What you should do is to change serialVersionUID (for example increase it by 1 or make your IDE generate automatically a new value) every time there is some change in the definition of data stored in the class. For example if you change data types, variable names or add new data – hence every time you want to have ‘backward incompatibility’ for deserialization.
19 Comments until now
[...] http://www.javablogging.com/what-is-serialversionuid/ [...]
Nice article, I’ve banned serialVersionUID on our project for the exact
reason you’ve listed at the end. People add it thinking they are being good and getting rid of an IDE warning… Then never maintain it.
Nice post. Thank you.
Good one, this helps me to do some good work
As i understand from this great article, the “serialVersionUID” it`s a magic field-name.
But i can`t find any “serialVersionUID” string occurrences in ObjectOutputStream class code.
Cool…
to Vadim Voituk:
@see
java.io.ObjectOutputStream.writeClass(Class, boolean)
@see
java.io.ObjectStreamClass
@r3d
Thanks, found it
java.io.ObjectStreamClass.java:1582
What’s wrong with defaulting to 1 rather than not defining it? If to default to 1, you SAVE big time on the cost of creating a serializationID during runtime.
Very nice article. I have a question ( may be a bit off topic)
Serializable interface has no methods or fields. But still you can use special methods like writeObject, readObject and also the field serialVersionUID .
How is it possible in java ? Is there any nomenclature for such type of special methods / fields ?
@Ravi P
void writeObject(ObjectOutputStream out)and
void readObject(ObjectInputStream in) are does not belong to any class hierarchy in java API. They basically form a part of Jav serialization mechanism. whenever you serialize any object, JVM checks wether any method like writeObject(ObjectOutputStream out) has been declared. This is to intercept the normal serialization mechanism caused by calling ObjectOutputStream.writeObject.
Adding to it as void writeObject(ObjectOutputStream out)and
void readObject(ObjectInputStream in) are both private methods, it means they are not extended from any class (overridden), hence do not belong to any particular class in the java API. Somethings in java are meant for JVM to invoke
and for the nomenclature, such interfaces are called ‘Marker Interface’ in Java. Another example is Cloneable interface.
[...] 参考:http://www.javablogging.com/what-is-serialversionuid/ [...]
this is good article to understand about serialVersionUID. i red in javaworld.com also, but this one is short with fruitfull info.
[...] 5. http://www.javaworld.com/javaworld/jw-02-2006/jw-0227-control.html?page=1 6. http://www.javablogging.com/what-is-serialversionuid/ 7. http://java.dzone.com/articles/dont-ignore-serialversionuid 8. [...]
I have one question or infact should say I am stuck at this and looking for a solution.
Is there any way to deserialize an object even if its serialVersionUID is changed OR say to ignore this exception for that object and let it continue deserialization of other fields?
Let me explain this, Say I have a serializable class MyClass which has two fields:
—————————————-
MyClass implements Serialzable{
Class1 field1;
Class2 field2;
private static final long serialVersionUID = 1L;
}
—————————————-
Where Class1 and Class2 both are also serializable now if Class1’s UID is changed (its a third party class so out of my control) but I still want to deserailize MyClass (even with null OR default value for field1) how can I do this?
Very nice article with good example. Thanks! It helped me to clear my understanding..
Women’s vibram five fingers kso shoes Gray Pink Shoes can keep your feet in the freest condition,just as if your were barefooted. vibram five fingers kso shoes is made of the best and proper materials,so you don’t need to doubt of its comfort with so thin sole and upper.
Gray match with a dreamlike and romantic color,pink vibram five fingers kso shoes is very consistent with the style of young girls.In this busy and tense times,people need relax without any fetter.
Add your Comment!