0

I am using Jackson to serialize JSON, but my JSON clients are not Java, and don't use Jackson.

I want to avoid circular reference serialization infinite recursion by, whenever serializing a whole bean would cause an infinite recursion, serializing the id of the bean instead of the whole bean.

This can be accomplished by maintaining a stack of the current serialization context.

Whenever Jackson starts to serialize a bean, it should see if the stack contains the bean.

If the bean is already in the stack, serialize the id instead of the whole bean, thereby avoiding the infinite recursion.

If the bean is not in the stack, push it onto the stack, and serialize the whole bean normally.

Once Jackson has finished serializing the bean, pop the bean off the stack.

Therefore, I want the following Java to serialize into the following JSON:

Java:

class A {
    String id;
    B      b;
    B      c;
}

class B {
    String id;
    A      a;
}

class Main {
    public static void main(String[] args) {
        A a = new A();
        B b = new B();
        a.id = "a1";
        b.id = "b1";
        a.b = b;
        a.c = b;
        b.a = a;
        ObjectMapper m = new ObjectMapper();
        System.out.println(m.writeValueAsString(a));
        System.out.println(m.writeValueAsString(b));
    }
}

JSON:

{
    "id": "a1",
    "b": {
        "id": "b1",
        "a":  "a1"
    },
    "c": {
        "id": "b1",
        "a":  "a1"
    }
}

{
    "id": "b1",
    "a": {
        "id": "a1",
        "b":  "b1"
    }
}

I only know of two built-in Jackson ways to handle circular references, neither of which, if I understand them correctly, can output the above JSON:

  1. @JsonIdentityInfo, which, when best setup, annotating both A & B with:

    @JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
    

    would output (with a comment indicating the problem):

    {
        "id": "a1",
        "b": {
            "id": "b1",
            "a":  "a1"
        },
        "c": "b1" // problem: value of "c" is b.id instead of b with b.a = a.id
    }
    
    {
        "id": "b1",
        "a": {
            "id": "a1",
            "b":  "b1"
        }
    }
    
  2. @JsonManagedReference & @JsonBackReference, for which I have to specify one side as forward, and the other as back. Say I choose A -> B properties as forward, then I get:

    {
        "id": "a1",
        "b": {
            "id": "b1",
            "a":  "a1"
        },
        "c": {
            "id": "b1",
            "a":  "a1"
        }
    }
    
    {
        "id": "b1"
        // problem: "a" isn't serialized
    }
    

Is there any built-in Jackson way to serialize as I desire?

If not, does Jackson maintain a serialization stack?

If so, how can I access it, and somehow modify the serialization output?

If not, how can I hook into Jackson to maintain a stack in my own classes that implement some Jackson interfaces / extend some Jackson classes, and then use that stack to influence serialization?

XDR
  • 4,070
  • 3
  • 30
  • 54

1 Answers1

1

Jackson does maintain couple of stacks. The older one is at JsonGenerator level, see getOuputContext(). That lets you see what is being output physically, that is, which scopes (Object, Array) are open.

But Jackson 2.5 added new method, JsonGenerator.getCurrentValue(), and matching calls from databind, which should additionally give you Object graph view of what is being serialized, at least when combining the two. To access ancestors of the current value, you need to traverse "output context", ask for current value up the output stack.

StaxMan
  • 113,358
  • 34
  • 211
  • 239
  • Thanks. This should solve it. I'll comment again later to verify that I've successfully implemented the functionality using this stack. I'm just busy with some other work for a little while. – XDR May 05 '15 at 12:39
  • @XDR I hope so; mechanism is quite powerful (and low overhead from databinding perspective), but being a new feature not well known. But it is also something that was asked for a long time, to help with contextual handling. – StaxMan May 05 '15 at 19:31