Ta Sas Ta Sas - 8 months ago 186
Java Question

Infinite Recursion with Jackson JSON and Hibernate JPA issue

When trying to convert a JPA object that has a bi-directional association into JSON, I keep getting

org.codehaus.jackson.map.JsonMappingException: Infinite recursion (StackOverflowError)

All I found is this thread which basically concludes with recommending to avoid bi-directional associations. Does anyone have an idea for a workaround for this spring bug?

------ EDIT 2010-07-24 16:26:22 -------


Business Object 1:

@Table(name = "ta_trainee", uniqueConstraints = {@UniqueConstraint(columnNames = {"id"})})
public class Trainee extends BusinessObject {

@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() {

... getters/setters ...

Business Object 2:

import javax.persistence.*;
import java.util.Date;

@Table(name = "ta_bodystat", uniqueConstraints = {@UniqueConstraint(columnNames = {"id"})})
public class BodyStat extends BusinessObject {

@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)
private Date measureTime;

@ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
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;

@RequestMapping(value = "/trainees")
public class TraineesController {

final Logger logger = LoggerFactory.getLogger(TraineesController.class);

private Map<Long, Trainee> trainees = new ConcurrentHashMap<Long, Trainee>();

private ITraineeDAO traineeDAO;

* Return json repres. of all trainees
@RequestMapping(value = "/getAllTrainees", method = RequestMethod.GET)
public Collection getAllTrainees() {
Collection allTrainees = this.traineeDAO.getAll();

this.logger.debug("A total of " + allTrainees.size() + " trainees was read from db");

return allTrainees;

JPA-implementation of the trainee DAO:

public class TraineeDAO implements ITraineeDAO {

private EntityManager em;

public Trainee save(Trainee trainee) {
return trainee;

@Transactional(readOnly = true)
public Collection getAll() {
return (Collection) em.createQuery("SELECT t FROM Trainee t").getResultList();


<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
<persistence-unit name="RDBMS" transaction-type="RESOURCE_LOCAL">
<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"/> -->


You may use @JsonIgnore to break the cycle.