Xlint:serial checking from checking the declaration of
serialVersionUID fields to checking the declarations of all serialization-related fields and methods.
Mis-declaring serialization-related fields and methods can lead to runtime exceptions and silent failures.
Add checks for all the serialization and externalization related fields and methods:
private void writeObject(java.io.ObjectOutputStream stream) throws IOException; private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException; private void readObjectNoData() throws ObjectStreamException; ANY-ACCESS-MODIFIER Object writeReplace() throws ObjectStreamException; ANY-ACCESS-MODIFIER Object readResolve() throws ObjectStreamException;
private static final long serialVersionUID private static final ObjectStreamField serialPersistentFields
The checks are triggered when a field or method in a serializable type has a name matching one of the serialization-related fields or methods, respectively.
Additional checks are done for Externalizable types as some serialization-related methods are ineffectual there.
The semantics of serialization are covered in the "Java Object Serialization Specification" (https://docs.oracle.com/en/java/javase/17/docs/specs/serialization/index.html), abbreviated as JOSS in the remainder of this CSR, as well as in portions of the core library specification, including the classes
The overall objective is to warn for cases where declarations cause the runtime serialization mechanism to silently ignore a mis-declared entity, rendering it ineffectual. Also, the checks include several compile-time patterns that could lead to runtime failures.
The checks are specialized for each of serializable
enum classes, and
record classes. (Per the JLS annotation interfaces are not serializable.)
For fields and methods in Serializable classes (not
records), the checks make sure:
- mandatory modifiers are present (e.g.
- modifiers that should not be present are absent (e.g.
writeObject; those methods must be instance methods)
- for fields, the field is declared with the proper type
- for methods, the return type, number and of type of parameters match and the throws clause is compatible (methods are not declared to throw any checked exceptions that are not subtypes of those thrown by the canonical method's signature)
Existing checks that the
serialVersionUID field is declared
static final and of the right type, etc. are preserved.
serialPersistentFields is initialized to a literal null, a distinct warning is issued since a null
serialPersistentFields field is ignored, JOSS 1.5.
A serializable class is checked that it has access to a no-arg constructor in the first non-serializable class up its superclass chain (required in JOSS section 1.10). Note that
java.lang.Object is not serializable and has a public non-arg constructor so the chain will terminate. An externalizable class is checked to have a public no-arg constructor (JOSS section 1.11).
Warnings are issued if an externalizable class has a
readObject method, or
readObjectNoData method; those declarations are ineffectual for an externalizable class (JOSS 1.11 "An Externalizable class can optionally define the following methods: ... A writeReplace method to allow a class to nominate a replacement object to be written to the stream ... A readResolve method to allow a class to designate a replacement object for the object just read from the stream").
enum classes, since the serialization spec states the five serialization-related methods and two fields are all ignored (JOSS 1.12), the presence of any of those in an
enum class will generate a warning.
record classes, from JOSS 1.13 "any class-specific writeObject, readObject, readObjectNoData, writeExternal, and readExternal methods defined by record classes are ignored during serialization and deserialization." Therefore, warnings are generated for the ineffectual declarations that serialization would ignore.
interfaces, if a
writeObject method is defined, a warning is issued since a class implementing the interface will be unable to declare
private versions of those methods and the methods must be private to be effective. If an interface defines default
readResolve methods, a warning will be issued since serialization only looks up the super*class* chain for those methods and not for default methods from interfaces. Since a
serialPersistentFields field must be
private to be effective, the presence of such a (non-
private) field an in interface generates a warning. The presence of a
serialVersionUID field does not generate a warning, but the declaration is checked to conform to the field's requirements to be effective, having the proper type, etc. There are limited circumstances where the
serialVersionUID of an interface are used.
The behavior in the Solution section above is intended to be a full and accurate description of the expansion in
-Xlint:serial checking. There is not a specification document per se for the lint behavior, other than summary statements in the
javac help messages and similar usage documentation.
The description of
-Xlint:serial is updated as follows:
- Warn about Serializable classes that do not provide a serial version ID. \n\ -\ Also warn about access to non-public members from a serializable element. + Warn about Serializable classes that do not have a serialVersionUID field. \n\ +\ Also warn about other suspect declarations in Serializable and Externalizable classes and interfaces.