On 02/24/2014 10:53 PM, Stuart Marks wrote:
On 2/24/14 8:22 PM, Joe Darcy wrote:
On 02/20/2014 12:49 PM, Paul Benedict wrote:
Joe, I find it interesting that you suppressed the serial warning on an
abstract class. I'd like to know more about that. Is this a
universal rule?
Are serial uids not important for abstract classes?
I wouldn't generalize that way from this example.
The serial hash of NavigableSubMap has differed in different JDK
releases,
but its subclasses do define serialVersionUID fields. I assume the
set of
non-transient fields in NavigableSubMap has stayed unchanged, but I
haven't
verified that.
If I hadn't found the change in the hash value, I would have added the
serialVersionUID to NavigableSubMap too.
And in his reply to Paul, Joe said:
From what I was able to discern by reading the serialization
specification
[1], If a class does *not* declare a serialVersionUID, the
serialVersionUID
of its superclass is *not* included in the serialver hash computation
of the
child class. However, my understanding is that changes to the fields
stored
in superclass and changes to the semantics of its readObject /
writeObjects
methods could affect the serialization of the child class.
I think we need to take a closer look at these issues.
I believe that abstract, serializable superclasses *do* need to have a
serialVersionUID defined. The reason is that when a subclass is
serialized, its superclass descriptor (an ObjectStreamClass) is also
serialized. Upon deserialization, the descriptor's svuid is matched
against the svuid of the class loaded at runtime, and if there is a
mismatch, InvalidClassException ensues.
While the svuid of an abstract superclass isn't included in the
subclass' svuid hash, the svuid of the superclass does affect serial
compatibility of subclasses as described above. Thus, an apparently
innocuous change to the superclass might prevent serial compatibility
of its subclasses, no matter how carefully the subclasses are programmed.
If the NavigableSubMap class has changed svuid values over several
releases, well, unfortunately we may have a compatibility problem
already in the field. We'd need to choose which release to be
compatible with. Since 8 isn't quite out yet, we might be able to
change an early 8-update and 9 to be compatibile with the latest
7-update.
Note that the svuid of a class does not relate solely to the fields
that are serialized. It's an attempt at a version hash of the
*implementation* of a class, not a version of the serial protocol.
Even changes to a class that don't affect the serialized output stream
can affect the svuid. For example, renaming a package-private method
will affect the svuid. See section 4.6 of the serialization spec.
I am trying hard to remain blissfully ignorant of any more low-level
details of the serialization format; however, I might not be successful
on that goal much longer ;-)
My preference in a case like this is to add the svuid if for no other
reason that is is simple to explain and understand, even if it is not
strictly required.
While we're at it (sorry...) in the diffs for your other serial
warnings patch JDK-8035453, there are several lines where the serial
warning is suppressed like so:
+@SuppressWarnings("serial") // JDK implementation class
As you know, serialization can expose the private fields of a class,
making them public in a sense. Serialization can also expose what are
internal, implementation classes, if these classes are part of a
serializable object graph that is exposed to applications. I don't
know about the specific situation with the DOM classes, but even if a
serializable class is internal, we might need to be concerned about
serialization compatibility.
There is a difference in character between a serializable class in Java
SE (java.* and javax.*) and the jdk.Exported(true) types in the JDK and
a serializable class that lives in sun.* or some other
jdk.Exported(false) area.
For that latter, the serialization contract has to be different, with
fewer guarantees, just as the general usage contract for those types has
fewer guarantees. I think this is analogous to putting non-serializable
classes into collections; the collection itself is serializable, but it
won't be anymore if you put non-serializable objects into it.
If a user happens to have a direct or indirect reference to an object of
a JDK implementation type, the compatibility contract is weaker than if
an object with a public Java SE type were being dealt with.
Finally, EnumSet doesn't need a serial version UID. It's serialized
using a proxy class, so EnumSet never appears in a serialized byte
stream. (Note, its readObject throws an exception unconditionally.) So
it's probably safe to suppress its serialization warning.
Yes, EnumSet was a bit tricky, it is serializable itself, but uses a
proxy internally. ("Effective Java, 2nd edition" both recommends the
proxy pattern and recommends adding a svuid to all serializable classes,
but doesn't explicitly give guidance to this combination of features.)
To avoid adding a long comment explaining the proxy pattern and why a
svuid on EnumSet isn't really required, my preference would just be to
add the svuid if it doesn't cause any harm.
Thanks,
-Joe