Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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)

like image 695
MalteJ Avatar asked Jul 22 '14 14:07

MalteJ


People also ask

What is the use of Jackson annotations?

This annotation allows any method to be marked as a setter method. This annotation is used to specify a custom deserializer in order to unmarshall a JSON object. Using this annotation, we use a default value for deserializing an unknown enum value.

What is @JsonManagedReference and @JsonBackReference?

@JsonManagedReference is the forward part of reference, the one that gets serialized normally. @JsonBackReference is the back part of reference; it'll be omitted from serialization.

What is @JsonIdentityInfo?

The @JsonIdentityInfo annotation is used when an object has a parent-child relationship in the Jackson library. The @JsonIdentityInfo annotation is used to indicate the object identity during the serialization and deserialization process.


1 Answers

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.

like image 115
MalteJ Avatar answered Oct 05 '22 07:10

MalteJ