当尝试将具有双向关联的JPA对象转换为JSON时,我不断得到
org.codehaus.jackson.map.JsonMappingException: Infinite recursion (StackOverflowError)
我所发现的是this thread,其基本结论是建议避免双向关联。有人有解决这个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;
}
}
学员DAO的JPA实施:
@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>
28条答案
按热度按时间6yjfywim16#
我也遇到了同样的问题。我使用
@JsonIdentityInfo
的ObjectIdGenerators.PropertyGenerator.class
发电机类型。这是我的解决方案:
lvmkulzt17#
在我的情况下,将关系从:
致:
另一个关系保持原样:
czfnxgou18#
您应该将@JsonBackReference与@ManyTone实体一起使用,@JsonManagedReference与包含实体类的@onetomany一起使用。
w8f9ii6919#
***@JSONIGNOREPORTIES***是答案。
使用类似这样的东西::
fdx2calv20#
现在有一个Jackson模块(用于Jackson 2),专门用于处理序列化时的Hibernate延迟初始化问题。
https://github.com/FasterXML/jackson-datatype-hibernate
只需添加依赖项(注意Hibernate 3和Hibernate4有不同的依赖项):
然后在初始化Jackson的ObjectMapper时注册模块:
目前的文档不是很好。有关可用选项,请参阅Hibernate4Module代码。
h9vpoimq21#
对我来说,最好的解决方案是使用
@JsonView
并为每个场景创建特定的过滤器。您也可以使用@JsonManagedReference
和@JsonBackReference
,但这是一种硬编码解决方案,仅适用于一种情况,即所有者始终引用拥有方,而不是相反。如果您有另一个序列化场景,需要以不同的方式重新注解属性,则您将无法这样做。问题
让我们使用两个类
Company
和Employee
,它们之间有循环依赖关系:以及尝试使用
ObjectMapper
(Spring Boot)序列化的测试类:如果运行此代码,将得到:
使用“@JsonView”的解决方案`
@JsonView
允许您在序列化对象时使用过滤器并选择应包括哪些字段。过滤器只是用作标识符的类引用。因此,让我们首先创建过滤器:请记住,过滤器是虚拟类,仅用于指定带有
@JsonView
注解的字段,因此您可以根据需要创建任意数量的过滤器。让我们看看它的实际情况,但首先我们需要注解Company
类:并更改测试,以便序列化程序使用视图:
现在,如果您运行这段代码,无限递归问题就解决了,因为您明确表示只想序列化用
@JsonView(Filter.CompanyData.class)
注解的属性。当它到达
Employee
中公司的反向引用时,它会检查是否未对其进行注解,并忽略序列化。您还有一个强大而灵活的解决方案来选择要通过RESTAPI发送的数据。使用Spring,您可以使用所需的
@JsonView
过滤器注解REST控制器方法,并将序列化透明地应用于返回对象。以下是您需要检查时使用的导入:
nom7f22z22#
对我来说工作正常Resolve Json Infinite Recursion problem when working with Jackson
这就是我在一对一和多对一Map中所做的
x0fgdtte23#
这对我来说非常好。在子类中添加注解@JsonIgnore,其中提到了对父类的引用。
tez616oj24#
现在Jackson支持在不忽略字段的情况下避免循环:
Jackson - serialization of entities with birectional relationships (avoiding cycles)
sg24os4d25#
此外,Jackson 1.6支持handling bi-directional references…这似乎是您正在寻找的功能(this blog entry也提到了该功能)
截至2011年7月,还有“jackson-module-hibernate”,它可能在处理Hibernate对象的某些方面有所帮助,但不一定是这个特定的对象(需要注解)。
cgyqldqp26#
此外,使用Jackson 2.0+可以使用
@JsonIdentityInfo
。对于我的hibernate类来说,这比@JsonBackReference
和@JsonManagedReference
工作得好得多,这对我来说有问题,并且没有解决问题。只需添加以下内容:它应该会起作用。
2sbarzqh27#
新注解@jsonignoreperties解决了其他选项的许多问题。
看看这里。它的工作原理与文档中的一样:
http://springquay.blogspot.com/2016/01/new-approach-to-solve-json-recursive.html
mrzz3bfm28#
您可以使用
@JsonIgnore
打破循环(参考)。您需要导入
org.codehaus.jackson.annotate.JsonIgnore
(旧版本)或com.fasterxml.jackson.annotation.JsonIgnore
(当前版本)。