I am using the Java Serializable
interface and the ObjectOutputStream
to serialize objects (until now, this method has been sufficient for my purposes).
My API relies on object identity for some operations and I’m wondering if it will be preserved by serialization. That is to say: if, for two arbitrary objects a
and b
, it holds a == b
before serialization, does it still hold after deserialization?
I’ve found some texts that claim the contrary – but they either wrote about an older version of the JRE (I’m only interested in 1.6 and perhaps 1.5), or were concerned with RMI (which is not relevant for me).
The documentation isn’t very forthcoming regarding object identity. A technical article on sun.com mentions that ObjectOutputStream
uses caching on objects, which to me only makes sense if the object identity is indeed preserved but I’m not confident enough to rely on this flimsy evidence.
I’ve tried it out (Java 1.6, OS X) and found that yes, the identity of objects remains unchanged by serialization. But can I extrapolate from these results or are they unreliable?
For my test, I’ve serialized the following object graph:
C----------+ | b1 b2 | +----------+ | | v v B---+ B---+ | a | | a | +---+ +---+ \ / \ / \/ A----+ | | +----+
A minimal reproducing code:
import java.io.*; public class SerializeTest { static class A implements Serializable {} static class B implements Serializable { final A a; public B(A a) { this.a = a; } } static class C implements Serializable { final B b1, b2; public C() { A object = new A(); b1 = b2 = new B(object); } } public static void main(String[] args) throws IOException, ClassNotFoundException { C before = new C(); System.out.print("Before: "); System.out.println(before.b1.a == before.b2.a); // Serialization. ByteArrayOutputStream data = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(data); out.writeObject(before); out.close(); // Deserialization. ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(data.toByteArray())); C after = (C) in.readObject(); System.out.print("After: "); System.out.println(after.b1.a == after.b2.a); } }
Serialization in Java allows us to convert an Object to stream that we can send over the network or save it as file or store in DB for later usage. Deserialization is the process of converting Object stream to actual Java Object to be used in our program.
Serialization is the process of converting an object into a stream of bytes to store the object or transmit it to memory, a database, or a file. Its main purpose is to save the state of an object in order to be able to recreate it when needed. The reverse process is called deserialization.
Since serialization does not offer any transaction control mechanisms per se, it is not suitable for use within applications needing concurrent access without making use of additional APIs.
To serialize an object means to convert its state to a byte stream so that the byte stream can be reverted back into a copy of the object. A Java object is serializable if its class or any of its superclasses implements either the java.
For two arbitrary objects a and b, if it holds a == b before serialization, it will still hold true after deserialization IF:
readResolve()
that has the potential of changing how references are restored back; neither do classes that hold a and b.For all other cases, object identity will NOT be preserved.
The answer is no, by default object identity is not preserved via serialization if you are considering 2 separate serializations of a given object/graph. For example, if a I serialize an object over the wire (perhaps I send it from a client to a server via RMI), and then do it again (in separate RMI calls), then the 2 deserialized objects on the server will not be ==.
However, in a "single serialization" e.g. a single client-server message which is a graph containing the same object multiple times then upon deserialization, identity is preserved.
For the first case, you can, however, provide an implementation of the readResolve
method in order to ensure that the correct instance is returned (e.g. in the typesafe enum pattern). readResolve
is a private method which will be called by the JVM on a de-serialized Java object, giving the object the chance to return a different instance. For example, this is how the TimeUnit
enum
may have been implemented before enum
's were added to the language:
public class TimeUnit extends Serializable { private int id; public TimeUnit(int i) { id = i; } public static TimeUnit SECONDS = new TimeUnit(0); //Implement method and return the relevant static Instance private Object readResolve() throws ObjectStreamException { if (id == 0) return SECONDS; else return this; } }
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With