尝试将具有双向关联的JPA对象转换为JSON时,我不断
org.codehaus.jackson.map.JsonMappingException: Infinite recursion (StackOverflowError)
我所发现的只是该线程,基本上以建议避免双向关联为结尾。有谁知道这个Spring错误的解决方法?
代码段:
业务对象1:
@Entity
@Table(name = "ta_trainee", uniqueConstraints = {@UniqueConstraint(columnNames = {"id"})})
public class Trainee extends BusinessObject {
@Id
@GeneratedValue(strategy = GenerationType.TABLE)
@Column(name = "id", nullable = false)
private Integer id;
@Column(name = "name", nullable = true)
private String name;
@Column(name = "surname", nullable = true)
private String surname;
@OneToMany(mappedBy = "trainee", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@Column(nullable = true)
private Set<BodyStat> bodyStats;
@OneToMany(mappedBy = "trainee", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@Column(nullable = true)
private Set<Training> trainings;
@OneToMany(mappedBy = "trainee", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@Column(nullable = true)
private Set<ExerciseType> exerciseTypes;
public Trainee() {
super();
}
... getters/setters ...
业务对象2:
import javax.persistence.*;
import java.util.Date;
@Entity
@Table(name = "ta_bodystat", uniqueConstraints = {@UniqueConstraint(columnNames = {"id"})})
public class BodyStat extends BusinessObject {
@Id
@GeneratedValue(strategy = GenerationType.TABLE)
@Column(name = "id", nullable = false)
private Integer id;
@Column(name = "height", nullable = true)
private Float height;
@Column(name = "measuretime", nullable = false)
@Temporal(TemporalType.TIMESTAMP)
private Date measureTime;
@ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@JoinColumn(name="trainee_fk")
private Trainee trainee;
控制器:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletResponse;
import javax.validation.ConstraintViolation;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
@Controller
@RequestMapping(value = "/trainees")
public class TraineesController {
final Logger logger = LoggerFactory.getLogger(TraineesController.class);
private Map<Long, Trainee> trainees = new ConcurrentHashMap<Long, Trainee>();
@Autowired
private ITraineeDAO traineeDAO;
/**
* Return json repres. of all trainees
*/
@RequestMapping(value = "/getAllTrainees", method = RequestMethod.GET)
@ResponseBody
public Collection getAllTrainees() {
Collection allTrainees = this.traineeDAO.getAll();
this.logger.debug("A total of " + allTrainees.size() + " trainees was read from db");
return allTrainees;
}
}
JPA实施学员DAO:
@Repository
@Transactional
public class TraineeDAO implements ITraineeDAO {
@PersistenceContext
private EntityManager em;
@Transactional
public Trainee save(Trainee trainee) {
em.persist(trainee);
return trainee;
}
@Transactional(readOnly = true)
public Collection getAll() {
return (Collection) em.createQuery("SELECT t FROM Trainee t").getResultList();
}
}
persistence.xml
<persistence 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"
version="1.0">
<persistence-unit name="RDBMS" transaction-type="RESOURCE_LOCAL">
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="hibernate.hbm2ddl.auto" value="validate"/>
<property name="hibernate.archive.autodetection" value="class"/>
<property name="dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect"/>
<!-- <property name="dialect" value="org.hibernate.dialect.HSQLDialect"/> -->
</properties>
</persistence-unit>
</persistence>
你现在可以使用JsonIgnoreProperties到属性(序列化过程中)的抑制序列,或忽略JSON性能的处理读取(反序列化过程)。如果这不是你想要的,请继续阅读以下内容。
(感谢As Zammel AlaaEddine指出了这一点)。
JsonManagedReference和JsonBackReference
从Jackson 1.6开始,你可以使用两个注释来解决无限递归问题,而不必在序列化过程中忽略getter / setter方法:@JsonManagedReference
和@JsonBackReference
。
说明
为了使Jackson正常工作,不应将关系的两个方面之一进行序列化,以避免引起你stackoverflow错误的infite循环。
因此,Jackson接受了引用的前一部分(你Set<BodyStat> bodyStats
在Trainee类中),并将其转换为类似json的存储格式;这就是所谓的编组过程。然后,Jackson查找引用的Trainee trainee
后半部分(即,在BodyStat类中),并将其保留不变,而不对其进行序列化。关系的这一部分将在前向引用的反序列化(反编组)期间重新构建。
你可以这样更改代码(我跳过了无用的部分):
业务对象1:
@Entity
@Table(name = "ta_trainee", uniqueConstraints = {@UniqueConstraint(columnNames = {"id"})})
public class Trainee extends BusinessObject {
@OneToMany(mappedBy = "trainee", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@Column(nullable = true)
@JsonManagedReference
private Set<BodyStat> bodyStats;
业务对象2:
@Entity
@Table(name = "ta_bodystat", uniqueConstraints = {@UniqueConstraint(columnNames = {"id"})})
public class BodyStat extends BusinessObject {
@ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@JoinColumn(name="trainee_fk")
@JsonBackReference
private Trainee trainee;
现在一切都应该正常工作。
如果你需要更多信息,我在我的博客Keenformatics上写了一篇有关Json和Jackson Stackoverflow问题的文章。
编辑:
你可以检查的另一个有用的注释是@JsonIdentityInfo:使用它,每次Jackson序列化你的对象时,它将为它添加一个ID(或你选择的另一个属性),这样就不会每次都完全“扫描”它。当你在更多相互关联的对象之间形成链循环时(例如:Order-> OrderLine-> User-> Order and over over),这很有用。
在这种情况下,你必须要小心,因为你可能需要多次读取对象的属性(例如,在一个产品列表中有多个共享同一卖方的产品),并且此注释会阻止你这样做。我建议始终查看Firebug日志,以检查Json响应,并查看代码中发生了什么。
问题内容: 当尝试将具有双向关联的JPA对象转换为JSON时,我不断 我所发现的只是该线程,基本上以建议避免双向关联为结尾。有谁知道这个春季错误的解决方法? ------编辑2010-07-24 16:26:22 ------- 代码段: 业务对象1: 业务对象2: 控制器: JPA实施学员DAO: persistence.xml 问题答案: 您可以使用它来打破循环。
当尝试将具有双向关联的JPA对象转换为JSON时,我不断得到 我所发现的就是这条线索,它的基本结论是建议避免双向关联。有没有人有办法解决这个spring bug? ------编辑2010-07-24 16:26:22------- 代码片段: 业务对象1: 业务对象2: 控制器: JPA-见习DAO的实施: 坚持不懈xml
产品类别: 提供程序类: Prices_1类:
我正在用Java构建一个数独求解器,我正在使用回溯算法。有一个堆栈溢出错误,我怀疑在我的代码中有无限递归。我知道我提供的信息很少,但我太难了,不知道该怎么做。 网格是一个9乘9的数组,表示每个数独平方,它保存一个名为“value”的自定义类型,该类型简单地包含一个整数和一个布尔值,“IsOriginal”指示该值是给定的还是可更改的。 “moveon”是一个全局变量,它的值在“checkall”中
我来自Grails背景,最近在Micronaut使用GORM启动了一个项目。 我有以下代码: 应用程序编译和启动没有问题,但当我尝试访问url http:localhost:8080/author时,我收到以下错误: 10:25:29.431[nioEventLoopGroup-1-2]错误i.m.h.s.netty。RoutingInBoundHandler-发生意外错误:将对象[[micron
在尝试执行GET到发布者存储库时,我正在执行GET和无限循环。 出版商: 书: 完整代码可在此处获得: https://github.com/vanyasav/library