Automating class serial version numbers

S

Simon Brooke

For serialisation to work properly as an object changes through versions we
are advised to provide a serialVersionUID which is a static final long.
I'd like to automate the generation of serialVersionUIDs at compile time.
The value could be based either (preferably) on an ant variable called
PROJECT_VERSION or (less preferred) on the time/date of compilation.

I'm certain someone has done this; I've a nasty feeling that it is (or
should be) a FAQ.

The only solution that springs obviously to mind is for ant to copy the
source files from the source directory to an intermediate temporary
directory, making the substitutions as it does so; and then compile from
the intermediate temporary directory to the build directory. This would
work but is clunky.

Does anyone have a better solution?
 
C

Chris Uppal

Simon said:
For serialisation to work properly as an object changes through versions
we are advised to provide a serialVersionUID which is a static final long.
I'd like to automate the generation of serialVersionUIDs at compile time.
The value could be based either (preferably) on an ant variable called
PROJECT_VERSION or (less preferred) on the time/date of compilation.

In general you want the serialVersionUID to stay the same as the class
evolves -- the only time when it should change is when you have made a change
to the object's structure which the serialisation mechanism can't cope with by
itself. So it's the programmer who should be making such changes, as a very
conscious (and very public, since it will typically affect other code)
decision.

-- chris
 
S

Simon Brooke

Chris Uppal said:
In general you want the serialVersionUID to stay the same as the class
evolves -- the only time when it should change is when you have made a
change to the object's structure which the serialisation mechanism can't
cope with by
itself. So it's the programmer who should be making such changes, as a
very conscious (and very public, since it will typically affect other
code) decision.

Yup, which is why I want it to get it set from PROJECT_VERSION, which will
change only on API updates. But when the API does change, I'd like all the
serialVersionUIDs to change rather than to have to manually edit currently
245 source files in one project, and 177 in another.

Our version numbers are based on the major-version.minor-version.patch
convention (e.g. 1.10.17) where

* Major version numbers change only with significant architectural change;
* Minor version numbers change with any API change, no matter how small;
* Patch numbers are given to releases which fix bugs only and do not
involve API changes.

It seems to me to make sense to have the serialVersionUID value based on
the major/minor version numbers in some systematic way, so that in
debugging we can tell immediately just which API version a class relates
to. Doing it on date would be effectively similar, since all classes in
the same release would be compiled in the same build operation on the same
date, and relating a date to a release isn't all that problematic.

Obviously, there will be many classes which don't actually change in any
given new release, and so would be inter-serialisable between releases,
but the maintenance overhead in maintaining and tracking separate
servialVersionUID numbers against API changes seems to me uneconomically
high.

Comments?
 
A

Andy Dingley

Simon said:
For serialisation to work properly as an object changes through versions we
are advised to provide a serialVersionUID which is a static final long.

Why do you need to do this? Is it to allow deserialization to work
correctly with objects that were serialized from an old implementation
(different ID from current) or merely so that it's checked that objects
have the correct ID (i.e. objects aren't ever persisted between builds
with different IDs)?

If it's the latter case, then life is much simpler. You never care
_what_ the ID is, just that it's not shared with an old and
incompatible version. If the ID changes and the object hasn't, then
that's OK. Just embed the Subversion (or CVS etc.)
$LastChangedRevision: $ marker in a suitable constant. Subversion is
smart enough to only update this when the source is changed (not just
timestamp it on every checkin) and even though it'll be updated when
non-significant changes to code are made that didn't affect
serialization, that's no problem -- your system merely needs to check
that all objects of that class are using the _same_ ID.
 
C

Chris Uppal

Simon Brooke wrote:

[me:]
Yup, which is why I want it to get it set from PROJECT_VERSION, which will
change only on API updates. But when the API does change, I'd like all the
serialVersionUIDs to change rather than to have to manually edit currently
245 source files in one project, and 177 in another.

I'm still not sure that we are thinking about this in the same way. As a very
silly example,

class Temperature
{
private double degrees;
public double getDegrees() { return degrees; }
// etc
}

changing that to:

class Temperature
{
private double degrees;
/**@deprecated*/ public double getDegrees() { return
getDegreesCentrigrade(); }
public double getDegreesCentrigrade() { return degrees; }
public double getDegreesFahrenheiht() { return degrees*9.0/5.0+32.0; }
// etc
}

would be a major API change, but does not break serialisation. OTOH, changing
the original to:

class Temperature
{
private double degreesFahrenheiht;
public double getDegrees() { return (degreesFahrenheiht-32)*5.0/9.0; }
// etc
}

is no API change at all, but /does/ break serialisation.

The only scenario I can think of which respects those facts is if, as Andy has
suggested, you don't ever have serialised objects hanging around at all (maybe
you only use it for RMI, perhaps). But in that case, there doesn't seem to be
a lot of point to defining serialVersionUID in the first place. But if you do
need it, then it seems simplest just to have in each serialisable class:

package my.company;
import my.company.ProductIDs;

class SomeClassOrOther
implements Serializable
{
public static final long serialVersionUID
= ProductIDs.PRODUCT_VERSION_NUMBER;
//...
}

and let javac do the work for you...

-- chris
 
S

Simon Brooke

Andy said:
Why do you need to do this? Is it to allow deserialization to work
correctly with objects that were serialized from an old implementation
(different ID from current) or merely so that it's checked that objects
have the correct ID (i.e. objects aren't ever persisted between builds
with different IDs)?

Frankly, I /don't/ need to do it, since I don't serialise anything. Which
makes it a bit hard to work out just what the right thing to do is. But
people who use stuff I build may need to; and I'm getting annoyed by too
many whinges from the compiler complaining that I haven't done it.
If it's the latter case, then life is much simpler. You never care
_what_ the ID is, just that it's not shared with an old and
incompatible version. If the ID changes and the object hasn't, then
that's OK. Just embed the Subversion (or CVS etc.)
$LastChangedRevision: $ marker in a suitable constant.

OK, but the value of a revision in CVS is of the form $Revision: 1.3.2.3 $,
which isn't particularly easy to compile systematically into a long.
Still, it's worth looking at as a possibility.
Subversion is
smart enough to only update this when the source is changed (not just
timestamp it on every checkin) and even though it'll be updated when
non-significant changes to code are made that didn't affect
serialization, that's no problem -- your system merely needs to check
that all objects of that class are using the _same_ ID.

Yup. I ought to think seriously about moving to Subversion, but I haven't
got there yet.

--
(e-mail address removed) (Simon Brooke) http://www.jasmine.org.uk/~simon/
.::;===r==\
/ /___||___\____
//==\- ||- | /__\( MS Windows IS an operating environment.
//____\__||___|_// \|: C++ IS an object oriented programming language.
\__/ ~~~~~~~~~ \__/ Citroen 2cv6 IS a four door family saloon.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,266
Messages
2,571,082
Members
48,773
Latest member
Kaybee

Latest Threads

Top