Mike Desjardins is an Enterprise Java developer who lives in Portland, Maine, U.S.A. His primary focus is on ORM technologies, Database Design, and Web Services, as well as occasional dabbling in web design. Mike is also a proud parent and avid gardener. Mike is a DZone MVB and is not an employee of DZone and has posted 6 posts at DZone. You can read more from them at their website. View Full User Profile

Don't Ignore serialVersionUID

12.15.2008
| 37133 views |
  • submit to reddit
Okay,I admit that this one should have totally been obvious to me long ago. But I'm still a bit of a JEE newcomer (been doing it for almost five years), so perhaps I can be forgiven.

If you do a lot of ORM or EJB remoting, you probably deal with a lot of Serializable classes. And you're probably used to the annoying warning message that you see all the time in your IDE when you're working with Serializable classes:

The serializable class BlaBlaBla does not declare a static final serialVersionUID field of type long BlaBlaBla.java myProject/src/main/java/us/mikedesjardins/foo/domain/entity line 44

If you're like me, you roll your eyes and politely add a @SuppressWarnings("serial") to the top of the class definition (or, worse, you just shut the warning message off in your IDE altogether. Even I don't do that!). You reason with yourself that current versions of Java conveniently and automatically compute the serialVersionUID at run-time, so there's no need to bother with the formality of a version number on your class - it's just a nuisance holdover from days of Java yore.

IT'S A TRAP!
Now that I've found myself well into a new project with this lazy philosophy, I'm starting to run into problems. I have a client of my EJB that uses one of these Serializable objects, and I'm finding that when I make the most trivial changes to my shared classes, I need to compile both the server and the client components. The two components that were supposed to be loosely coupled are now hopelessly intertwined. So I did some further research on how the JVM computes the ad-hoc serialVersionUID at runtime when it isn't provided.

This article over at JavaWorld does a far better and more thorough job of explaining it than I will. In a nutshell, backward-compatability with respect to serialization and de-serialization is a lot less fragile than the cases that the serialVersionUID generation is protecting you against. That version generation algorithm computes an SHA hash based on the class name, sorted member variables, modifiers, and interfaces.

In reality, serialization and de-serialization generally only breaks when one of the following things happens to your class (from the aforementioned article at JavaWorld):
  • Delete fields
  • Change class hierarchy
  • Change non-static to static
  • Change non-transient to transient
  • Change type of a primitive field
Ensure Minimal Coupling Between Components
To ensure that your components which use Serialization have minimal runtime dependencies on each other, you have two options:
  • Declare a specific serialVersionUID, and update it whenever you make a change that breaks backward compatability.
  • Don't rely on any classes for use as transfer objects which will potentially change. This one is pretty obvious, but sometimes you will be surprised down the road at which classes are modified more often than others.
  • Don't use your own objects at all when transferring data. Instead, rely on classes like Integers, Strings, or HashMaps to shuttle data around among components. (Obviously, protocols like SOAP and REST rely on XML documents for this to ensure maximum de-coupling, but you're presumably using something like EJB remoting to avoid the complexity or overhead of these protocols).

From http://mikedesjardins.us/blog/

Published at DZone with permission of Mike Desjardins, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Tags:

Comments

Jeroen Wenting replied on Mon, 2008/12/15 - 7:17am

Your last point is incorrect.
If those HashMaps (for example) contain instances of your custom classes (rather than Integers and other core language constructs) you're still sending Serializable objects over the line and still need to ensure that they can be deserialised at the other end which requires an identical SerialVersionUID.

Of course blindly setting a UID at some point and changing your classes without regard for backwards compatibility is itself a recipe for disaster.
If you say change a data type to one that's incompatible with what your client has who has an older version of the class, you're still going to get nasty errors trying to communicate.
A fixed UID is only useful to prevent those errors when they originate from changes that do not reflect in the data that is (de)serialised, so member methods.

Carlos Rafael R... replied on Mon, 2008/12/15 - 9:28am

Well,

His last option says: "Don't use your own objects at all when transferring data". It is obviuos that the author means, that you can compose the data using Maps of Strings, Integer, etc. Classes that usually do not change often. And I think that his last option is correct.

Jilles Van Gurp replied on Mon, 2008/12/15 - 10:49am

To fix, just press ctrl+1 in eclipse and select geneated id. Much easier than adding a suppress warning and it actually addresses the issue.

Carlos Rafael R... replied on Mon, 2008/12/15 - 1:56pm in response to: Jilles Van Gurp

I agree :-D

Sean Gao replied on Tue, 2008/12/16 - 1:57am

Well, it depends.

 Just as Jeroen has said, it makes no sense or things could even get really nasty if you supply a generated serialVersionUID and later make some "contract-breaking" change to your serializable class.

 BTW, we always build and publish both server end and client end code at the same time. So it's less of an issue. Actually we (as a team) even made an agreement, a general rule that is, as not to provide a serialVersionUID to our serializable classes. In case someone made a change and forgot to update the serialVersionUID.

 

Jeroen Wenting replied on Tue, 2008/12/16 - 1:35am in response to: Carlos Rafael Ramirez

[quote=crramirez]

Well,

His last option says: "Don't use your own objects at all when transferring data". It is obviuos that the author means, that you can compose the data using Maps of Strings, Integer, etc. Classes that usually do not change often. And I think that his last option is correct.

[/quote]

Which would indeed not break the serialisation and deserialisation, but it could well break the next step.
You'd essentially have to create your own system to map the content of that Map to the application data, a system that would break if the content of the Map breaks.
Add a field and it's no great problem, it just gets ignored by the recipients. But expect that field to be returned by the recipient who doesn't know about it and you again are in trouble.
Change the data type of a field and the recipient is in trouble, expecting for example a numerical value but receiving an alphanumerical value instead (we had such a situation here lately, where a String that in the past contained only numerical data now can contain alphanumerical data, leading to a required rewrite of a number of stored procedures and some Java code).

Essentially, data changes can always lead to problems at some point. Having the Serialization engine detect and warn about those problems is IMO a good way to detect them early on, rather than having to start debugging deep inside application frameworks to figure out why you're suddenly getting NPEs or NFEs when nothing on your end of the system changed.

Cyril Ronseaux replied on Tue, 2008/12/16 - 4:01am in response to: Jilles Van Gurp

[quote=jilles]To fix, just press ctrl+1 in eclipse and select geneated id. Much easier than adding a suppress warning and it actually addresses the issue.[/quote] Providing a UUID that you never change is worse than NOT providing one.

If you provide none : then any change to the class will break the serialization (throw an exception).

If you provide one that you change each time a compatibility-break arise : then only changes to the class that break compatibility will fire an exception.

If you provide one that you will never change : the safeguard check of UUID will always think it's ok to serialize, but you will get a more obscure exception, or you'll get erroneous data.

 

So if you don't know what to do, just don't provider a UUID.

You need a serial UUID when :

- the one that serialize and the one that deserialize might be on different source code (e.g. deployed on different servers)

-a server shutdown and code update might happen between serialization and deserialization (e.g. wha!! supra cool, tomcat can persist my httpsessions on disk if I stop it, when I launch it again it reloads the old sessions, and my customers are not disconnected.... well... then you wonder why you have to restart 2 ou 3 times your tomcat after you deployed a new version of your webapp...)

We are used to shut warning off, or generate crap, maybe we should just write a comment :

// no provided serial UUID, I want to keep the generated JVM one, even if it breaks more often that it should.

When I used an ORM, as long as I don't play with EJBs (or more correct : I don't use distributed components), I need to flag Serializable because the ORM requires it (and because semantics of Serialization just say : it can be saved outside memory for later reloading), I don't really need a UUID (because UUID is only useful when java Object default de/serialization is used).

I guess when I start deploying on clusters, then I have to consider UUIDs. Distributed caches too maybe ? (don't know if caches store object data as text, like in a map of strings, or as serialized objects)

 Also, I don't get the point of using a "generated" one. I prefer to work with a sequence : 1L, 2L, 3L. When I do compatibility-breaking change to my source, I don't have to wonder whether the one number will be different from any I used before. And this way, UUID feels more like a version number to me, which is what I think UUID is for serialization.

 

 

Carlos Rafael R... replied on Tue, 2008/12/16 - 10:20am in response to: Jeroen Wenting

I agree, using Maps to pass data is not the better way. For me a conclusion in this thread is to use a fixed serialVersionID and change it when breaking changes occurs. The first part is easy allow the IDE to generate the number. The second part is not. Be carefully to change the number when breaking changes occurs, it is something that is very easy to forget.

 

The good point in caches and distributed sessions, is that it is not common to have different object versions, due to we are working in the same layer.  But problems like restart tomcat and change version can occur, i think not to ofen.

Shane Watson replied on Thu, 2009/03/26 - 4:53am in response to: Carlos Rafael Ramirez

A fixed UID is only useful to prevent those errors when they originate from changes that do not reflect in the data that is (de)serialised, so member methods. Marketing Dissertations | Custom Essay | Dissertation

Danny Jhosup replied on Tue, 2009/04/14 - 3:59am

Just as Jeroen has said, it makes no sense or things could even get really nasty if you supply a generated serialVersionUID and later make some "contract-breaking" change to your serializable class.

thesis help   | custom thesis

Jan Inden replied on Tue, 2011/01/18 - 10:46am

Wieso ein Kreditrechner so beliebt ist. Eine Autoversicherung berechnen und sparen. Wie eine Günstige Autoversicherung funktioniert.

Jan Inden replied on Tue, 2011/01/18 - 10:48am

Wie man einen Tagesgeld Zinsvergleich machen kann. Einen Rechtsschutz Test machen. Einen PKV Vergleich machen. Eine Unfallversicherung abschliessen.

Lola Martin replied on Mon, 2011/08/29 - 5:07am

I too am a newbie on this field. I have been in constant research on things needed for me to get myself the needed ways to get myself the needed ways to meet the said project's expected results. I do want to see some video demo as it would be a convenient way to get the answers easily.

Lola

From  BBQ Islander

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.