jam0
jam0

Reputation: 23

Is serialVerionUID really meaningful for Externalized classes?

I've read several of the questions and discussions about how Java controls access to Serializable objects. My question is about an Externalizable object and why the serialVersionUID should affect it. I expect that the answer is going to be at "because the Externalizable interface extends the Serializable interface", therefore the field is required. My admittedly somewhat annoying response is "Why does Externalizable extend Serializable?" for two reasons.

The first reason is simply that to implement Externalization requires overriding the readExternal and writeExternal to transfer data to and from the class instance.

The second is a bit more complicated, but here's the situation:

My new Foo class that currently contains two String fields, but I expect that it will grow as my function grows because the user changes some requirements. If I declare Foo to be Serializable, I can write the objects to a file with no problem until I need to update the class to add another field. Now I can't have two versions of the Foo object in a single program, so any file of existing Foo objects is garbage and can't be processed without writing one function read the current Foo file and write it out as text, and then another function to read the text, value the new Foo field and write it as an updated version of the Serialized form.

So my idea was that I should declare Foo as Externalizable, add an internal version field that is the first field written thru the writeExternal function so the readExternal function reads that field first and the remainder can be controlled based on that value.

Putting the two versions side-be-side for comparison:

enter code
    Original version                                          Updated version

 1  public class Foo implements Externalizable {              public class Foo implements Externalizable {
 2                        
 3    static final private long serialVersionUID=????;          static final private long serialVersionUID=????;
 4    static final private long VER00=0;                        static final private long VER00=0;
 5                                                     *****    static final private long VER01=1;
 6
 7    private int fooVer=0;                                     private int fooVer=1;
 8    public String dsn="", lst="";                    *****    public String dsn="", lst="", ext="";
 9    public String getDsn() {return dsn;}                      public String getDsn() {return dsn;}
10    public String getLst() {return lst;}                      public String getLst() {return lst;}
11                                                     *****    public String getExt() {return ext;}
12    public void putDsn(String s) {dsn=s;}                     public void putDsn(String s) {dsn=s;}
13    public void putLst(String s) {lst=s;}                     public void putLst(String s) {lst=s;}
14                                                     *****    public void putExt(String s) {ext=s;}
15                        
16    public Foo() {super();}                                   public Foo() {super();}
17                        
18    @Override                                                @Override
19    public void readExternal(ObjectInput in)                 public void readExternal(ObjectInput in)
20      throws IOException, ClassNotFoundException {             throws IOException, ClassNotFoundException {
21      this.fooVer=in.readLong();                               this.fooVer=in.readLong();
22                                                     *****     if (this.fooVer==VER01) {
23                                                     *****       this.dsn=(String) in.readObject();
24                                                     *****       this.lst=(String) in.readObject();
25                                                     *****       this.ext=(String) in.readObject();
26                                                     *****       return;
27                                                     *****     }
28      if (this.fooVer==VER00) {                                if (this.fooVer==VER00) {
29        this.dsn=(String) in.readObject();                       this.dsn=(String) in.readObject();
30        this.lst=(String) in.readObject();                       this.lst=(String) in.readObject();
31                                                     *****       this.ext="no ext available";
32        return;                                                  return;
33      }                                                        }
34      throw new ClassNotFoundException                         throw new ClassNotFoundException
35        ("unsupported fooVer "+this.fooVer);                     ("unsupported fooVer "+this.fooVer);
36    }                                                        }
37                        
38    @Override                                                @Override
39    public void writeExternal(ObjectOutput out)              public void writeExternal(ObjectOutput out)
40      throws IOException {                                     throws IOException {
41      fooVer=VER00;                                  *****     fooVer=VER01;
42      out.writeLong(fooVer);                                   out.writeLong(fooVer);
43      out.writeObject(dsn);                                    out.writeObject(dsn);
44      out.writeObject(lst);                                    out.writeObject(lst);
45                                                     *****     out.writeObject(ext);
46    }                                                        }
47  }                                                        }

here

Since Foo is controlling Externalization, I should be able to have the value be different, say 0 and 1, and still properly process the record, but if I write with the old value and read with the new on the first read I get an InvalidClassException where the message is: "local class incompatible: stream classdesc serialVersionUID = 0, local class serialVersionUID = 1".

So from what I can tell, regardless of how careful I am, I have to simply pick a value for the serialVersionUID and never change it unless I want to lose all earlier data. Therefore, I am basically am doing a lot of extra work to prevent Serialization from using the serialVersionUID to do what it is intended to do. :/

Did I miss something?

Upvotes: 1

Views: 218

Answers (1)

user207421
user207421

Reputation: 310957

I have to simply pick a value for the serialVersionUID and never change it unless I want to lose all earlier data

That is correct, and it applies whether you implement Ssrializable or Externalizable.

Upvotes: 2

Related Questions