1

I'm trying to understand java serialization mechanism, and I have few doubts

kindly answer the following questions regarding java serialization:

  • Why we use oos.defaultWriteObject(); ? According to this post its there for backward compatibility. And I don't quite understand how it achieves that.one of incompatible changes for serialization is deleting a field in the newer version. Which means the older versions will have to set default values which sometimes invalid for the user.how is this any different than newer versions adding a new field and allowed to set default values?
  • during custom serialization does it make any difference to use both oos.defaultWriteObject(); and oos.writeObject(address); doesn't the both does the same thing ? I mean both writes non-transient non-static fields of all super class and current class to OOS.

here

private void writeObject(java.io.ObjectOutputStream stream)
        throws IOException {
    stream.writeObject(name);
    stream.writeInt(id);
    stream.writeObject(DOB);
}

private void readObject(java.io.ObjectInputStream stream)
        throws IOException, ClassNotFoundException {
    name = (String) stream.readObject();
    id = stream.readInt();
    DOB = (String) stream.readObject();
}

the above code produces the same result as the below code

private void writeObject(java.io.ObjectOutputStream stream)
            throws IOException {
        stream.defaultWriteObject();
    }

    private void readObject(java.io.ObjectInputStream stream)
            throws IOException, ClassNotFoundException {
         stream.defaultReadObject();
    }

when to use those 2 methods , when to use just writeObject(employee);//employee is my whole object//

  1. here is the list of possible duplicate questions which doesn't answer my question.
  2. question 1 it says * If defaultWriteObject or writeFields is not invoked once before the writing of optional data (if any), then the behavior of instance deserialization is undefined in cases where the ObjectInputStream* but I can still call writeObject without using deafultwriteobject.right ?
  3. question 2 these answers say that defaultwriteobject method writes some extra data to stream and it reflectively checks what to write. doesn't the oos.writeobject(object obj) also reflectively check?
  4. Finally i can get control of my serialization by overriding writeObject and ReadObject method, then whats the point of Externalizable ?
  5. If providing serial versionUID does not throw exception what will happen if i deserialize an object which has missing field from older class which has that field, basically what will happen to all incompatible changes if i provide my own SerialverUID ? is it having own serial version UID will not throw streamcorrupted exception for all compatible changes ?
amarnath harish
  • 945
  • 7
  • 24
  • @eugene can you guys help me here? – amarnath harish Dec 19 '19 at 02:13
  • The backwards compatibility cited refers to compatibility *with prior versions of the class that didn't have a custom* `writeObject()` method, but that's not all it is for. It is called inside a custom `writeObject()` method when you want the default serialization actions *plus* some of your own. All this is documented. When you call it outside that context, as you have, you get that exception. This also is documented. As is everything else you've asked. See the Object Serialization Specification. – user207421 Dec 20 '19 at 07:30
  • @user207421 i did went through the documentation, and im here for clarification. if defaultwriteobject is for custom serialization then why we have externalizable interface ? we could have simply overriden writeobject method right – amarnath harish Dec 20 '19 at 16:31
  • 1
    I don't propose to redundantly explain to you what is already completely covered in the document I referred you to. – user207421 Dec 20 '19 at 19:45

1 Answers1

1

For your question

  1. writeObject is not for backward compatibility. readObject is.
  2. They are same. defaultWriteObject is to help you quick write "serialzable" values.

Backward compatibility

Consider your bean added a new field.

class Bean implements Serializable {
  int id;
  String name;
  String newValue = "123";
}

Though you have give the newValue default value, java serialization will ignore it. (Because it allocate the instance instead of new it)

Now if you don't use readObject, you will get newValue=null. So you need do the initialization at readObject as well.

  private void readObject(ObjectInputStream stream) throws Exception {
    stream.defaultReadObject();
    this.newValue = "123";
  }

How defaultWriteObject help you

Consider your bean is almost "serializable" except some field.

See the following code. The BadThing is not Serializable or it has some sensitive data that you don't want serialize them.

class Bean implements Serializable {
  int id;
  String string;
  BadThing badThing;
}

To quick serialize it, you can let the field transient and write your writeObject method to handle it

  private void writeObject(ObjectOutputStream stream) throws Exception {
    stream.defaultWriteObject();
    stream.writeInt(badThing.id);
  }

  // Corresponding `readObject`

Of course you can replace defaultWriteObject to several writeXXX. But if you have many many fields, write the code is tired and boring, right?

So defaultWriteObject is just to save you from write boring code.

Dean Xu
  • 4,438
  • 1
  • 17
  • 44