Does Java Serialization work for cyclic references?
Asked Answered
G

5

18

For example: Object A contains Object B that contains Object C that contains Object A.

Will Object A serialize properly?

Comment #9 here indicates that it does not work .

In contrast, XStream indicates that it does handle cyclic references.

Goines answered 24/11, 2009 at 19:50 Comment(3)
Not with hash sets. See: bugs.java.com/bugdatabase/view_bug.do?bug_id=6208166Bryner
official specs say it should work: docs.oracle.com/en/java/javase/17/docs/specs/serialization/…Ormuz
@Bryner this a report for 1.4: I bet it's outdated... (here is an updated link btw: bugs.java.com/bugdatabase/view_bug?bug_id=6208166 )Ormuz
E
19

Yes, the default Java serialization works for cyclic references. When you serialize object C, the field will contain a backreference to the already-serialized object A instead of serializing it again.

Engen answered 24/11, 2009 at 19:53 Comment(1)
Is there any documentation on how this works... I would like to handle this in one of my own serialization implementations.Camelliacamelopard
K
5

Yes, Java serialization works for circular references, read here for more information to help your understanding of what Java serialization can do.

Kalmar answered 24/11, 2009 at 20:4 Comment(1)
Thanks from your link "Special cases like circular references and multiple references to a single object are preserved such that when the tree graph gets recreated new objects don't magically appear where a reference to another object in the tree should be." java.sun.com/developer/technicalArticles/ALT/serializationGoines
N
3

Yes it does.

I did this very, very, simple test, and at least it finish the serialization. I assume it is correct, but you can check that with some extra lines.

import java.io.*;
class A implements Serializable { B b; }
class B implements Serializable { C c; }
class C implements Serializable { A a; }
class Test {
    public static void main( String [] args ) throws IOException {
        A a = new A();
        a.b = new B();
        a.b.c = new C();
        a.b.c.a = a;
        new ObjectOutputStream( new ByteArrayOutputStream( ) ).writeObject( a );
        System.out.println("It works");

    }    
}
Nitrous answered 24/11, 2009 at 20:42 Comment(0)
G
3

Yes - with one big caveat: You can't use writeReplace/readResolve where the object graph contains a cycle. The reason is explained here.

This means that cyclic object graphs are incompatible with use of Josh Bloch's SerializationProxy pattern in the general case. You can work around this sometimes if you know enough about the structure of descendant nodes in the object graph to remove back references on serialization and replace them on deserialization. But that is not generally possible. This issue has been raised in JDK bug reports several times but was met with shrugs. I think given the vulnerability of default Java serialization this attitude is pretty irritating. We are left to implement our own general object serialization solution which is a daunting task, but open source alternatives exist.

One that I have come across and which appears to be of a reasonably high quality is Kryo by Esoteric Software.

Gobbler answered 25/1, 2022 at 3:3 Comment(0)
B
0

You can actually view the referencing firsthand if you serialize your object to XML. The child objects are only serialized once. Any reference (anywhere in the serialized structure) to a child object that has already been serialized will simply point to that object in the file.

Serializing cyclic references can get a little messy, though, so you might want to avoid them if you can.

Boart answered 24/11, 2009 at 20:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.