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.
48 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..
Nice Article. It cleared all my doubts..
This is wonderful example I have ever seen for serialVersionUID. I liked the way how simply it has been explained. Some important points – serialVersionUID being static, is exception to serialization.
Thanks a tonne,
Kishore
Well written article. Surely clears my confusion with serialization. Many thanks
Wonderful article. This question was asked to me in an interview, but at that time i was not aware of this blog.
After the interview I found this blog on google and it had cleared many doubts of mine.
Although Kapil’s question is still pending, I would like to know the answer for his question.
Thanks
Yogesh249@gmail.com
Great article with great example. Understood serialVersionUId beautifully. Thanks.
Still keeping an eye on Kapil’s questions.
Very nice article and examples as well. It took one shot reading and understood crystal clearly. Keep your good work!!
Thanks a lot.
very well explained
Gr8 article.. Thanks a lot
Nice Article Miron.
For those looking for the solution to Kapil’s question,
you just need to implement the following method in MyClass
private void readObject(ObjectInputStream in) throws FileNotFoundException, IOException, ClassNotFoundException
Sample implementation:
——————
public class MyClass implements Serializable {
private static final long serialVersionUID = 1L;
private Class1 c1;
private Class2 c2;
public MyClass(int i){
c1 = new Class1(i);
c2 = new Class2();
}
public String getData(){
return c1.getData()+ ” ” + c2.getData(); }
private void readObject(ObjectInputStream in) throws FileNotFoundException, IOException, ClassNotFoundException{
try{
MyClass dto = (MyClas)in.readObject();
System.out.println(”data: ” + dto.getData());}
catch(InvalidClassException ex){
MyClass dto = new MyClass(1);
System.out.println(”data_: ” + dto.getData());}
}
}
——————
@Kapil Ghodawat
Maybe you should try to write onto DB instead of using serialization.
But if you already have a large number of files that u still want to use with the updated library, maybe java Reflection and a custom class loader could be used. Then u could clone from one version of the class to another. Let me know if you want more info on this (apparently it’s been a year now) at ustamansangat AT live.com
@Reena,
wouldn’t your in.readObject() already fail because the objects were serialized with older class definition?
Very informative article and dully explained the role of serialVersionUID.
Really well complied artical.
Hi..What if we assign 1 to serialVersionUID..Will it affect to the program or not?
In the class, i implemented the Serialization so Im wondering if it matters.Thanks
Hi thanks a lot for the article.
Very nice article, excellent explanation.
Good Post, Liked it! It was helpful.
Good One
Excellent explanation. Thanks mucho!
Great explanation. Thank you
Thanks for such a nice explanation of serialVersionUID
Excellent article, thanks a lot!
Wish you keep blogging
I just wish serialisation never existed. I’ve come into an organisation that writes serial objects into files, and then reads those files & deserialises them. These intermediate files are indecipherable for debugging purposes, and the whole exercise is totally pointless .. why couldn’t they have used plain ascii/xml files and made life simple? I’m sure the reason is they could do it, made them feel clever, so they did do it… and everyone following in their wake are lumbered, cursing the stupidity.
Very Nice Article. Keep it on.
Thank you – although the fact is that I don’t need the serialVersionUID right now, it is very useful to know precisely for what sake it there.)
[...] What is serialVersionUID? [...]
I had posted a question on this blog that wasn’t answered properly by anyone though I found a way to get it work. Sorry all for posting it so late..
The idea is to use a deserialize hook via use of a custom input stream and override readClassDescriptor() method in this customInputStream class as shown below:
public class CustomObjectInputStream extends ObjectInputStream
{
/**
* Collection of classes for which this hook should come into picture.
*/
private static final ArrayList hookedClasses = new ArrayList();
static
{
hookedClasses.add(”com.test.Class1″);
}
public CustomObjectInputStream(InputStream in) throws IOException
{
super(in);
}
/*
* (non-Javadoc)
* @see java.io.ObjectInputStream#readClassDescriptor()
*/
protected ObjectStreamClass readClassDescriptor() throws IOException,
ClassNotFoundException
{
// initially streams descriptor
ObjectStreamClass resultClassDescriptor = super.readClassDescriptor();
Class localClass = Class.forName(resultClassDescriptor.getName());
if (localClass == null)
{
Logger.error(”No local class for ”
+ resultClassDescriptor.getName());
return resultClassDescriptor;
}
if (!hookedClasses.contains(localClass.getName()))
{
return resultClassDescriptor;
}
ObjectStreamClass localClassDescriptor = ObjectStreamClass
.lookup(localClass);
if (localClassDescriptor != null)
{ // only if class implements serializable
final long localSUID = localClassDescriptor.getSerialVersionUID();
final long streamSUID = resultClassDescriptor.getSerialVersionUID();
if (streamSUID != localSUID)
{ // check for serialVersionUID mismatch.
final StringBuilder s = new StringBuilder(
“WARNING: Overriding serialized class version mismatch for class: ”
+ localClass.getName());
s.append(” local serialVersionUID = “).append(localSUID);
s.append(” stream serialVersionUID = “).append(streamSUID);
Logger.debug(s.toString());
resultClassDescriptor = localClassDescriptor; // Use local class
// descriptor
// for
// deserialization
}
}
return resultClassDescriptor;
}
}
Hope this will help…
And yes don’t forget to put readObject() method in MyClass and in that method you have to do stuff like:
private void readObject(java.io.ObjectInputStream in) throws IOException,
ClassNotFoundException
{
ObjectInputStream ois = new CustomObjectInputStream(in);
ois.defaultReadObject();
}
Loved it. Very elagently explained.
Very nice article. Helpful to understand Serialization.
Great article. Short, Sharp, to the point.
Thanks.
Add your Comment!