4
When I use the ObjectOutpuStream
to write to file, parent class attributes will also be saved?
4
When I use the ObjectOutpuStream
to write to file, parent class attributes will also be saved?
3
When it comes to inheritance, there are some nuances as to what will or will not be included in serialization.
The ObjectOutputStream
will serialize all hierarchy classes that are marked with java.io.Serializable
and their descendants. Of these, the non-static, non-stransient attributes that are also marked with the said interface will be serialized.
Kind of tricky, huh? 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 class "father" 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 the two classes have values and references for serializable and non-serializable classes.
What happens if we try to serialize the class Filha
? There occurs a java.io.NotSerializableException
because of the reference to the class which cannot be serialized OutraClasse
in class Filha
.
If we remove the reference to the unserviceable class from the 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);
Exit:
11
Obviously, the attribute of valorFilha
is properly serialized and retrieved because it is part of the serializable class and is a primitive type.
System.out.println(filhaRecuperada.outraClasseSerializavelFilha.outroValorSerializavel);
Exit:
33
The attribute outraClasseSerializavelFilha
was also serialized correctly, as well as its value, because it is a reference to a class serialized from the class Filha
which is serializable.
Pai
, that is not serializableSystem.out.println(filhaRecuperada.valorPai);
Exit:
0
We now note that, although no errors occur, static attributes in a nonserializable superclass are not serialized.
System.out.println(filhaRecuperada.outraClassePai);
System.out.println(filhaRecuperada.outraClasseSerializavelPai);
Exit:
null
null
And finally, we observe that references to classes of any kind (serializable or not) in a non-savizable superclass will also be excluded from serialization.
Extending a class to make it serializable does not work, because as it was seen the serialization process ignores the non-proserializable superclasses and an error occurs when including a non-serializable attribute.
But is there a solution? The answer is yes!
To class documentation java.io.Serializable
points out some methods that should be implemented so that you can change "manually" 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;
Follows a basic implementation of methods readObject()
and writeObject()
in the Daughter class that solve the problem of serialization of both the superclass integer attribute and 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 make 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 exit:
11
22
33
44
55
66
All attributes have been saved!
Although Java does not solve the whole issue of serialization automagically, it provides us with a practical and flexible mechanism to resolve this, as it allows you to completely control how the object is saved and recovered from the file.
On the other hand, manual coding of each class attribute is required in the correct order.
1
Yes, not only the attributes of the object itself are saved, but also those of the superclasses, and also all objects referenced. That is, a sufficient "graph" of objects is recorded to restore the saved object completely, without relying on any pre-existing object.
Example:
class A {
int x;
}
class B {
A y;
}
class C extends B {
int z;
}
By serializing an object of C
, the fields will be included y
and z
, whereas y
will be a serialization of the class object A
(that is to say, x
will also be included).
Note: this example is simplified. According to the documentation of ObjectOutputStream
, only objects implementing the interface Serializable
will be written in the archive. If memory serves me correctly, any nonserializable object in the object graph will cause an exception to be thrown when attempting serialization - unless there is code of its own to deal with this case.
Browser other questions tagged java filing-cabinet
You are not signed in. Login or sign up in order to post.
I think it’s prudent to quote that they’re not all the referenced objects that are serialized -- Fields marked with
transient
are not serialized.– Bruno Reis