When objects are being serialized using the writeObject()
method, each individual object is written to the output stream only once. Calls to the Invoking writeObject()
method for on the second and subsequent occurrences, place references to the first occurrence same object a second time places a back-reference to the previously serialized instance in the stream. Correspondingly, the readObject()
method produces at most one actual object instance for each object found present in the input stream ; references that was previously written by writeObject()
become references to the first object found in the stream.
According to the Java API [API 2011], the writeUnshared()
method:
...
This means that the writeUnshared()
/readUnshared()
methods cannot be used for round-trip serialization of data structures that require a one-to-one mapping between objects pre-serialization and objects post-deserialization. One common example of such a data structure is a graph or network of objects that may contain reference cycles.
This means that to serialize a network of objects containing circular references and then to successfully deserialize the same network the writeUnshared()
/readUnshared()
methods must not be used.
Consider the following code example.
Code Block |
---|
public class Person { private String name; Person() { // do nothing - needed for serialization } Person(String theName) { name = theName; } public String getName () { return name; } // other details not relevant to this example } public class Student extends Person implements Serializable { private Professor tutor; Student(){ // do nothing - needed for serialization } Student(String theName, Professor theTutor) { super(theName); tutor = theTutor; } public Professor getTutor() { return tutor; } } public class Professor extends Person implements Serializable { private ArrayList<Student> tutees = new ArrayList<Student>(); Professor(){ // do nothing - needed for serialization } Professor(String theName) { super(theName); } public ArrayList<Student> getTutees () { return tutees; } /** * checkTutees checks that all the tutees * have this Professor as their tutor */ public boolean checkTutees () { boolean result = true; for(Student stu: tutees) { if (stu.getTutor() != this) { result = false; break; } } return result; } } // ... Professor jane = new Professor("Jane"); Student able = new Student("Able", jane); Student baker = new Student("Baker", jane); Student charlie = new Student("Charlie", jane); jane.getTutees().add(able); jane.getTutees().add(baker); jane.getTutees().add(charlie); System.out.println("checkTutees returns: " + jane.checkTutees()); // prints "checkTutees returns: true" |
Professor
and Students
are types that extend the basic type Person
. A student (i.e., an object of type Student
) has a tutor of type Professor
. A professor (i.e., an object of type Professor
) has a list (actually, an ArrayList
) of tutees (of type Student
). The method checkTutees()
checks whether all of the tutees of this professor have this professor as their tutor, returning true
if that is the case and false
otherwise. We then create
Professor Jane who has three tutees, Able, Baker, and Charlie, all of whom have Professor Jane as their tutor. The println()
statement prints true
Issues can arise if writeUnshared()
and readUnshared()
methods are used with these classes as demonstrated in the following noncompliant code example.
Noncompliant Code Example
This noncompliant code example attempts to serialize the data from the example above using writeUnshared()
. However, when the data is deserialized using readUnshared()
, the checkTutees()
method no longer returns true
because the tutor objects of the three students are different objects from the original Professor
object.
Code Block | ||
---|---|---|
| ||
String filename = "serial"; try { System.out.println(" // Serializing using writeUnshared"); ObjectOutputStream ObjectOutputStream oos = new ObjectOutputStream (new FileOutputStream(filename)); oos.writeUnshared(jane); oos.close(); System.out.println("// Deserializing using readUnshared"); ObjectInputStream ois = new ObjectInputStream (new FileInputStream(filename)); Professor jane2 = (Professor)ois.readUnshared(); ois.close(); System.out.println("checkTutees returns: " + jane3.checkTutees()); // prints "checkTutees returns: false" } catch(Exception e) { System.out.println("Exception during deserialization" + e); } |
...