Feature: Handle bi-directional references using declarative method(s)
(see Jira entry JACKSON-235 for more details)
Before Jackson 1.5, back references such as "parent" links from child objects, previous sibling for doubly-linked lists, and general bi-directional references for ORM-managed beans (iBatis, Hibernate) would cause serialization to failure since they are cyclic dependencies.
In Jackson 1.6 there are 2 new annotations that allow specifying relationship between 2 properties that form such bi-directional dependency so that Jackson can properly omit cycle during serialization, and re-construct during serialization.
New annotations
Annotations are:
@JsonManagedReference is the "forward" part of reference: one that gets serialized normally, and handling of which triggers back-linkage for the other reference
Annotated property can be a bean, array, Collection (List, Set) or Map type, and it must be a bean property (handled by a property of type serialized using BeanSerializer
@JsonBackReference is the "back" part of reference: it will be omitted from serialization, and re-constructed during deserialization of forward reference.
- Annotated property must be of bean type
These annotations can be used for:
* Methods (getters and setters) * Fields
but not for types (classes) or constructor arguments.
Annotations take optional "name" parameter; if omitted default name is used. Name is needed to allow multiple reference pairs for one bean type.
Example
Here is a simple example of a double-linked linked list, where references are both in same class
public class Node
{
public String name; // simple property
// reference with default name
@JsonManagedReference public SimpleTreeNode child; // forward reference, serialized
@JsonBackReference public Node parent; // backward reference, not serialized
public SimpleTreeNode() { this(null); }
public SimpleTreeNode(String n) { name = n; }Linkage also works for structured types (arrays, Collections, Maps), as long as only forward reference is of such type. For example:
public class NodeList
{
@JsonManagedReference
public List<NodeForList> nodes;
}
public class NodeForList
{
public String name;
@JsonBackReference public NodeList parent;
public NodeForList() { this(null); }
public NodeForList(String n) { name = n; }
}and it is possible to use multiple references, by specifying distinct names:
public class FullTreeNode
{
public String name;
// parent-child links
@JsonBackReference("parent")
public FullTreeNode parent;
@JsonManagedReference("parent")
public FullTreeNode firstChild;
// sibling-links
@JsonManagedReference("sibling")
public FullTreeNode next;
@JsonBackReference("sibling")
protected FullTreeNode prev;
public FullTreeNode() { this(null); }
public FullTreeNode(String name) {
this.name = name;
}
}One final note: if using getter and setter methods instead of fields, you will may to add reference annotations on both methods (you will always need them in setters which are used for deserialization; getters for forward references are handled correctly without annotations, but getters for serializing back links do need to be annotated).
Known Issues
(added 25-Sep-2010)
Currently (as of version 1.6.0) combination of abstract types (with polymorphic handling using @JsonTypeInfo) do not work with this feature -- hopefully this can be addressed in future, but there are technical issues that make fix non-trivial. Specific problem is that of deserializer for such types being AbstractDeserializer, which is just a placeholder for real deserializer.
External links
There are some useful articles that show how to use this feature:
* Jackson to the Rescue (with Spring 3.0)
