1

I am going through Effective Java, item 75:

If all instance fields are transient, it is technically permissible to dispense with invoking defaultWriteObject and defaultReadObject , but it is not recommended. Even if all instance fields are transient, invoking defaultWriteObject affects the serialized form, resulting in greatly enhanced flexibility. The resulting serialized form makes it possible to add nontransient instance fields in a later release while preserving backward and forward compatibility. If an instance is serialized in a later version and deserialized in an earlier version, the added fields will be ignored. Had the earlier version’s readObject method failed to invoke defaultReadObject , the deserialization would fail with a StreamCorruptedException

The question is why it's necessary to call defaultReadObject/defaultWriteObject to preserve backward and forward compatibility?

Can you explain with an example?

Why the added fields will be ignored?

Why a StreamCorruptedException will be thrown?

Arghya Sadhu
  • 41,002
  • 9
  • 78
  • 107

2 Answers2

0

Because that's what happens by default. If you add these methods you have to at least do what would have happened if they weren't present. Otherwise you won't read/write the stream in a compatible manner. You can't just completely replace what would have been written without risking compatibility.

Unless you can magically change both ends at the same time and there are no permanently serialized streams anywhere, e.g. in files or a database.

user207421
  • 305,947
  • 44
  • 307
  • 483
0

The answer to your question is actually in the excerpt you just provided (though it is a bit vague, I admit). The crucial part is this:

If an instance is serialized in a later version and deserialized in an earlier version, the added fields will be ignored. Had the earlier version’s readObject method failed to invoke defaultReadObject, the deserialization would fail [...]

Imagine the following example: You have an object with only transient fields in it. You decide to skip defaultWriteObject/defaultReadObject calls, because you assume that you do not need it.

Then you add new features to your program, and you also add some non-transient fields to this object. You call defaultWriteObject properly this time, and you expect that the old version of your application will still function (ignoring the new field of course). But it won't. Instead of ignoring the new field you just added because it found unexpected data there.

Gergely Bacso
  • 14,243
  • 2
  • 44
  • 64
  • So is the streamcorruptedexception because we are adding the method now which was absent earlier? – Arghya Sadhu Oct 28 '15 at 06:38
  • 1
    No. The stream is considered corrupted because there is now data there which is not supposed to be there (by App v1.0). Very stupid example but: v1.0 is instructed to read data and construct Object B from it. v2.0 writes data by writing A non-transient fields first (A is the parent class) then fields from B. v1.0 tries to read this. What does it find there? B uuid has not changed, but there are new fields there! It must be corrupted then... Why? Because v1.0 never even considered reading data for class A. – Gergely Bacso Oct 28 '15 at 06:47
  • So if the default methods are called in app v1.0 then how magically it stops itself from thinking the data being corrupted? – Arghya Sadhu Oct 28 '15 at 07:01
  • By calling the defaultRead the v1.0 version is being told that there will be data in the stream that belongs to A. – Gergely Bacso Oct 28 '15 at 07:50