springmvc @ResponseBody 返回json数据错误

 

原因:父子关系,导致jackson 死循环: 解决方案如下:见红色处

 

@JsonBackReference @JsonManagedReference @JsonIgnore

 
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 
Java代码  收藏代码
  1. import java.util.ArrayList;  
  2. import java.util.List;  
  3.   
  4. import org.codehaus.jackson.annotate.JsonBackReference;  
  5. import org.codehaus.jackson.annotate.JsonManagedReference;  
  6.   
  7. public class TreeNode {  
  8.     String name;  
  9.     @JsonBackReference  
  10. //  @JsonIgnore  
  11.     TreeNode parent;  
  12.     @JsonManagedReference  
  13.     List<TreeNode> children;  
  14.   
  15.     public TreeNode() {  
  16.     }  
  17.   
  18.     public TreeNode(String name) {  
  19.         this.name = name;  
  20.     }  
  21.   
  22.     public String getName() {  
  23.         return name;  
  24.     }  
  25.   
  26.     public void setName(String name) {  
  27.         this.name = name;  
  28.     }  
  29.   
  30.     public TreeNode getParent() {  
  31.         return parent;  
  32.     }  
  33.   
  34.     public void setParent(TreeNode parent) {  
  35.         this.parent = parent;  
  36.     }  
  37.   
  38.     public List<TreeNode> getChildren() {  
  39.         return children;  
  40.     }  
  41.   
  42.     public void setChildren(List<TreeNode> children) {  
  43.         this.children = children;  
  44.     }  
  45.   
  46.     public void addChild(TreeNode child) {  
  47.         if (children == null)  
  48.             children = new ArrayList<TreeNode>();  
  49.         children.add(child);  
  50.     }  
  51. }  

JsonTest.java 
Java代码  收藏代码
  1. import java.io.IOException;  
  2.   
  3. import org.codehaus.jackson.JsonGenerationException;  
  4. import org.codehaus.jackson.map.JsonMappingException;  
  5. import org.codehaus.jackson.map.ObjectMapper;  
  6. import org.junit.AfterClass;  
  7. import org.junit.BeforeClass;  
  8. import org.junit.Test;  
  9.   
  10. public class JsonTest {  
  11.     static TreeNode node;  
  12.   
  13.     @BeforeClass  
  14.     public static void setUp() {  
  15.         TreeNode node1 = new TreeNode("node1");  
  16.         TreeNode node2 = new TreeNode("node2");  
  17.         TreeNode node3 = new TreeNode("node3");  
  18.         TreeNode node4 = new TreeNode("node4");  
  19.         TreeNode node5 = new TreeNode("node5");  
  20.         TreeNode node6 = new TreeNode("node6");  
  21.   
  22.         node1.addChild(node2);  
  23.         node2.setParent(node1);  
  24.         node2.addChild(node3);  
  25.         node3.setParent(node2);  
  26.         node2.addChild(node4);  
  27.         node4.setParent(node2);  
  28.         node3.addChild(node5);  
  29.         node5.setParent(node3);  
  30.         node5.addChild(node6);  
  31.         node6.setParent(node5);  
  32.   
  33.         node = node3;  
  34.     }  
  35.   
  36.     @Test  
  37.     public void test() throws JsonGenerationException, JsonMappingException, IOException {  
  38.         ObjectMapper mapper = new ObjectMapper();  
  39.         String json = mapper.writeValueAsString(node);  
  40.         System.out.println(json);  
  41.         TreeNode readValue = mapper.readValue(json, TreeNode.class);  
  42.         System.out.println(readValue.getName());  
  43.     }  
  44.   
  45.     @AfterClass  
  46.     public static void tearDown() {  
  47.         node = null;  
  48.     }  
  49. }  


参考: 
http://wiki.fasterxml.com/JacksonFeatureBiDirReferences 
jira:http://jira.codehaus.org/browse/JACKSON-235 

备注: 
jackson版本:1.9.9 

似乎jackson从2.0开始可以通过@JsonIdentityInfo解决无限递归的问题,但本人没验证。 

有兴趣还可以研究研究这篇文章里的方式: 
http://www.linuxso.com/architecture/26599.html
 
 
posted @ 2012-11-21 17:25  eggbucket  阅读(3230)  评论(0编辑  收藏  举报