Annotation @JsonIdentityInfo giải quyết vấn đề **circular reference** (tham chiếu vòng) khi serialize object có quan hệ parent-child (bidirectional). Nó dùng **Object Identity** để tham chiếu object đã serialize thay vì lồng lặp vô tận.
Cú pháp
@Target({ANNOTATION_TYPE, TYPE, FIELD, METHOD, PARAMETER})
@Retention(RUNTIME)
public @interface JsonIdentityInfo {
Class<? extends ObjectIdGenerator> generator() default ObjectIdGenerators.IntSequenceGenerator.class;
String property() default "";
// ... các thuộc tính khác: scope, resolver...
}
Ví dụ: Quan hệ User - Address (Bidirectional)
import com.fasterxml.jackson.annotation.*;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.*;
public class JsonIdentityInfoTest {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
User user = new User(115, "Raja", "Ramesh");
Address address = new Address(125, "Madhapur", "Hyderabad", user);
user.addAddress(address);
String json = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(address);
System.out.println(json);
}
}
@JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "userId"
)
class User {
private int userId;
private String firstName, lastName;
private List<Address> addresses = new ArrayList<>();
public User(int userId, String firstName, String lastName) {
this.userId = userId; this.firstName = firstName; this.lastName = lastName;
}
// getters...
public void addAddress(Address a) { addresses.add(a); }
}
@JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "userId"
)
class Address {
private int userId; // Property dùng làm ID
private String city, street;
private User user; // Back-reference
public Address(int userId, String street, String city, User user) {
this.userId = userId; this.street = street; this.city = city; this.user = user;
}
// getters...
}
Output
{
"userId" : 125,
"city" : "Hyderabad",
"street" : "Madhapur",
"user" : {
"userId" : 115,
"firstName" : "Raja",
"lastName" : "Ramesh"
}
}
Không có @JsonIdentityInfo: Serialize address → user → addresses → address → ... → StackOverflowError.
Các Generator phổ biến
- PropertyGenerator: Dùng property của object làm ID (như ví dụ
userId). - IntSequenceGenerator: Tự gán ID số nguyên tăng dần (mặc định).
- UUIDGenerator: Dùng UUID.
- Custom Generator: Implement
ObjectIdGenerator.
Lưu ý
- Cả hai phía quan hệ (parent & child) đều cần @JsonIdentityInfo với generator/property tương thích.
- Property dùng làm ID phải **unique** trong scope serialization.
- Deserialize: Jackson tự resolve reference dựa trên ID.
- Alternative:
@JsonManagedReference+@JsonBackReference(xem bài tiếp theo).