serialVersionUID fixes

Eric Blake ebb9@email.byu.edu
Mon Oct 7 22:06:00 GMT 2002


I finally found the exact specification of serialVersionUID computation
- the first 64 bits of a SHA-1 hash over the sorted names of fields,
constructors, and methods (more or less).

http://java.sun.com/j2se/1.4.1/docs/guide/serialization/spec/class.doc6.html#4100 



Note that Sun's documentation linked above recommends: "Note - It is
strongly recommended that serializable classes that are inner classes or
which contain inner classes declare the serialVersionUID data member.
This is because different implementations of compilers could use
different names for synthetic members that are generated for the
implementation of inner classes, and these names are used in the current
computation of SUIDs."

It is more important for Classpath to always specify serialVersionUID
than libgcj, since jikes does not match javac in synthetic method names,
and classpath is not always compiled by the same compiler. It is
theoretically possible to reverse engineer javac's naming scheme for
access$xxx methods and other synthetic stuff, but it was deemed more
work than necessary by the jikes project.

Here's an example of the differences:
$ cat Foo.java
class Foo implements java.io.Serializable
{
   class Bar implements java.io.Serializable {}
   public static void main(String[] args)
   {
     System.out.println(Foo.class);
   }
}
$ jikes Foo.java
$ serialver Foo
Foo:    static final long serialVersionUID = -2215115786195463901L;
$ serialver Foo.Bar
Foo.Bar:    static final long serialVersionUID = -6563485480712032514L;
$ javap -private Foo
Compiled from Foo.java
class Foo extends java.lang.Object implements java.io.Serializable {
     static java.lang.Class class$Foo;
     public static void main(java.lang.String[]);
     static java.lang.Class class$(java.lang.String, boolean);
     Foo();
     class Foo. Bar extends java.lang.Object implements
java.io.Serializable {
         final Foo this$0;
         Foo.Bar(Foo);
     }
}

$ javac Foo.java
$ serialver Foo
Foo:    static final long serialVersionUID = -5812209821592755555L;
$ serialver Foo.Bar
Foo.Bar:    static final long serialVersionUID = -3167754321743704770L;
$ javap -private Foo
Compiled from Foo.java
class Foo extends java.lang.Object implements java.io.Serializable {
     static java.lang.Class class$Foo;
     Foo();
     public static void main(java.lang.String[]);
     static java.lang.Class class$(java.lang.String);
     class Foo. Bar extends java.lang.Object implements java.io.Serializable
     /* ACC_SUPER bit NOT set */
{
         private final Foo this$0;
         Foo.Bar(Foo);
     }
}

Here, there are two differences: in Foo, jikes created `Class
class$(String, boolean)' whereas javac created `Class class$(String)';
and in Bar, jikes' this$0 is not private while javac's is.

(FYI, the reason jikes omits the private modifier is so that classes
nested inside Bar can reuse this$0 without additional accessor methods.
And it passes an extra parameter to class$() to avoid class
initialization when evaluation the class literal - the boolean tells
class$ whether it is parsing a class or an array name.  I'll have to
file a PR against gcj for initializing classes when evaluating the class
literal, as Sun claims that is a bug in their implementation).

Tom Tromey wrote:
> Eric Blake's arguments on the Classpath list convinced me to change my
> stance on this topic.  It now seems to me that it is too difficult for
> us to ensure compatibility in the compiler.
-- 
This signature intentionally left boring.

Eric Blake             ebb9@email.byu.edu
   BYU student, free software programmer



More information about the Java-patches mailing list