@JsonBackReference和@JsonManagedReference(解决对象中存在双向引用导致的无限递归)

jackson中的@JsonBackReference和@JsonManagedReference,以及@JsonIgnore均是为了解决对象中存在双向引用导致的无限递归(infinite recursion)问题。这些标注均可用在属性或对应的get、set方法中。  

@JsonBackReference和@JsonManagedReference:这两个标注通常配对使用,通常用在父子关系中。@JsonBackReference标注的属性在序列化(serialization,即将对象转换为json数据)时,会被忽略(即结果中的json数据不包含该属性的内容)。@JsonManagedReference标注的属性则会被序列化。在序列化时,@JsonBackReference的作用相当于@JsonIgnore,此时可以没有@JsonManagedReference。但在反序列化(deserialization,即json数据转换为对象)时,如果没有@JsonManagedReference,则不会自动注入@JsonBackReference标注的属性(被忽略的父或子);如果有@JsonManagedReference,则会自动注入自动注入@JsonBackReference标注的属性。  

@JsonIgnore:直接忽略某个属性,以断开无限递归,序列化或反序列化均忽略。当然如果标注在get、set方法中,则可以分开控制,序列化对应的是get方法,反序列化对应的是set方法。在父子关系中,当反序列化时,@JsonIgnore不会自动注入被忽略的属性值(父或子),这是它跟@JsonBackReference和@JsonManagedReference最大的区别。  

示例测试代码(注意反序列化后的TreeNode[readValue]的children里的parent):  
TreeNode.java  

import java.util.ArrayList;  
import java.util.List;  
  
import org.codehaus.jackson.annotate.JsonBackReference;  
import org.codehaus.jackson.annotate.JsonManagedReference;  
  
public class TreeNode {  
    String name;  
    @JsonBackReference  
//  @JsonIgnore  
    TreeNode parent;  
    @JsonManagedReference  
    List<TreeNode> children;  
  
    public TreeNode() {  
    }  
  
    public TreeNode(String name) {  
        this.name = name;  
    }  
  
    public String getName() {  
        return name;  
    }  
  
    public void setName(String name) {  
        this.name = name;  
    }  
  
    public TreeNode getParent() {  
        return parent;  
    }  
  
    public void setParent(TreeNode parent) {  
        this.parent = parent;  
    }  
  
    public List<TreeNode> getChildren() {  
        return children;  
    }  
  
    public void setChildren(List<TreeNode> children) {  
        this.children = children;  
    }  
  
    public void addChild(TreeNode child) {  
        if (children == null)  
            children = new ArrayList<TreeNode>();  
        children.add(child);  
    }  
}  

JsonTest.java   
Java代码    收藏代码
import java.io.IOException;  
  
import org.codehaus.jackson.JsonGenerationException;  
import org.codehaus.jackson.map.JsonMappingException;  
import org.codehaus.jackson.map.ObjectMapper;  
import org.junit.AfterClass;  
import org.junit.BeforeClass;  
import org.junit.Test;  
  
public class JsonTest {  
    static TreeNode node;  
  
    @BeforeClass  
    public static void setUp() {  
        TreeNode node1 = new TreeNode("node1");  
        TreeNode node2 = new TreeNode("node2");  
        TreeNode node3 = new TreeNode("node3");  
        TreeNode node4 = new TreeNode("node4");  
        TreeNode node5 = new TreeNode("node5");  
        TreeNode node6 = new TreeNode("node6");  
  
        node1.addChild(node2);  
        node2.setParent(node1);  
        node2.addChild(node3);  
        node3.setParent(node2);  
        node2.addChild(node4);  
        node4.setParent(node2);  
        node3.addChild(node5);  
        node5.setParent(node3);  
        node5.addChild(node6);  
        node6.setParent(node5);  
  
        node = node3;  
    }  
  
    @Test   
    public void test() throws JsonGenerationException, JsonMappingException, IOException {  
        ObjectMapper mapper = new ObjectMapper();  
        String json = mapper.writeValueAsString(node);  
        System.out.println(json);  
        TreeNode readValue = mapper.readValue(json, TreeNode.class);  
        System.out.println(readValue.getName());  
    }  
  
    @AfterClass  
    public static void tearDown() {  
        node = null;  
    }  
}  

在前后端分离的项目,我们通常会使用JSON格式来传递数据。但是,如果我们在实体类存在循环引用,就会导致JSON序列化时出现无限递归的情况,导致程序崩溃。 解决这个问题有几种方法: 1. 使用@JsonBackReference和@JsonManagedReference注解 在实体类,我们可以使用@JsonBackReference和@JsonManagedReference注解来解决循环引用的问题。例如: ```java @Entity public class User { @Id private Long id; private String name; @ManyToOne @JsonBackReference private Department department; // getter和setter省略 } @Entity public class Department { @Id private Long id; private String name; @OneToMany(mappedBy = "department") @JsonManagedReference private List<User> users; // getter和setter省略 } ``` @JsonManagedReference注解标注在实体类的一对多关系的“一”方,表示该实体类是被管理方。@JsonBackReference注解标注在实体类的一对多关系的“多”方,表示该实体类是被反向引用方。这样,在序列化时,就不会无限递归了。 2. 使用@JsonIgnore注解 在实体类,我们也可以使用@JsonIgnore注解来忽略某个属性在序列化时的输出。例如: ```java @Entity public class User { @Id private Long id; private String name; @ManyToOne @JsonIgnore private Department department; // getter和setter省略 } @Entity public class Department { @Id private Long id; private String name; @OneToMany(mappedBy = "department") private List<User> users; // getter和setter省略 } ``` 3. 使用DTO(Data Transfer Object) 在实际开发,我们通常会使用DTO(Data Transfer Object)来传递数据。DTO是一个纯粹的数据对象,它不包含任何业务逻辑,只包含实体类需要传递的属性。例如: ```java public class UserDTO { private Long id; private String name; private Long departmentId; // getter和setter省略 } ``` 这样,在序列化时,就不会出现循环引用的问题了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值