当尝试将具有双向关联的JPA对象转换为JSON时,我不断得到
org.codehaus.jackson.map.JsonMappingException: Infinite recursion (StackOverflowError)
我所发现的就是这条线索,它的基本结论是建议避免双向关联。有没有人有办法解决这个spring bug?
------编辑2010-07-24 16:26:22-------
代码片段:
业务对象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();
}
}
坚持不懈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解决了其他选项的许多问题。
@Entity
public class Material{
...
@JsonIgnoreProperties("costMaterials")
private List<Supplier> costSuppliers = new ArrayList<>();
...
}
@Entity
public class Supplier{
...
@JsonIgnoreProperties("costSuppliers")
private List<Material> costMaterials = new ArrayList<>();
....
}
看看这里。它的工作原理就像在留档:
http://springquay.blogspot.com/2016/01/new-approach-to-solve-json-recursive.html
您可以使用@JsonIgnore
来打破循环(参考)。
您需要导入org.codehaus.jackson.annotate.JsonIgnore
(旧版)或com.fasterxml.jackson.annotation.JsonIgnore
(当前版本)。
您现在可以使用JsonIgnoreProperties来抑制属性的序列化(在序列化期间),或者忽略对JSON属性读取的处理(在反序列化期间)。如果这不是您要找的,请继续阅读下面的内容。
(感谢As Zammel AlaaEddine指出这一点)。
从Jackson 1.6开始,您可以使用两个注释来解决无限递归问题,而不会在序列化过程中忽略getter/setter:@JsonManaged参考
和@JsonBack参考
。
解释
为了让Jackson正常工作,不应该序列化关系的两个方面之一,以避免导致stackoverflow错误的infite循环。
因此,Jackson将引用的前半部分(你的集合)
您可以这样更改代码(我跳过无用的部分):
业务对象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;
现在这一切都应该正常工作了。
如果你想要更多的信息,我写了一篇关于Json和Jackson Stackoverflow问题的文章在我的博客Keenformtics上。
编辑:
您可以检查的另一个有用注释是@JsonIdtyInfo:使用它,每次Jackson序列化您的对象时,它都会向其添加一个ID(或您选择的另一个属性),这样它就不会每次都完全“扫描”它。当您在更多相互关联的对象之间有一个链式循环时,这可能会很有用(例如:订单-
在这种情况下,您必须小心,因为您可能需要多次读取对象的属性(例如,在一个产品列表中,有多个产品共享同一卖家),而此注释阻止您这样做。我建议经常查看firebug日志,检查Json响应,看看代码中发生了什么。
资料来源:
Keenformtics-如何解决JSON无限递归Stackoverflow(我的博客)
- 杰克逊参考
- 个人经历
问题内容: 当尝试将具有双向关联的JPA对象转换为JSON时,我不断 我所发现的只是该线程,基本上以建议避免双向关联为结尾。有谁知道这个春季错误的解决方法? ------编辑2010-07-24 16:26:22 ------- 代码段: 业务对象1: 业务对象2: 控制器: JPA实施学员DAO: persistence.xml 问题答案: 您可以使用它来打破循环。
问题内容: 尝试将具有双向关联的JPA对象转换为JSON时,我不断 我所发现的只是该线程,基本上以建议避免双向关联为结尾。有谁知道这个Spring错误的解决方法? 代码段: 业务对象1: 业务对象2: 控制器: JPA实施学员DAO: persistence.xml 问题答案: 你现在可以使用JsonIgnoreProperties到属性(序列化过程中)的抑制序列,或忽略JSON性能的处理读取(反
我来自Grails背景,最近在Micronaut使用GORM启动了一个项目。 我有以下代码: 应用程序编译和启动没有问题,但当我尝试访问url http:localhost:8080/author时,我收到以下错误: 10:25:29.431[nioEventLoopGroup-1-2]错误i.m.h.s.netty。RoutingInBoundHandler-发生意外错误:将对象[[micron
我现在正在做一个关于Collatz序列的问题。我必须找到最长的Collatz序列,如果我们从范围1开始,。。。,数字n的Collatz序列定义为:如果n mod 2==0,则下一个数字为n/2。如果n mod 2!=0那么下一个数字是3*n 1。n=10的顺序为10,5,16,8,4,2,1。 当然,如果我们用简单的方法来解决这个问题,我们会计算1,…,之间每个数字n的Collatz序列,。。。,
我用的是Spring Roo 1.2.1和Jackson 1.9.7。在使用json序列化我的类时,我得到了一个JsonMappingException。 我读了以下帖子,但没有找到适合我的工作解决方案: Jackson的无限递归 Jackson-具有双方向关系的实体序列化(避免循环) 我不知道为什么JsonIgnore在属性QueueOuts的类Queue中不起作用。我也尝试了JsonManag
我使用Google Endpoint创建了一个应用服务器,它是一个即时消息应用程序的后端。每个用户都有一个好友列表。 当我创建一个新朋友时,我使用下面的方法将用户添加到彼此的朋友列表中。然而,由于循环依赖关系,当我添加朋友时,它给了我以下错误。 我看了贴出的其他问题和解决方案。他们中的大多数人结构不同,他们没有解决我的问题。 这个网站的一个答案是建议添加,但我没有任何字段可以添加。我试图放置,但我