Feature: Object Identity (or Object Identifier / Object Id)
(see Jira entry JACKSON-107 for details)
Background
Before Jackson 2.0, handling of cyclic object graphs (or, more generally, that of shared references) was limited to specific case of parent/child (bi-directional) references. While this could be used to support straight-forward one-to-many and one-to-one references that are common with database models, it is not a general solution.
Since 2.0 allowed bigger changes to API and internal interfaces, more general solution was planned for this release
General Approach
At high level, there are two major alternatives for handling Object Identity:
- Transparent: library handles identity of all objects, without input from user (except for possible big enable/disable switch)
Explicit: library allows enabling/disabling use of Object Identity, similar to how Type Id handling works.
Benefit of the first approach is that it would be universal, and work for general Java Object serialization use case. The big downsides include:
- Invasive for JSON: all JSON structures would potentially require addition of a Type Identifier
- Invasive for API: support would need to be added for most handlers for both serialization and deserialization
Conversely, second approach has opposite benefits/drawbacks:
- Benefit: less invasive (JSON, API)
Benefit: similarities with handling of Type Id; easier to understand, control
- Drawback: require additional indicators from user/framework, to indicate where to add Object Id
- Drawback: may have restrictions on kinds of objects that support Object Id
Chosen Approach
Given these trade-offs, it seemed more feasible to use approach of requiring explicit enabling of Object Identity handling. In the first phase (2.0), all types must be explicitly annotated (possibly with mix-ins); although this could be extended to allow "default Object Identity", similar to how "default typing" can be used with Type Id.
New annotation: @JsonIdentityInfo
Whether Object Identity information is to be used for determining how to serialize/deserialize property value to/from JSON (and other data formats) will be based on existence (or lack thereof) of @JsonIdentityInfo annotation. It can be used on classes (to indicate that properties of that type should have feature enabled) as well as on individual properties (to support cases where type itself can not be annotated; or to use different id generation sequence).
A simple example would be:
@JsonIdentityInfo(generator=ObjectIdGenerators.IntSequenceGenerator.class, property="@id")
public class Identifiable
{
public int value;
public Identifiable next;
}and if we created a cycle consisting of two values, like:
Identifiable ob1 = new Identifiable(); ob1.value = 13; Identifiable ob2 = new Identifiable(); ob2.value = 42; // link as a cycle: ob1.next = ob2; ob2.next = ob1;
and serialized using:
String json = objectMapper.writeValueAsString(ob1);
we would get following serialization for JSON:
{
"@id" : 1,
"value" : 13,
"next" : {
"@id" : 2,
"value" : 42,
"next" : 1
}
}This example shows couple of notable things:
Standard ObjectIdGenerator used (IntSequenceGenerator}) will produce integer ids, starting with value 1: hence ids 1 and 2, in order that the Objects are encountered
First time an Object with expected Object Id is encountered, it will be serialized as is: but all further references (in this case "id2.next", which refers to "id1") will be serialized using Object Id of that object.
Finally: we would deserialize such JSON using usual calls:
Identifiable result = objectMapper.readValue(json, Identifiable.class);
