Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/348.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Jackson JSON和Hibernate JPA问题的无限递归_Java_Json_Orm_Spring Mvc_Jackson - Fatal编程技术网

Java Jackson JSON和Hibernate JPA问题的无限递归

Java Jackson JSON和Hibernate JPA问题的无限递归,java,json,orm,spring-mvc,jackson,Java,Json,Orm,Spring Mvc,Jackson,当尝试将具有双向关联的JPA对象转换为JSON时,我不断得到 org.codehaus.jackson.map.JsonMappingException: Infinite recursion (StackOverflowError) 我所发现的一切基本上都是建议避免双向关联。有没有人有办法解决这个spring bug ------编辑2010-07-2416:26:22------- 代码片段: 业务对象1: @实体 @表(name=“ta_培训生”,uniqueConstraints={@

当尝试将具有双向关联的JPA对象转换为JSON时,我不断得到

org.codehaus.jackson.map.JsonMappingException: Infinite recursion (StackOverflowError)
我所发现的一切基本上都是建议避免双向关联。有没有人有办法解决这个spring bug

------编辑2010-07-2416:26:22-------

代码片段:

业务对象1:

@实体
@表(name=“ta_培训生”,uniqueConstraints={@UniqueConstraint(columnNames={“id”})})
公共类培训生扩展BusinessObject{
@身份证
@GeneratedValue(策略=GenerationType.TABLE)
@列(name=“id”,nullable=false)
私有整数id;
@列(name=“name”,nullable=true)
私有字符串名称;
@列(name=“姓氏”,nullable=true)
私家姓;
@OneToMany(mappedBy=“培训生”,fetch=FetchType.EAGER,cascade=CascadeType.ALL)
@列(nullable=true)
私人设置bodyStats;
@OneToMany(mappedBy=“培训生”,fetch=FetchType.EAGER,cascade=CascadeType.ALL)
@列(nullable=true)
私人培训;
@OneToMany(mappedBy=“培训生”,fetch=FetchType.EAGER,cascade=CascadeType.ALL)
@列(nullable=true)
私有集练习类型;
公共培训生(){
超级();
}
//…接受者/接受者。。。
}
业务对象2:

import javax.persistence.*;
导入java.util.Date;
@实体
@表(name=“ta_bodystat”,uniqueConstraints={@UniqueConstraint(columnNames={“id”})})
公共类BodyStat扩展了BusinessObject{
@身份证
@GeneratedValue(策略=GenerationType.TABLE)
@列(name=“id”,nullable=false)
私有整数id;
@列(name=“height”,nullable=true)
私人浮动高度;
@列(name=“measuretime”,null=false)
@时态(TemporalType.TIMESTAMP)
私人日期测量时间;
@manytone(fetch=FetchType.EAGER,cascade=CascadeType.ALL)
@JoinColumn(name=“培训生”
私人见习生;
}
控制器:

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;
@控制器
@RequestMapping(value=“/培训生”)
公营实习控制员{
最终记录器=LoggerFactory.getLogger(实习控制器类);
私有映射受训者=新的ConcurrentHashMap();
@自动连线
私营工矿局培训生局;
/**
*返回所有学员的json代表
*/
@RequestMapping(value=“/GetAllInspects”,method=RequestMethod.GET)
@应答器
公共集合GetAllInter培训生(){
Collection all培训生=this.traineeDAO.getAll();
this.logger.debug(“从db中读取的“+allpedi培训生.size()+”培训生总数”);
归还所有学员;
}    
}
JPA学员DAO的实施:

@存储库
@交易的
公共类TraineDao实施iTraineDao{
@持久上下文
私人实体管理者;
@交易的
公共实习生储蓄(实习生){
em.persist(培训生);
返回学员;
}
@事务(只读=真)
公共集合getAll(){
return(Collection)em.createQuery(“从学员t中选择t”).getResultList();
}
}
persistence.xml


假的

您可以使用
@JsonIgnore
来打破循环()


您需要导入
org.codehaus.jackson.annotate.JsonIgnore
(旧版本)或
com.fasterxml.jackson.annotation.JsonIgnore
(当前版本)。

此外,jackson 1.6还支持。。。好像 您正在寻找的内容(还提到了该功能)


截至2011年7月,还有一个“”可能在处理Hibernate对象的某些方面有所帮助,尽管不一定是这个特定的对象(它需要注释)。

现在Jackson支持在不忽略字段的情况下避免循环:

JsonIgnoreProperties[2017年更新]: 现在可以使用来抑制属性的序列化(在序列化期间),或忽略JSON属性读取的处理(在反序列化期间)。如果这不是你想要的,请继续阅读下面的内容

(感谢As Zammel AlaaEddine指出这一点)


JsonManagedReference和JsonBackReference 由于Jackson 1.6,您可以使用两个注释来解决无限递归问题,而不必在序列化过程中忽略getter/setter:和

解释

为了使Jackson能够很好地工作,不应该序列化关系的两个方面之一,以避免导致stackoverflow错误的infite循环

因此,Jackson获取引用的前向部分(您的
在培训生类中设置bodyStats
),并将其转换为类似json的存储格式;这就是所谓的编组过程。然后,Jackson查找引用的后面部分(即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;
@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;
现在一切都应该结束了
@Entity
@Table(name = "ta_trainee", uniqueConstraints = {@UniqueConstraint(columnNames = {"id"})})
@JsonIdentityInfo(generator=ObjectIdGenerators.IntSequenceGenerator.class, property="@traineeId")
public class Trainee extends BusinessObject {

@Entity
@Table(name = "ta_bodystat", uniqueConstraints = {@UniqueConstraint(columnNames = {"id"})})
@JsonIdentityInfo(generator=ObjectIdGenerators.IntSequenceGenerator.class, property="@bodyStatId")
public class BodyStat extends BusinessObject {
@OneToMany(mappedBy = "county")
private List<Town> towns;
@OneToMany
private List<Town> towns;
@ManyToOne
@JoinColumn(name = "county_id")
private County county;
<dependency>
  <groupId>com.fasterxml.jackson.datatype</groupId>
  <artifactId>jackson-datatype-hibernate4</artifactId>
  <version>2.4.0</version>
</dependency>
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new Hibernate4Module());
@ManyToOne
@JoinColumn(name = "ID", nullable = false, updatable = false)
@JsonIgnore
private Member member;
public class A{
   private int id;
   private String code;
   private String name;
   private List<B> bs;
}

public class B{
   private int id;
   private String code;
   private String name;
   private A a;
}
"select new A(id, code, name) from A"
public class A{
   private int id;
   private String code;
   private String name;
   private List<B> bs;

   public A(){
   }

   public A(int id, String code, String name){
      this.id = id;
      this.code = code;
      this.name = name;
   }

}
public A getAById(int id); //THE A id

public List<B> getBsByAId(int idA); //the A id.
@Entity

public class Material{
   ...    
   @JsonIgnoreProperties("costMaterials")
   private List<Supplier> costSuppliers = new ArrayList<>();
   ...
}

@Entity
public class Supplier{
   ...
   @JsonIgnoreProperties("costSuppliers")
   private List<Material> costMaterials = new ArrayList<>();
   ....
}
public class Company {

    private Employee employee;

    public Company(Employee employee) {
        this.employee = employee;
    }

    public Employee getEmployee() {
        return employee;
    }
}

public class Employee {

    private Company company;

    public Company getCompany() {
        return company;
    }

    public void setCompany(Company company) {
        this.company = company;
    }
}
@SpringBootTest
@RunWith(SpringRunner.class)
@Transactional
public class CompanyTest {

    @Autowired
    public ObjectMapper mapper;

    @Test
    public void shouldSaveCompany() throws JsonProcessingException {
        Employee employee = new Employee();
        Company company = new Company(employee);
        employee.setCompany(company);

        String jsonCompany = mapper.writeValueAsString(company);
        System.out.println(jsonCompany);
        assertTrue(true);
    }
}
org.codehaus.jackson.map.JsonMappingException: Infinite recursion (StackOverflowError)
public class Filter {

    public static interface EmployeeData {};

    public static interface CompanyData extends EmployeeData {};

} 
public class Company {

    @JsonView(Filter.CompanyData.class)
    private Employee employee;

    public Company(Employee employee) {
        this.employee = employee;
    }

    public Employee getEmployee() {
        return employee;
    }
}
@SpringBootTest
@RunWith(SpringRunner.class)
@Transactional
public class CompanyTest {

    @Autowired
    public ObjectMapper mapper;

    @Test
    public void shouldSaveCompany() throws JsonProcessingException {
        Employee employee = new Employee();
        Company company = new Company(employee);
        employee.setCompany(company);

        ObjectWriter writter = mapper.writerWithView(Filter.CompanyData.class);
        String jsonCompany = writter.writeValueAsString(company);

        System.out.println(jsonCompany);
        assertTrue(true);
    }
}
import static org.junit.Assert.assertTrue;

import javax.transaction.Transactional;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;

import com.fasterxml.jackson.annotation.JsonView;
@Entity
@Table(name = "ta_trainee", uniqueConstraints = {@UniqueConstraint(columnNames = {"id"})})
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public class Trainee extends BusinessObject {
...
@ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@JoinColumn(name="trainee_fk")
private Trainee trainee;
@OneToMany(mappedBy = "trainee", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@Column(nullable = true)
private Set<BodyStat> bodyStats;
@OneToMany(mappedBy = "course",fetch=FetchType.EAGER)
@JsonIgnoreProperties("course")
private Set<Student> students;
@ManyToOne
@JoinColumn(name="Key")
@JsonBackReference
private LgcyIsp Key;


@OneToMany(mappedBy="LgcyIsp ")
@JsonManagedReference
private List<Safety> safety;
    @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
    private Trainee trainee;
@OneToMany(
            mappedBy = "queue_group",fetch = FetchType.LAZY,
            cascade = CascadeType.ALL
        )
    @JsonManagedReference
    private Set<Queue> queues;



@ManyToOne(cascade=CascadeType.ALL)
        @JoinColumn(name = "qid")
       // @JsonIgnore
        @JsonBackReference
        private Queue_group queue_group;
@Access(AccessType.PROPERTY)
@OneToMany(fetch = FetchType.LAZY)
@JoinColumn(name="townshipId", nullable=false ,insertable=false, updatable=false)
public List<Village> getVillages() {
    return villages;
}

@JsonIgnore
@Access(AccessType.PROPERTY)
public void setVillages(List<Village> villages) {
    this.villages = villages;
}
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "townshipId", insertable=false, updatable=false)
Township township;

@Column(name = "townshipId", nullable=false)
Long townshipId;
//before
@OneToMany(mappedBy="client")
private Set<address> addressess;

//after
@OneToMany(mappedBy="client")
private List<address> addressess;
@ManyToOne
@JoinColumn(name="client_id", nullable = false)
@JsonIgnore
@ToString.Exclude
private Client client;
@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)
@JsonBackReference
private Set<BodyStat> bodyStats;
@EqualsAndHashCode(exclude = {"attributeOfTypeList", "attributeOfTypeSet"})
@JsonIdentityInfo(generator= ObjectIdGenerators.UUIDGenerator.class, property="@id")