@JsonIdentityInfo 处理循环引用

@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 中:

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

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值