How to use @JsonIdentityInfo with circular references?

Burkhard picture Burkhard · May 18, 2016 · Viewed 35.1k times · Source

I am trying to use the @JsonIdentityInfo from Jackson 2 as described here.

For testing purposes I created the following two classes:

public class A
{
    private B b;
    // constructor(s) and getter/setter omitted
}
public class B
{
    private A a;
    // see above
}

Of course, the naive approach failes:

@Test
public void testJacksonJr() throws Exception
{
    A a = new A();
    B b = new B(a);
    a.setB(b);
    String s = JSON.std.asString(a);// throws StackOverflowError
    Assert.assertEquals("{\"@id\":1,\"b\":{\"@id\":2,\"a\":1}}", s);
}

Adding @JsonIdentityInfo(generator=ObjectIdGenerators.IntSequenceGenerator.class, property="@id") to class A and/or class B does not work either.

I was hoping that I could serialize (and later deserialize) a to something like this: (not too sure about the JSON though)

{
    "b": {
        "@id": 1,
        "a": {
            "@id": 2,
            "b": 1
        }
    }
}

How can I do that?

Answer

Sotirios Delimanolis picture Sotirios Delimanolis · May 18, 2016

It seems jackson-jr has a subset of Jackson's features. @JsonIdentityInfo must not have made the cut.

If you can use the full Jackson library, just use a standard ObjectMapper with the @JsonIdentityInfo annotation you suggested in your question and serialize your object. For example

@JsonIdentityInfo(generator=ObjectIdGenerators.IntSequenceGenerator.class, property="@id")
public class A {/* all that good stuff */}

@JsonIdentityInfo(generator=ObjectIdGenerators.IntSequenceGenerator.class, property="@id")
public class B {/* all that good stuff */}

and then

A a = new A();
B b = new B(a);
a.setB(b);
ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.writeValueAsString(a));

will generate

{
    "@id": 1,
    "b": {
        "@id": 2,
        "a": 1
    }
}

where the nested a is referring to the root object by its @id.