...
According to the Java API [API 20112013], the writeUnshared()
method
writes an "unshared" object to the
ObjectOutputStream
. This method is identical towriteObject
, except that it always writes the given object as a new, unique object in the stream (as opposed to a back-reference pointing to a previously serialized instance).
...
reads an "unshared" object from the
ObjectInputStream
. This method is identical toreadObject
, except that it prevents subsequent calls toreadObject
andreadUnshared
from returning additional references to the deserialized instance obtained via this call.
This means that Consequently, the writeUnshared()
and readUnshared()
methods cannot be used are unsuitable for round-trip serialization of data structures that require a one-to-one mapping between objects preserialization and objects postdeserialization. One common example of such a data structure is a graph or network of objects that may contain reference cycles.
Consider the following code example:
...
Professor
and Students
are types that extend the basic type Person
. A student (that is, an object of type Student
) has a tutor of type Professor
. A professor (that is, 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.
Suppose that Professor Jane has three tuteesstudents, Able, Baker, and Charlie, all of whom have Professor Jane as their tutor. Issues can arise if the 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 previous example 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 from the original Professor
object.
Code Block | ||
---|---|---|
| ||
String filename = "serial"; try(ObjectOutputStream oos = null; try { // Serializing using writeUnsharednew ObjectOutputStream(new oos = new ObjectOutputStream(new FileOutputStream(filename)); oos.writeUnshared(jane); } catch (Exception e) { System.out.println("Exception during serialization" + e); } finally { try { oos.close(); // Serializing using writeUnshared oos.writeUnshared(jane); } catch (IOExceptionThrowable e) { // System.out.println("Exception during serialization" + e); } } Handle error } // Deserializing using readUnshared try(ObjectInputStream ois = null; try {new ObjectInputStream(new ois = new ObjectInputStream(new FileInputStream(filename));){ Professor jane2 = (Professor)ois.readUnshared(); System.out.println("checkTutees returns: " + jane2.checkTutees()); } catch (ExceptionThrowable e) { System.out.println("Exception during deserialization" + e); } finally { try { ois.close(); } catch (IOException e) { System.out.println("Exception during deserialization" + e); } }// Handle error } |
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 from the original Professor
object.
Compliant Solution
This compliant solution overcomes the problem of the noncompliant code example by using uses the writeObject()
and readObject()
, ensuring methods to ensure that the tutor object referred to by the three students has a one-to-one mapping with the original Professor
object. So the The checkTutees()
method correctly returns true
.
Code Block | ||
---|---|---|
| ||
String filename = "serial"; try(ObjectOutputStream oos = null; try { // Serializing using writeUnsharednew ObjectOutputStream(new oos = new ObjectOutputStream(new FileOutputStream(filename)); oos.writeObject(jane); } catch (Exception e) { // System.out.println("Exception during serialization" + e); } finally { try { oos.close(); } catch (IOExceptionSerializing using writeUnshared oos.writeObject(jane); } catch (Throwable e) { System.out.println("Exception during serialization" + e); } }// Handle error } // Deserializing using readUnshared try(ObjectInputStream ois = null; try {new ObjectInputStream(new ois = new ObjectInputStream(new FileInputStream(filename));) { Professor jane2 = (Professor)ois.readObject(); System.out.println("checkTutees returns: " + jane2.checkTutees()); } catch catch (ExceptionThrowable e) { System.out.println("Exception during deserialization" + e); } finally { try { ois.close(); } catch (IOException e) { System.out.println("Exception during deserialization" + e); } }// Handle error } |
Applicability
Using the writeUnshared()
and readUnshared()
methods may produce unexpected results when used for the round-trip serialization of the data structures containing reference cycles.
Bibliography
Class |
...