On 12 Feb 2014, at 15:24, David M. Lloyd <[email protected]> wrote:

> That's a quote from the serialization spec.  I take it to mean, "Don't write 
> fields and everything might go to hell".  In practice, if the reading side 
> doesn't read fields, things end up more or less OK, as evidenced by various 
> classes in the wild.  But it's not hard to imagine a scenario in which a 
> class change could cause protocol corruption.
> 
> I think the specifics of the quote relate to this kind of class change; in 
> particular, if a class is deleted from the hierarchy on the read side, and 
> that class corresponds to the class that had the misbehaving writeObject, I 
> suspect that things will break at that point as the read side will probably 
> try to consume and discard the field information for that class, which will 
> be missing (it will start reading the next class' fields instead I think).

Yes, possibly. And who knows what fields/values may be read and mistaken for 
the wrong object in the hierarchy. So ‘undefined' behaviour seems right to me.

A simple example throws StreamCorruptedException with Oracles JDK:

public class NoFields {

    public static void main(String[] args) throws Exception  {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        try (ObjectOutputStream oos = new ObjectOutputStream(baos)) {
            oos.writeObject(new B(5, 10));
        }

        ByteArrayInputStream bais = new 
ByteArrayInputStream(baos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bais);
        B b = (B)ois.readObject();
        System.out.println("aValue = " + b.aValue);
        System.out.println("bValue = " + b.bValue);
    }

    static class A implements Serializable {
        final int aValue;
        A(int value) { this.aValue = value; }

        private void writeObject(ObjectOutputStream oos) throws IOException {
            oos.defaultWriteObject();  // <<< comment out
        }
    }

    static class B extends A implements Serializable {
        final int bValue;
        B(int aValue, int bValue) { super(aValue); this.bValue = bValue; }
    }

-Chris.

> 
> On 02/12/2014 09:08 AM, Chris Hegarty wrote:
>> David, others?
>> 
>> I'm afraid I'm still not clear what is mean by:
>>   " ... undefined in cases where the ObjectInputStream cannot resolve
>>     the class which defined the writeObject method in question."
>> 
>> This does not seem directly related to the issue we are discussing (
>> whether to invoke default read/write object ).
>> 
>> -Chris.
>> 
>> On 10/02/14 15:37, David M. Lloyd wrote:
>>> I agree that it's a problem; however it's also clear that there are many
>>> classes in the wild which have this problem.  It would be nice if the
>>> behavior could _become_ defined *somehow* though.  I can see at least
>>> four options:
>>> 
>>> 1) do nothing :(
>>> 2) start throwing (or writing) an exception in write/readObject when
>>> stream ops are performed without reading fields (maybe can be disabled
>>> with a sys prop or something)
>>> 3) leave fields cleared and risk protocol issues
>>> 4) silently start reading/writing empty field information (risks
>>> protocol issues)
>>> 
>>> Maybe there are better options I'm not thinking of.
>>> 
>>> On 02/10/2014 08:53 AM, Chris Hegarty wrote:
>>>> David,
>>>> 
>>>> " ... undefined in cases where the ObjectInputStream cannot resolve the
>>>> class which defined the writeObject method in question."
>>>> 
>>>> I'm not clear as to what this statement is about?
>>>> 
>>>> I'm sure you already know this, and maybe in your environment do not
>>>> care much about it, but having a read/writeObject not invoke the
>>>> appropriate default read/write Object/Fields method is a serious
>>>> impediment to evolving the serial form ( in a compatible way ). For
>>>> example, if your class has no serializable fields in one revision, but
>>>> adds a serializable field(s) in a subsequent revision. This could lead
>>>> to a StreamCorruptedException, or some other undefined behavior.
>>>> 
>>>> The OpenJDK sources do seem to be quite tolerant of this situation. I'm
>>>> not entirely sure if this is a good or a bad thing. That said, I don't
>>>> think we want to encourage this kind of behavior.
>>>> 
>>>> -Chris.
>>>> 
>>>> On 07/02/14 15:07, David M. Lloyd wrote:
>>>>> Since the topic of serialization has come up recently, I'll take it as
>>>>> an excuse to bring up a problem that I've run into a couple of times
>>>>> with the serialization specification, which has resulted in user
>>>>> problems.
>>>>> 
>>>>> If you read section 2.3 [1] of the specification, it says:
>>>>> 
>>>>> "The class's writeObject method, if implemented, is responsible for
>>>>> saving the state of the class. Either ObjectOutputStream's
>>>>> defaultWriteObject or writeFields method must be called once (and only
>>>>> once) before writing any optional data that will be needed by the
>>>>> corresponding readObject method to restore the state of the object;
>>>>> even
>>>>> if no optional data is written, defaultWriteObject or writeFields must
>>>>> still be invoked once. If defaultWriteObject or writeFields is not
>>>>> invoked once prior to the writing of optional data (if any), then the
>>>>> behavior of instance deserialization is undefined in cases where the
>>>>> ObjectInputStream cannot resolve the class which defined the
>>>>> writeObject
>>>>> method in question."
>>>>> 
>>>>> If you go to section 3.4 [2] of the specification, it reads:
>>>>> 
>>>>> "The readObject method of the class, if implemented, is responsible for
>>>>> restoring the state of the class. The values of every field of the
>>>>> object whether transient or not, static or not are set to the default
>>>>> value for the fields type. Either ObjectInputStream's defaultReadObject
>>>>> or readFields method must be called once (and only once) before reading
>>>>> any optional data written by the corresponding writeObject method; even
>>>>> if no optional data is read, defaultReadObject or readFields must still
>>>>> be invoked once."
>>>>> 
>>>>> Now the problem: there are many classes in the wild which nevertheless
>>>>> do not write/read fields.  We cause an exception in such cases rather
>>>>> than make up some undefined behavior.  What I'm wondering is, is there
>>>>> some sensible behavior that could be specified for this case?  The
>>>>> Oracle JDK seems to simply leave fields uninitialized in this case,
>>>>> maybe that can be a specified behavior?
>>>>> 
>>>>> [1]
>>>>> http://docs.oracle.com/javase/7/docs/platform/serialization/spec/output.html#861
>>>>> 
>>>>> 
>>>>> 
>>>>> 
>>>>> [2]
>>>>> http://docs.oracle.com/javase/7/docs/platform/serialization/spec/input.html#2971
>>>>> 
>>>>> 
>>>>> 
>>>>> 
>>>>> 
>>> 
>>> 
> 
> 
> -- 
> - DML

Reply via email to