当尝试将具有双向关联的JPA对象转换为JSON时,我不断得到
org.codehaus.jackson.map.JsonMappingException:无限递归(StackOverflower错误)
我只找到了此线程的基本结论是建议避免双向关联。有没有人有办法解决这个spring bug
——编辑2010-07-2416:26:22——-
代码片段:
业务对象1:
@Entity
@表(名称=“TAU培训生”,uniqueConstraints={@UniqueConstraint(columnNames={id})})
公共类培训生扩展BusinessObject{
@身份证
@GeneratedValue(策略=GenerationType.TABLE)
@列(名称=“id”,可空=false)
私有整数id;
@列(name=";name";,null=true)
私有字符串名称;
@列(名称=“姓氏”,可空=真)
私家姓;
@OneToMany(mappedBy=“培训生”,fetch=FetchType.EAGER,cascade=CascadeType.ALL)
@列(nullable=true)
私人设置<;BodyStat>;bodyStats;
@OneToMany(mappedBy=“培训生”,fetch=FetchType.EAGER,cascade=CascadeType.ALL)
@列(nullable=true)
私人设置<;培训>;培训;
@OneToMany(mappedBy=“培训生”,fetch=FetchType.EAGER,cascade=CascadeType.ALL)
@列(nullable=true)
私有集<;ExerciseType>;exerciseTypes;
公共培训生(){
超级();
}
//…接受者/接受者。。。
}
业务对象2:
导入javax.persistence.*;
导入java.util.Date;
@实体
@表(name=";tau bodystat";,uniqueConstraints={@UniqueConstraint(columnNames={";id";})})
公共类BodyStat扩展了BusinessObject{
@身份证
@GeneratedValue(策略=GenerationType.TABLE)
@列(名称=“id”,可空=false)
私有整数id;
@列(名称=“高度”,可空=真)
私人浮动高度;
@列(name=";measuretime";,null=false)
@时态(TemporalType.TIMESTAMP)
私人日期测量时间;
@manytone(fetch=FetchType.EAGER,cascade=CascadeType.ALL)
@JoinColumn(名称=“培训生fk”)
私人见习生;
}
控制器:
import org.slf4j.Logger;
导入org.slf4j.LoggerFactory;
导入org.springframework.beans.factory.annotation.Autowired;
导入org.springframework.stereotype.Controller;
导入org.springframework.ui.Model;
导入org.springframework.web.bind.annotation.RequestBody;
导入org.springframework.web.bind.annotation.RequestMapping;
导入org.springframework.web.bind.annotation.RequestMethod;
导入org.springframework.web.bind.annotation.ResponseBody;
导入javax.servlet.http.HttpServletResponse;
导入javax.validation.ConstraintViolation;
导入java.util.*;
导入java.util.concurrent.ConcurrentHashMap;
@控制器
@请求映射(值=“学员”)
公营实习控制员{
最终记录器=LoggerFactory.getLogger(实习控制器类);
私有映射<;Long,培训生>;培训生=新ConcurrentHashMap<;Long,培训生>;();
@自动连线
私营工矿局培训生局;
/**
*返回所有学员的json代表
*/
@RequestMapping(值=";/GetAllInter培训生";,方法=RequestMethod.GET)
@应答器
公共集合GetAllInter培训生(){
Collection all培训生=this.traineeDAO.getAll();
this.logger.debug(“从db”中读取了总共“+all培训生.size()+”培训生”);
归还所有学员;
}
}
JPA学员DAO的实施:
@Repository
@交易的
公共类TraineDao实施iTraineDao{
@持久上下文
私人实体管理者;
@交易的
公共实习生储蓄(实习生){
em.persist(培训生);
返回学员;
}
@事务(只读=真)
公共集合getAll(){
return(Collection)em.createQuery(“从学员t中选择t”).getResultList();
}
}
persistence.xml
<;持久性xmlns=";http://java.sun.com/xml/ns/persistence"
xmlns:xsi=";http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=";http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
版本=";1.0“&燃气轮机;
<;持久性单元名称=“持久性单元名称”;“关系数据库管理系统”;交易类型=";资源“本地”&燃气轮机;
<;排除未列出的类别>;假</排除未列出的类别>;
<;房地产>;
<;属性名称=“属性名称”;hibernate.hbm2ddl.auto;值=”;“验证”/&燃气轮机;
<;属性名称=“属性名称”;hibernate.archive.autodetection“;值=”;“类”/&燃气轮机;
<;属性名称=“属性名称”;方言;值=”;org.hibernate.dialogue.mysql5innodbdialogue“/&燃气轮机;
<;!--&书信电报;属性名称=“属性名称”;方言;值=”;org.hibernate.dialogue.hsqldialogue“/&燃气轮机--&燃气轮机;
</房地产>;
</持久性单位>;
</持久性>;
JsonIgnoreProperties[2017年更新]:
您现在可以使用JsonIgnoreProperties到抑制属性序列化(在序列化期间),或忽略JSON属性读取的处理(在反序列化期间)。如果这不是你想要的,请继续阅读下面的内容
(感谢As Zammel AlaaEddine指出这一点)
JsonManagedReference和JsonBackReference
自Jackson 1.6以来,您可以使用两个注释来解决无限递归问题,而不必在序列化过程中忽略getter/setter:@JsonManagedReference
和@JsonBackReference
解释
为了使Jackson能够很好地工作,不应该序列化关系的两个方面之一,以避免导致stackoverflow错误的infite循环
因此,Jackson获取引用的前半部分(培训生类中的Set<;BodyStat>;bodyStats
),并将其转换为类似json的存储格式;这就是所谓的编组过程。然后,Jackson查找引用的后半部分(即,培训生类中的培训生
)并保持原样,而不是序列化。这部分关系将在前向引用的反序列化(解组)过程中重新构建
您可以这样更改代码(我跳过无用的部分):
业务对象1:
@实体
@表(name=“ta_培训生”,uniqueConstraints={@UniqueConstraint(columnNames={“id”})})
公共类培训生扩展BusinessObject{
@OneToMany(mappedBy=“培训生”,fetch=FetchType.EAGER,cascade=CascadeType.ALL)
@列(nullable=true)
@JsonManagedReference
私人设置<;BodyStat>;bodyStats;
业务对象2:
@实体
@表(name=“ta_bodystat”,uniqueConstraints={@UniqueConstraint(columnNames={“id”})})
公共类BodyStat扩展了BusinessObject{
@manytone(fetch=FetchType.EAGER,cascade=CascadeType.ALL)
@JoinColumn(name=“培训生”
@JsonBackReference
私人见习生;
现在一切都应该正常工作了
如果你想了解更多信息,我写了一篇关于关于Keeformatics的Json和Jackson Stackoverflow问题,我的博客
编辑:
您可以检查的另一个有用的注释是@JsonIdentityInfo:使用它,每次Jackson序列化您的对象时,它都会添加一个ID(或您选择的另一个属性)这样它就不会每次都完全“扫描”它。当你在更多相关的对象(例如:订单->订单行->用户->订单等)之间有一个链式循环时,这会很有用
在这种情况下,您必须小心,因为您可能需要多次读取对象的属性(例如,在产品列表中,多个产品共享同一卖家)我建议您经常查看firebug日志,以检查Json响应,并查看代码中的情况
来源: