When I use ObjectOutpuStream
to write to file, will the parent class attributes also be written?
When I use ObjectOutpuStream
to write to file, will the parent class attributes also be written?
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.
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 ...
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
.
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;
}
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 ...
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.
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.
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.
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.
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!
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;
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!
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.