views:

412

answers:

3

I am writing a serializer to serialize POJO to JSON but stuck in circular reference problem. In hibernate bidirectional one-to-many relation, parent references child and child references back to parent and here my serializer dies. (see example code below)
How to break this cycle? Can we get owner tree of an object to see whether object itself exists somewhere in its own owner hierarchy? Any other way to find if the reference is going to be circular? or any other idea to resolve this problem?

A: 

Can a bi-directional relationship even be represented in JSON? Some data formats are not good fits for some types of data modelling.

One method for dealing with cycles when dealing with traversing object graphs is to keep track of which objects you've seen so far (using identity comparisons), to prevent yourself from traversing down an infinite cycle.

matt b
I did the same and it works but not sure will it work in all mapping scenarios. At least for now I am well set and will keep thinking on having more elegant idea
Leslie Norman
Of course they can -- there just isn't native data type or structure for this. But anything can be represented in XML, JSON, or most other data formats.
StaxMan
I'm curious - how would you represent a circular reference in JSON?
matt b
Multiple ways: keep in mind that generally it's not just JSON, but combination of JSON and some metadata, most commonly class definitions you use to bind to/from JSON. For JSON it's just question of whether to use object identity of some kind, or recreate linkage (Jackson lib for example has a specific way to represent parent/child linkage).
StaxMan
+2  A: 

I rely on Google JSON To handle this kind of issue by using The feature

Excluding Fields From Serialization and Deserialization

Suppose a bi-directional relationship between A and B class as follows

public class A implements Serializable {

    private B b;

}

And B

public class B implements Serializable {

    private A a;

}

Now use GsonBuilder To get a custom Gson object as follows (Notice setExclusionStrategies method)

Gson gson = new GsonBuilder()
    .setExclusionStrategies(new ExclusionStrategy {

        public boolean shouldSkipClass(Class<?> clazz) {
            return (clazz == B.class);
        }

        /**
          * Custom field exclusion goes here
          */
        public boolean shouldSkipField(FieldAttributes f) {
            return false;
        }

     })
    /**
      * Use serializeNulls method if you want To serialize null values 
      * By default, Gson does not serialize null values
      */
    .serializeNulls()
    .create();

Now our circular reference

A a = new A();
B b = new B();

a.setB(b);
b.setA(a);

String json = gson.toJson(a);
System.out.println(json);

Take a look at GsonBuilder class

Arthur Ronald F D Garcia
Thank you Arthur for your kind suggestion but the actual question is what is the best way to build so called generic "shouldSkipClass" method. For now I worked on matt's idea and resolved my issue but still skeptic, in future this solution may break in certian scenarios.
Leslie Norman
A: 

Jackson 1.6 (released september 2010) has specific annotation-based support for handling such parent/child linkage, see http://wiki.fasterxml.com/JacksonFeatureBiDirReferences.

You can of course already exclude serialization of parent link already using most JSON processing packages (jackson, gson and flex-json at least support it), but the real trick is in how to deserialize it back (re-create parent link), not just handle serialization side. Although sounds like for now just exclusion might work for you.

StaxMan