When do I have to change the serialVersionUID?
Asked Answered
F

6

66

I know that I can use serialVersionUID to control the version of classes. And I read that I can then add or remove fields and the class will still be compatible, it will just use default values.

When must I change the serialVersionUID?

Filature answered 19/7, 2010 at 20:51 Comment(1)
Related to #3678636Longhair
E
64

The value of the serialVersionUID field should ideally be changed when incompatible changes are made to the structure of the class. The complete list of incompatible changes is present in the Java Object Serialization Specification.

To expand further, incompatible changes to a class will prevent the deserialization mechanism from creating an instance of the object, because there is information in the stream that does not map to the current class definition.

Elaineelam answered 19/7, 2010 at 20:56 Comment(2)
No it isn't. The incompatible changes listed in the Specification are those that will result in exceptions when attempted. Those that merely don't map to the current class definition are compatible changes, and there is a long list of those too.Equilibrate
To expand further, incompatible changes [...] prevent the deserialization mechanism from creating an instance: Doesn't this answer amount to saying I should change serialVersionUID to make the deserialization mechanism throw an exception, even though it can already do that without my help as it's an incompatible change that prevents the said mechanism from working? If that's the case, I think there should be a clarification on how that's useful. (I'm doubting here because EJP's answer makes a lot more sense.)Omnivore
E
30

The frequently-repeated mantra about changing the serialVersionUID every time you change the class is complete and utter nonsense. See this Sun article which they republished on their site and which was migrated to the Oracle Technology Network after the acquisition.

You should change the serialVersionUID only when you deliberately want to break compatibility with all existing serializations, or when your changes to the class are so radical that you have no choice - in which case you should really think several times about what it is that you are actually doing.

In all other cases you should bust your boiler trying to use custom readObject()/writeObject() and/or writeReplace()/readResolve() methods and/or serialFields annotations so that you can continue to read objects from those existing serializations. Once you break that you are in for a major headache, indeed nightmare.

Equilibrate answered 20/7, 2010 at 8:40 Comment(7)
This answer could be improved by stating exactly what you disagree with, or what you think your linked article is advocating for. Reading the article, I can't see what Sun is "disagreeing" with.Elliottellipse
what if I added a new field to a class. This change is still compatible: no exception will be thrown. But the field will not contain any information, so semantically it's incompatible. Should I increase UID in this case?Cloistered
@damluar No. That will only make it more incompatible. At least if you don't cause the exception you have several opportunities for mending the semantics. With the exception you have no hope.Equilibrate
Good answer, straight to the point. However, I can't for the life of me figure out what the third paragraph means. Bust your boiler: Are you referring hypothetically to projects where boilerplate code (and/or policy) are to blame because they force change to serialVersionUID by defining stated methods and introduce undue strictness?Omnivore
@Omnivore 'Bust your boiler' is well-known slang for 'work as hard as possible'. Any policy that forces a change to serialVersionUID is wrong, for the reasons stated here and by Sun. I cannot imagine how any boilerplate code could possibly do so.Equilibrate
@Omnivore NB Edit rejected. I am not in any need of boldface to make my point, and when I say 'radical' I mean 'radical', not merely 'semantically different'. Your stated edit reason of 'clarify there's no "or" case' is meaningless. Don't edit things you don't understand.Equilibrate
@DavidS What Sun and I are disagreeing with is 'the frequently-repeated mantra about changing the serialVersionUID every time you change the class'. It's up there in black and white. This seems perfectly clear to me.Equilibrate
R
7

If you don't specify a serialVersionUID field in your Serializable classes, the Java compiler will specify one for you -- essentially it's a hash of the class name, interface names, methods, and fields of the class. Methods can be altered at any time, though, so if you need to change how a stored class is deserialized, you can override the readObject method. If you do specify the serialVersionUID field in your code, though, the compiler won't override that even if you do make incompatible changes, which can result in an exception at runtime -- your IDE or compiler won't give you a warning. (EDIT -- thanks EJP) IDEs such as Eclipse can insert the compiler's UID for you, if you want to easily check how the compiler views certain changes.

If you make changes often, keep an old version of the disk file around to test deserialization with. You can write unit tests to try and read in the old file, and see if it works or if it's totally incompatible.

One caveat, I've personally experienced the pain that is working with Serializable classes originally intended for long-term storage that were improperly designed. For example, storing GUI elements on disk rather than creating them when needed. Ask yourself if Serializable is really the best way to save your data.

Raeleneraf answered 19/7, 2010 at 22:27 Comment(4)
+1 for pointing at the issues with Serializable for storing data, especially when using your own classes (the ones in the JDK itself are at least stable enough).Hillman
'... incompatible changes, which can result in runtime exceptions' - you need to clarify this. You get IOExceptions, not RuntimeExceptions.Equilibrate
@EJP You're right, I could have phrased that better. You'll get an IOEXception /at runtime/ is what I meant to indicate by that -- your IDE or compiler won't warn you ahead of time.Raeleneraf
And another issue, the Java compiler doesn't generate serialVersionUIDs for you. ObjectOutputStream does that.Equilibrate
C
5

For the sake of completeness, here's a list of changes that break the compatibility of Java serialization according to the java 8 spec:

  • Deleting fields
  • Moving classes up or down the hierarchy
  • Changing a nonstatic field to static or a nontransient field to transient
  • Changing the declared type of a primitive field
  • Changing the writeObject or readObject method so that it no longer writes or reads the default field data or changing it so that it attempts to write it or read it when the previous version did not.
  • Changing a class from Serializable to Externalizable or vice versa
  • Changing a class from a non-enum type to an enum type or vice versa
  • Removing either Serializable or Externalizable
  • Adding the writeReplace or readResolve method to a class
Cower answered 20/2, 2019 at 17:19 Comment(1)
The first item on this list is misleading. Deleting a field specifically works rather than throwing an exception, but the resulting object may not work as intended. Same applies to changing a non-transient field to transient.Equilibrate
C
0

You can set serialiVersionUID to the same value for the life of the class. (Not always a good idea) Note: you can implement your own serialization version checking strategy with readObject/writeObject if you need this and leave the UID unchanged.

The only time you MUST change it is if you have already serialized some data to a file and you want to read it. If it has changed for any reason you MUST set the serialiVersionUID to the version in the file to have any hope of being able to read the data.

Cupcake answered 22/7, 2010 at 22:30 Comment(1)
That's rather an indication that you shouldn't have changed it in the first place.Equilibrate
D
0

To declare your own serialVersionUID in java, type this in the serialized object class:

@Serial

private static final long serialVersionUID = desired_number;

Darkroom answered 18/9, 2021 at 1:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.