@JsonIdentityInfo
用于处理对象的循环引用,方法是只在第一次遇到时序列化为完整的对象,之后再遇到同一个对象,都以对象的标识符代替。
生成对象标识符有两种主要方法:使用生成器(标准生成器或自定义生成器之一),或者使用属性的值。后一种情况是通过使用占位符生成器标记ObjectIdGenerators.PropertyGenerator来指示的;前者使用显式生成器。对象id必须序列化为pojo的属性;对象标识目前不支持JSON数组类型(Java数组或列表)或Java Map类型。
@JsonIdentityInfo annotation:
public @interface JsonIdentityInfo
{
// Object ID 的 JSON 属性名
public String property() default "@id";
// Object ID 的生成器
public Class<? extends ObjectIdGenerator<?>> generator();
// 将 Object ID 解析回对象的解析器
public Class<? extends ObjectIdResolver> resolver() default SimpleObjectIdResolver.class;
public Class<?> scope() default Object.class;
}
预定义的 ObjectIdGenerator
这些实现在 ObjectIdGenerators
中:
Example
POJOs
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public class Customer {
private int id;
private String name;
private Order order;
...
}
public class Order {
private int orderId;
private List<Integer> itemIds;
private Customer customer;
...
}
Main class
public class ExampleMain {
public static void main(String[] args) throws IOException {
Order order = new Order();
order.setOrderId(1);
order.setItemIds(List.of(10, 30));
Customer customer = new Customer();
customer.setId(2);
customer.setName("Peter");
customer.setOrder(order);
order.setCustomer(customer);
System.out.println(customer);
System.out.println("-- serializing --");
ObjectMapper om = new ObjectMapper();
String s = om.writeValueAsString(customer);
System.out.println(s);
System.out.println("-- deserializing --");
Customer customer2 = om.readValue(s, Customer.class);
System.out.println(customer2);
}
}
Customer{id=2, name='Peter', order=Order{id=1, itemIds=[10, 30]}}
-- serializing --
{"id":2,"name":"Peter","order":{"orderId":1,"itemIds":[10,30],"customer":2}}
-- deserializing --
Customer{id=2, name='Peter', order=Order{id=1, itemIds=[10, 30]}}
不使用 @JsonIdentityInfo
无限循环导致栈溢出:
Customer{id=2, name='Peter', order=Order{id=1, itemIds=[10, 30]}}
-- serializing --
Exception in thread "main" com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion (StackOverflowError) (through reference chain: org.example.c36.Order["customer"]->org.example.c36.Customer["order"]->org.example.c36.Order["customer"]->org.example.c36.Customer["order"]->org.example.c36.Order["customer"]->org.example.c36.Customer["order"]-...
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:785)
at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:178)
at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:728)
涉及一对多、多对多关系
Employee 与 Dept 多对多的例子:
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "empId")
public class Employee {
private int empId;
private List<Dept> depts;
...
}
public class Dept {
private int deptId;
List<Employee> employees;
...
}
public class ExampleMain2 {
public static void main(String[] args) throws IOException {
Employee emp = new Employee();
emp.setEmpId(1);
Dept dept1 = new Dept();
dept1.setDeptId(3);
dept1.setEmployees(List.of(emp));
Dept dept2 = new Dept();
dept2.setDeptId(4);
dept2.setEmployees(List.of(emp));
System.out.println("-- before serializing --");
System.out.println(emp);
System.out.println("-- json string after serializing --");
ObjectMapper om = new ObjectMapper();
String s = om.writeValueAsString(emp);
System.out.println(s);
System.out.println("-- deserializing --");
Employee employee = om.readValue(s, Employee.class);
System.out.println(employee);
System.out.println("-- deserialized back references --");
for (Dept dept : employee.getDepts()) {
System.out.println(dept + " -> " + dept.getEmployees());
}
}
}
-- before serializing --
Employee{empId=1, depts=[Dept{deptId=3}, Dept{deptId=4}]}
-- json string after serializing --
{"empId":1,"depts":[{"deptId":3,"employees":[1]},{"deptId":4,"employees":[1]}]}
-- deserializing --
Employee{empId=1, depts=[Dept{deptId=3}, Dept{deptId=4}]}
-- deserialized back references --
Dept{deptId=3} -> [Employee{empId=1, depts=[Dept{deptId=3}, Dept{deptId=4}]}]
Dept{deptId=4} -> [Employee{empId=1, depts=[Dept{deptId=3}, Dept{deptId=4}]}]
原文链接
Jackson JSON - Using @JsonIdentityInfo to handle circular references