When I use ObjectOutputStream are the attributes of the parent class also written?

4

When I use ObjectOutpuStream to write to file, will the parent class attributes also be written?

    
asked by anonymous 10.02.2014 / 12:53

2 answers

1

Yes, not only the attributes of the object itself are saved, but also those of the superclasses, as well as all referenced objects . That is, a sufficient "graph" of objects is saved to restore the object completely saved, without relying on any pre-existing object.

Example:

class A {
    int x;
}

class B {
    A y;
}

class C extends B {
    int z;
}

When serializing a C object, the y and z fields will be included, y will be a serialization of the A class object (ie x will also be included) .

Note: This example is simplified. According to the documentation of ObjectOutputStream , only objects that implement the interface Serializable will be written to the file. If the memory does not fail me, any non-serializable object in the object graph will cause an exception to be thrown by attempting to serialize - unless there is code to handle that case.     

10.02.2014 / 12:58
3

In the case of inheritance, there are some nuances as to what will or will not be included in the serialization.

ObjectOutputStream will serialize all classes in the hierarchy that are marked with java.io.Serializable and their descendants. Of these, non-static, non-transient attributes that are also marked with that interface will be serialized.

It's kind of complicated, is not it? Let's see one ...

Practical example (with error)

First, two classes that will be referenced, one serializable and one not:

class OutraClasseSerializavel implements Serializable {
    int outroValorSerializavel;
}

class OutraClasse {
    int outroValor;
}

Second, a "parent" class and a "daughter":

class Pai {
    OutraClasse outraClassePai;
    OutraClasseSerializavel outraClasseSerializavelPai;
    int valorPai;
}

class Filha extends Pai implements Serializable {
    OutraClasse outraClasseFilha;
    OutraClasseSerializavel outraClasseSerializavelFilha;        
    int valorFilha;
}

Note that both classes have values and references for serializable and non-serializable classes.

What happens if we try to serialize the class Filha ? java.io.NotSerializableException occurs because of reference to non-serializable class OutraClasse in class Filha .

Practical example

If we remove the reference to the non-serializable class of class Filha , the error does not occur:

class Filha extends Pai implements Serializable {
    OutraClasseSerializavel outraClasseSerializavelFilha;        
    int valorFilha;
}

Testing and analyzing the result

Let's take a test:

Filha filha = new Filha();

//valores da classe filha
filha.valorFilha = 11;
filha.outraClasseSerializavelFilha = new OutraClasseSerializavel();
filha.outraClasseSerializavelFilha.outroValorSerializavel = 33;

//valores da classe pai
filha.valorPai = 22;
filha.outraClasseSerializavelPai = new OutraClasseSerializavel();
filha.outraClasseSerializavelPai.outroValorSerializavel = 44;
filha.outraClassePai = new OutraClasse();
filha.outraClassePai.outroValor = 55;

//serializa
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("filha.out")));
oos.writeObject(filha);
oos.close();

//recupera classe serializada
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("filha.out")));
Filha filhaRecuperada = (Filha) ois.readObject();
ois.close();

Finally, let's print and analyze the returned values ...

Primitive attribute in serializable class

System.out.println(filhaRecuperada.valorFilha);

Output:

  

11

Obviously, the valorFilha attribute is properly serialized and retrieved because it is part of the serializable class and is a primitive type.

Reference to the serializable class in a class also serializable

System.out.println(filhaRecuperada.outraClasseSerializavelFilha.outroValorSerializavel);

Output:

  

33

The outraClasseSerializavelFilha attribute has also been properly serialized, as well as its value, because it is a reference to a serializable class from the Filha class that is serializable.

Primitive attribute in class Pai , which is not serializable

System.out.println(filhaRecuperada.valorPai);

Output:

  

0

We now note that although no errors occur, static attributes in a non-serializable superclass are not serialized.

Reference to serializable and non-serializable classes in a non-serializable superclass

System.out.println(filhaRecuperada.outraClassePai);
System.out.println(filhaRecuperada.outraClasseSerializavelPai);

Output:

  

null

     

null

Finally, we note that references to classes of any type (serializable or not) in a non-serializable superclass will also be excluded from serialization.

Considerations

Extending a class to make it serializable does not work, as it was seen the serialization process ignores non-serializable superclasses and an error occurs when we include a non-serializable attribute.

But is there a solution? The answer is yes!

Solution: readObject and writeObject

documentation of class java.io.Serializable lists some methods that should be implemented so that you can "manually" change the way Java serializes and deserializes an object.

The signatures are:

private void writeObject(java.io.ObjectOutputStream out)
    throws IOException
private void readObject(java.io.ObjectInputStream in)
    throws IOException, ClassNotFoundException;

Implementation example

Here is a basic implementation of the readObject() and writeObject() methods in the Daughter class that solve the serialization problem of both the superclass integer attribute and the references to other objects:

class Filha extends Pai implements Serializable {

    int valorFilha;
    transient OutraClasse outraClasseFilha;
    OutraClasseSerializavel outraClasseSerializavelFilha;

    private void readObject(java.io.ObjectInputStream stream)
            throws IOException, ClassNotFoundException {
        valorFilha =  stream.readInt();
        outraClasseFilha = new OutraClasse();
        outraClasseFilha.outroValor = stream.readInt();
        outraClasseSerializavelFilha = (OutraClasseSerializavel) stream.readObject();

        valorPai = stream.readInt();
        outraClassePai = new OutraClasse();
        outraClassePai.outroValor = stream.readInt();
        outraClasseSerializavelPai = (OutraClasseSerializavel) stream.readObject();
    }

    private void writeObject(java.io.ObjectOutputStream stream)
            throws IOException {
        stream.writeInt(valorFilha);
        stream.writeInt(outraClasseFilha.outroValor);
        stream.writeObject(outraClasseSerializavelFilha);

        stream.writeInt(valorPai);
        stream.writeInt(outraClassePai.outroValor);
        stream.writeObject(outraClasseSerializavelPai);
    }

}

Then we do a new test:

Filha filha = new Filha();

//valores da classe filha
filha.valorFilha = 11;
filha.outraClasseSerializavelFilha = new OutraClasseSerializavel();
filha.outraClasseSerializavelFilha.outroValorSerializavel = 22;
filha.outraClasseFilha = new OutraClasse();
filha.outraClasseFilha.outroValor = 33;

//valores da classe pai
filha.valorPai = 44;
filha.outraClasseSerializavelPai = new OutraClasseSerializavel();
filha.outraClasseSerializavelPai.outroValorSerializavel = 55;
filha.outraClassePai = new OutraClasse();
filha.outraClassePai.outroValor = 66;

//serializa
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("c.out")));
oos.writeObject(filha);
oos.close();

//recupera classe serializada
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("c.out")));
Filha filhaRecuperada = (Filha) ois.readObject();
ois.close();

//valores da classe filha
System.out.println(filhaRecuperada.valorFilha);
System.out.println(filhaRecuperada.outraClasseSerializavelFilha.outroValorSerializavel);
System.out.println(filhaRecuperada.outraClasseFilha.outroValor);

//valores da classe pai
System.out.println(filhaRecuperada.valorPai);
System.out.println(filhaRecuperada.outraClasseSerializavelPai.outroValorSerializavel);
System.out.println(filhaRecuperada.outraClassePai.outroValor);

And we get the output:

11
22
33
44
55
66

All attributes have been saved!

Conclusion

While Java does not solve the whole issue of automagically serialization, it provides us with a flexible and practical mechanism for solving this, as it allows us to completely control how the object is saved and retrieved from the file.

On the other hand, it is required to manually encode each attribute of the class in the correct order.

    
10.02.2014 / 14:00