How To Use Jackson's @JsonIdentityInfo for Deserialization of directed Graphs?

17,678

I got kind of blind of staring too long at it. Here's what's gone wrong:

The Serialization actually worked as intended. What didn't work was the Deserialization, because Jackson wasn't able to instantiate my Node-Object. I simply forgot to annotate the parameters of the constructor methods correctly.

I was now facing another problem. The generated JSON now looked like this:

"graph": {
  "nodes": [{
    "name": "B",
    "edges": [{
      "label": "1",
      "successor": "B"
    }, {
      "label": "0",
      "successor": {
        "name": "A",
        "edges": [{
          "label": "1",
          "successor": "A"
        }, {
          "label": "0",
          "successor": "B"
        }]
      }
    }]
  }, "A"]
}

So far so good. But during mapping, Jackson confronts me with this Error:

java.lang.IllegalStateException: Could not resolve Object Id [B] (for [simple
type, class some.package.graph.Node]) -- unresolved forward-reference?

I even changed the Label of the edges because I thought the same property name might confuse Jackson here, but that didn't help either...

My guess here is that Jackson can't reference the Node B, because it is still being constructed (you could say it is actually some kind of root in this example). The only way to fix this seems to construct all the Nodes without the edges and inject them in a second step.

Share:
17,678
MalteJ
Author by

MalteJ

Updated on July 22, 2022

Comments

  • MalteJ
    MalteJ almost 2 years

    I want to use Jackson 2.3.3 for Deserialization/Serialization of directed graphs. The structure I came up with is roughly the following:

    public Class Graph {
        private final Set<Node> nodes;
        public Graph(Set<Node> nodes) { ... }
        public Set<Node> getNodes() { ... }
    }
    
    @JsonIdentityInfo(
            generator = ObjectIdGenerators.PropertyGenerator.class,
            property = "name")
    public Class Node {
        private final String name;
        private final Set<Edge> edges;
        public Node(String name, Set<Edge> edges) { ... }
        public String getName() { ... }
        public Set<Edge> getEdges() { ... }
    }
    
    @JsonIdentityInfo(
            generator = ObjectIdGenerators.PropertyGenerator.class,
            property = "name")
    public Class Edge {
        private final String name;
        private final Node successor;
        public Edge(String name, Node successor) { ... }
        public String getName() { ... }
        public Node getSuccessor() { ... }
    }
    

    And I expect to have this JSON-Structure:

    {
      "graph": [{
        "name": "A",
        "edges": [{
          "name": "0",
          "successor": "B"
        }, {
          "name": "1",
          "successor": "A"
        }]
      }, {
        "name": "B",
        "edges": [{
          "name": "0",
          "successor": "A"
        }, {
          "name": "1",
          "successor": "B"
        }]
      }]
    }
    

    But I get the following error while deserialization (even with annotation @JsonProperty("name") at the Getters):

    com.fasterxml.jackson.databind.JsonMappingException: Invalid Object Id definition for some.package.graph.Node: can not find property with name 'name'

    I have found some solutions for Jackson 1.6 with Back-Reference Annotations, but I'd like to use the new Jackson 2.x Annotation, as it was advertised so much in the API Update from 1.9 to 2.0 of Jackson.

    What point am I missing here? Thanks for constructive answers in advance.

    EDIT

    (Removed my answer from here to the Answer section)