Reputation: 23
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
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