Java: When to add readObjectNoData() during serialization?
The readObjectNoData section in Java Object Serialization Specification seems interesting (see below).
Your edits to the question give a perfect example. If Employee
was serialized
when it did not extend Person
and later deserialized
when it did then the Person
part would be initialized to empty string and 0 age. Using this method, you can initialize them to "name" and 1 respectively.
For serializable objects, the readObjectNoData method allows a class to control the initialization of its own fields in the event that a subclass instance is deserialized and the serialization stream does not list the class in question as a superclass of the deserialized object. This may occur in cases where the receiving party uses a different version of the deserialized instance's class than the sending party, and the receiver's version extends classes that are not extended by the sender's version. This may also occur if the serialization stream has been tampered; hence, readObjectNoData is useful for initializing deserialized objects properly despite a "hostile" or incomplete source stream.
private void readObjectNoData() throws ObjectStreamException;
Each serializable class may define its own readObjectNoData method. If a serializable class does not define a readObjectNoData method, then in the circumstances listed above the fields of the class will be initialized to their default values (as listed in section 4.5.5 of The JavaTM Language Specification, Second Edition); this behavior is consistent with that of ObjectInputStream prior to version 1.4 of the JavaTM 2 SDK, Standard Edition, when support for readObjectNoData methods was introduced. If a serializable class does define a readObjectNoData method and the aforementioned conditions arise, then readObjectNoData will be invoked at the point during deserialization when a class-defined readObject method would otherwise be called had the class in question been listed by the stream as a superclass of the instance being deserialized.
"Extendable" means "can have a subclass".
readObjectNoData is used in an unusual case where the serializer (writer) is working with a version of a class with no base class, whereas the deserializer (reader) of the class has a version of the class that IS based on a subclass. The subclass can say "it's ok if my base class isn't in the serialized data - just make an empty one" by implementing readObjectNoData. See these release notes.
Are there any invariants in the Person class I created? When will they be violated?
None explicitly, but imagine that other methods in the class assume that name
is never null
and would throw NullPointerException
if it ever were. In this case, the non-nullity of name
is an invariant.
I copied the code for
readObjectData()
method in theEmployee
class , but it never got called. When will the methodreadObject()
be called ?
There's no method readObjectData()
involved with serialization, this must be a typo. The readObject()
method is called every time a serialized object is deserialized.
The readObjectNoData()
method is hit for some obscure corner case when deserializing a subclass of the class that contains the method.
The advanced serialization article on the SunOracle website covers the purpose of these serialization helper methods. I suggest you start there and post any subsequent questions you may run into.
(update)
In case you’re curious, the readObjectNoData method was added in release 1.4 to cover a corner case involving the addition of a serializable superclass to an existing serializable class. Details can be found in the serialization specification Serialization, 3.5.
The referenced text is:
For serializable objects, the readObjectNoData method allows a class to control the initialization of its own fields in the event that a subclass instance is deserialized and the serialization stream does not list the class in question as a superclass of the deserialized object. This may occur in cases where the receiving party uses a different version of the deserialized instance's class than the sending party, and the receiver's version extends classes that are not extended by the sender's version. This may also occur if the serialization stream has been tampered; hence, readObjectNoData is useful for initializing deserialized objects properly despite a "hostile" or incomplete source stream.
So this can happen in two cases:
- The JVM that decodes the object stream has a newer version of the subclass being deserialized (
Employee
), one that extends some parent class (Person
). The JVM that originally *en*coded the object stream has a different, older version of these classes, wherePerson
was not yet a superclass ofEmployee
. - Someone intentionally messed with the object stream in order to break things.