Bug 101476 - "Serializable class without serialVersionUID" setting and writeReplace
Summary: "Serializable class without serialVersionUID" setting and writeReplace
Status: VERIFIED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 3.1   Edit
Hardware: PC Windows XP
: P3 normal (vote)
Target Milestone: 3.3 M4   Edit
Assignee: Olivier Thomann CLA
QA Contact:
URL:
Whiteboard:
Keywords:
: 163567 (view as bug list)
Depends on:
Blocks:
 
Reported: 2005-06-23 11:41 EDT by Marcelo Paternostro CLA
Modified: 2019-04-02 12:10 EDT (History)
7 users (show)

See Also:


Attachments
Proposed fix (7.41 KB, patch)
2006-11-07 11:13 EST, Olivier Thomann CLA
no flags Details | Diff
Regression tests (6.01 KB, patch)
2006-11-07 11:14 EST, Olivier Thomann CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Marcelo Paternostro CLA 2005-06-23 11:41:30 EDT
If a class (or superclass) provides an implementation of the writeReplace method
to properly handle serialized objects, this warning is probably not relevant.  

And, since it is set to "Warning" by default, it can be annoying to have a bunch
of warnings after carefully designing a good strategy for serialization.
Comment 1 Olivier Thomann CLA 2005-06-23 16:24:08 EDT
It is recommended that each Serializable class has a serialVersionUID field.
Comment 2 David Williams CLA 2005-08-21 03:32:44 EDT
I agree, each Serializable class should have a serialVersionUID field.
That is, if you want long living code that can be worked with in the future 
in the largest number of circumstances. I like the reminding warning, becuase 
is so easy to forget, then you're "hosed" once your code is released. 
Its easy to make the warning go away, just add the serialVersionUID field.
[And ... Ed and I have already argued about this for hours ... so no need to 
repeat that argument here ... just ran accross this bugzilla so thought I'd 
chime in with my vote. 
Comment 3 Ed Merks CLA 2005-08-23 07:58:52 EDT
David,

I think you've missed the point of this defect completely.  The point is that if
writeReplace is defined, the serialialVersionID isn't used and hence insisting
that it's recommended to define it seems pointless at best and pedantic at worst.
Comment 4 David Williams CLA 2005-08-23 13:57:36 EDT
Yes, Ed, I did miss the point of this defect. Thanks for calling it to my 
attention. 

So, sounds like we've won you over on the Serialization case in general :) 
and this defect is only for those cases where writeReplace and readResolve
are both specified, or accessible from a super class?

I agree it would seem to be pointless, if no other versions of that class had
ever been released (which would not have had the methods) ... but not so sure
about pedantic? :)

Comment 5 Olivier Thomann CLA 2006-10-06 15:49:37 EDT
Will investigate.
Comment 6 Olivier Thomann CLA 2006-11-06 14:00:06 EST
*** Bug 163567 has been marked as a duplicate of this bug. ***
Comment 7 Olivier Thomann CLA 2006-11-07 09:46:14 EST
We should also fix the case where a class implements java.io.Externalizable.
In this case the serialVersionUID is not required as the class specifies explicitly how it is serialized through the readExternal and writeExternal methods.
Since java.io.Externalizable implements java.io.Serializable, we also report that class has having a missing serialVersionUID field.
Comment 8 Olivier Thomann CLA 2006-11-07 10:04:43 EST
Also if a Serializable class implements the methods:
 private void writeObject(java.io.ObjectOutputStream out)
     throws IOException
 private void readObject(java.io.ObjectInputStream in)
     throws IOException, ClassNotFoundException;

then it doesn't seem that they use the serialVersionUID field.
This field is only used if the "default" serialization is used. So we should also cover that case.
Comment 9 Olivier Thomann CLA 2006-11-07 10:08:09 EST
Not that javac also has such a warning and doesn't make the distinction with the presence of writeExternal, writeObject, readObject or java.io.Externalizable.
It seems to check only for serialVersionUID when a class implements java.io.Serializable.
Should we be smarter than that?
Comment 10 Olivier Thomann CLA 2006-11-07 10:51:45 EST
To summarize what I believe we should do:
If any of the following conditions is true, then the class that implements java.io.Serializable doesn't need to provide a serialVersionUID field.

1) it implements the interface java.io.Externalizable. This requires the class to implement the two methods writeExternal and readExternal that are bypassing the default serialization mecanism.
2) it implements the method:
ANY-ACCESS-MODIFIER Object writeReplace() throws ObjectStreamException;
3) it implements the pair of methods:
 private void writeObject(java.io.ObjectOutputStream out)
     throws IOException
 private void readObject(java.io.ObjectInputStream in)
     throws IOException, ClassNotFoundException;

Then we would have an accurate warning.
Any comment? Am I missing something?
Comment 11 Olivier Thomann CLA 2006-11-07 11:13:51 EST
Created attachment 53377 [details]
Proposed fix
Comment 12 Olivier Thomann CLA 2006-11-07 11:14:13 EST
Created attachment 53379 [details]
Regression tests
Comment 13 Olivier Thomann CLA 2006-11-07 22:56:21 EST
Released for 3.3M4.
Added regression tests in org.eclipse.jdt.core.tests.compiler.regression.SerialVersionUIDTests#test001/006
Comment 14 Frederic Fusier CLA 2006-12-12 09:52:22 EST
Verified for 3.3 M4 using build I20061212-0010.
Comment 15 Krzysztof Sobolewski CLA 2009-01-21 07:58:39 EST
Actually it seems that point 1) is not true:

"1) it implements the interface java.io.Externalizable. This requires the class
to implement the two methods writeExternal and readExternal that are bypassing
the default serialization mecanism."

It requires the class to override the data format, but the headers are written by the serialization mechanism just like with default serialization. This also includes the SUID value, which also gets checked upon deserialization.
At least that's my impression after hitting a SUID mismatch on an Externalizable class and some poking around the Web :)
Comment 16 Olivier Thomann CLA 2009-01-21 09:09:51 EST
Would you have some links about this?
My findings in 2006 were that the serial version UID is not used when a class is Externalizable with the corresponding methods implemented.
Ed, you had the same conclusion from comment 3.
Comment 17 Krzysztof Sobolewski CLA 2009-01-22 06:08:05 EST
Well, I don't have definite links, only some grumbling here and there, but I did a quick test. I wrote a trivial class implementing Externalizable, containing a single int, which it writes/reads to/from read/writeExternal(), set SUID to -1 and serialized it to a file. I then changed the SUID of the class to 1 and tried to deserialize it. The result was an exception:

Exception in thread "main" java.io.InvalidClassException: sertest.ExternalizableTest; local class incompatible: stream classdesc serialVersionUID = -1, local class serialVersionUID = 1
	at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:546)
	at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1552)
	at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1466)
	at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1699)
	at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1305)
	at java.io.ObjectInputStream.readObject(ObjectInputStream.java:348)
	at sertest.ExternalizableTest.main(ExternalizableTest.java:47)

even though SUID is the only thing that changed (apart from some code in main(), but that doesn't matter).
Comment 18 Yoav Frandzel CLA 2010-07-08 14:24:41 EDT
I think this bug should be re-opened, and the fix reverted. The sample code provided by Krzysztof Sobolewski above proves the point I believe. I have hit upon it too.
Comment 19 Charles Noneman CLA 2013-10-10 17:30:13 EDT
The documentiaion is highly misleading, but if you are using ObjectInput.readObject the serialVersionUID has to match the one that was written with writeObject.
Quick quote from this link: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4094702
"Even through a class is Externalizable, one still has to add
a serialVersionUID member to the class"
Comment 20 Lothar Kimmeringer CLA 2019-04-02 12:10:47 EDT
I second Yoav's request to reopen this bug and revert it to the way it was before. The warning-feature in the current state is nearly useless. No warning is shown for classes that implement Externalizable or that derive from a superclass with a serial version UID already defined. But both scenarios need this to avoid InvalidClassExceptions to occur during deserialization.

Alternatively allow the generation of such a UID explicitly instead of just providing that function as quick fix of the compiler warning.