Jackson JSON 및 Hibernate JPA 문제로 무한 재귀


412

양방향 연관이있는 JPA 객체를 JSON으로 변환하려고 할 때 계속

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

모든 I의 FOUND는 이 스레드 기본적으로 양방향 연결을 방지하기 위해 추천으로 결론. 이 봄 버그에 대한 해결 방법에 대한 아이디어가 있습니까?

------ 편집 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>

추가 @TransientTrainee.bodyStats.
phil294

2017 년 현재 @JsonIgnoreProperties가장 깨끗한 솔루션입니다. 확인 Zammel AlaaEddine의 답변을 자세한 내용은.
Utku

이 봄의 잘못은 어떻습니까?
Nathan Hughes 1

답변:


293

@JsonIgnore사이클을 중단하는 데 사용할 수 있습니다 .


1
@Ben : 사실은 모르겠습니다. 아마도 그 지원이 활성화되지 않은 : wiki.fasterxml.com/JacksonJAXBAnnotations
axtavt

40
Jackson 1.6부터는 더 나은 솔루션이 있습니다. 직렬화 중에 게터 / 세터를 무시하지 않고 두 가지 새로운 주석을 사용하여 무한 재귀 문제를 해결할 수 있습니다. 자세한 내용은 아래 답변을 참조하십시오.
커트 부르 바키

1
@axtavt 완벽한 답변 감사합니다. Btw, 나는 또 다른 해결책을 찾았습니다.이 값을 얻기 위해 getter를 만드는 것을 피할 수 있으므로 Spring은 JSON을 만드는 동안 액세스 할 수 없습니다 (그러나 모든 경우에 적합하다고 생각하지 않으므로 답변이 더 좋습니다)
Semyon Danilov 2014

11
위의 모든 솔루션은 주석을 추가하여 도메인 객체를 변경해야합니다. 타사 클래스를 직렬화하면 수정할 수 없습니다. 이 문제를 어떻게 피할 수 있습니까?
Jianwu Chen

2
이 솔루션은 일부 상황에서는 작동하지 않습니다. jpa와의 관계형 데이터베이스 @JsonIgnore에서 엔터티를 업데이트 할 때 "외래 키"에 null이 있으면 ...
slim

629

JsonIgnoreProperties [2017 업데이트] :

이제 JsonIgnoreProperties 를 사용 하여 특성 직렬화억제하거나 (직렬화 중) JSON 특성 읽기 처리 (직렬화 해제 중)를 무시할 수 있습니다. 원하는 것이 아닌 경우 아래를 계속 읽으십시오.

(이 점을 지적한 As Zammel AlaaEddine에게 감사합니다).


JsonManagedReference 및 JsonBackReference

잭슨 1.6 이후 당신은 직렬화하는 동안 게터 / 세터를 무시하지 않고 무한 재귀 문제를 해결하기 위해 두 개의 주석을 사용할 수 있습니다 @JsonManagedReference@JsonBackReference.

설명

Jackson이 제대로 작동하려면 스택 오버플로 오류를 일으키는 인피 트 루프를 피하기 위해 관계의 양면 중 하나를 직렬화하면 안됩니다.

따라서 Jackson은 참조의 앞 부분 ( Set<BodyStat> bodyStatsTrainee 클래스)을 가져 와서 json과 같은 저장 형식으로 변환합니다. 이것이 소위 마샬링 프로세스입니다. 그런 다음 Jackson은 참조의 뒷면 부분 (예 : Trainee traineeBodyStat 클래스)을 찾아 직렬화하지 않고 그대로 둡니다. 관계의이 부분은 순방향 참조 의 역 직렬화 ( 비 정렬 화 ) 중에 재구성됩니다 .

다음과 같이 코드를 변경할 수 있습니다 (쓸모없는 부분은 건너 뜁니다).

사업 목표 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 and Jackson Stackoverflow 문제에 대한 기사를 썼습니다 .

편집하다:

확인할 수있는 또 다른 유용한 주석은 @JsonIdentityInfo입니다 . Jackson을 사용하여 객체를 직렬화 할 때마다 ID (또는 선택한 다른 속성)가 추가되어 매번 다시 완전히 "스캔"되지 않습니다. 이것은 더 많은 상호 관련 된 객체 (예 : 주문-> 주문 라인-> 사용자-> 주문 이상) 사이에 체인 루프가있는 경우 유용 할 수 있습니다.

이 경우 객체 속성을 두 번 이상 읽어야하므로 (예 : 동일한 판매자를 공유하는 제품이 더 많은 제품 목록에서)이 주석을 사용하면 그렇게 할 수 없으므로주의해야합니다. Json 응답을 확인하고 코드에서 무슨 일이 일어나고 있는지 확인하려면 항상 Firebug 로그를 살펴 보는 것이 좋습니다.

출처 :


29
명확한 답변을 주셔서 감사합니다. 이것은 @JsonIgnore참조를 다시 하는 것보다 편리한 솔루션 입니다.
Utku Özdemir

3
이것이 올바른 방법입니다. Jackson을 사용하기 때문에 서버 측에서 이와 같이하면 클라이언트 측에서 사용하는 json mapper는 중요하지 않으며 자식을 부모 링크 매뉴얼로 설정할 필요가 없습니다. 그냥 작동합니다. 감사합니다 Kurt
flosk8

1
훌륭하고 자세한 설명과 확실히 더 나은 설명 접근 방식보다 @JsonIgnore.
Piotr Nowicki

2
감사! @JsonIdentityInfo는 많은 중첩 루프에서 여러 엔티티를 포함하는 주기적 참조에 효과적이었습니다.
n00b

1
나는 이것을 내 인생에서 일하게 할 수 없다. 나는 꽤 비슷한 설정을 가지고 있다고 생각하지만, 무한 재발 오류 외에는 아무것도 얻을 수 없기 때문에 분명히 뭔가 잘못되었습니다.
swv

103

새로운 주석 @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


@tero-이 방법으로 엔티티와 관련된 데이터를 얻지 못합니다.
Pra_A

@PAA HEY PAA 나는 그것이 엔티티와 관련이 있다고 생각합니다! 왜 그렇게 말합니까?
tero17

1
@ tero17 클래스가 두 개 이상인 경우 무한 재귀를 어떻게 관리합니까? 예를 들면 : 클래스 A -> B 급 -> 클래스 C는 -> 클래스 A. 나는 운없이 JsonIgnoreProperties으로 시도
Villat

@Villat 이것은 해결해야 할 또 다른 문제입니다. 새로운 요구를 열 것을 제안합니다.
tero17

코드 샘플의 경우 +1, Jackson 초보자에게는 @JsonIgnoreProperties의 사용이 JavaDoc
Wecherowski

47

또한 Jackson 2.0 이상을 사용하면을 사용할 수 있습니다 @JsonIdentityInfo. 이것은 @JsonBackReference및 보다 내 최대 절전 모드 클래스에서 훨씬 잘 작동 @JsonManagedReference하여 문제가 있었고 문제를 해결하지 못했습니다. 다음과 같은 것을 추가하십시오.

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

작동해야합니다.


"이것이 훨씬 나아졌다"고 설명해 주시겠습니까? 관리 참조에 문제가 있습니까?
Utku Özdemir

@ UtkuÖzdemir @JsonIdentityInfo위의 답변 에 대한 자세한 내용 을 추가했습니다 .
커트 부르 바키

1
이것은 "@JsonManagedReference"를 사용할 때 get 메소드가 stackoverflow 오류없이 값을 성공적으로 리턴했기 때문에 지금까지 찾은 최상의 솔루션입니다. 우리가 포스트를 사용하여 데이터를 저장하려고하지만, 그것은 415 (지원되지 않는 미디어 오류)의 오류 반환
cuser

1
@JsonIdentityInfo엔티티 에 주석을 추가 했지만 재귀 문제를 해결하지 못합니다. 만 @JsonBackReference하고 @JsonManagedReference해결할 수있는 문제,하지만 그들은 JSON에서 제거 매핑 속성입니다.
Oleg Abrazhaev

19

또한 Jackson 1.6은 양방향 참조 처리 를 지원합니다 ... 원하는 것 같습니다 ( 이 블로그 항목 에도 기능이 언급되어 있습니다)

그리고 2011 년 7 월 현재, " jackson-module-hibernate "도 있는데,이 특성은 반드시 주석이 필요한 특정 오브젝트는 아니지만 Hibernate 오브젝트 처리의 일부 측면에서 도움이 될 수 있습니다.


링크가 작동하지 않습니다. 링크를 업데이트하거나 답변을 편집 하시겠습니까?
GetMeARemoteJob


9

이것은 나를 위해 완벽하게 작동했습니다. 부모 클래스에 대한 참조를 언급하는 자식 클래스에 주석 @JsonIgnore를 추가하십시오.

@ManyToOne
@JoinColumn(name = "ID", nullable = false, updatable = false)
@JsonIgnore
private Member member;

2
@JsonIgnore이 속성이 클라이언트 측으로 검색되는 것을 무시 한다고 생각 합니다. 자녀와 함께이 속성이 필요한 경우 (자녀가있는 경우) 어떻게합니까?
Khasan 24-7

6

직렬화 할 때 Hibernate 지연 초기화 문제를 처리하도록 특별히 설계된 Jackson 모듈 (Jackson 2 용)이 있습니다.

https://github.com/FasterXML/jackson-datatype-hibernate

종속성을 추가하십시오 (Hibernate 3 및 Hibernate 4에 대해 다른 종속성이 있음에 유의하십시오).

<dependency>
  <groupId>com.fasterxml.jackson.datatype</groupId>
  <artifactId>jackson-datatype-hibernate4</artifactId>
  <version>2.4.0</version>
</dependency>

Jackson의 ObjectMapper를 초기화 할 때 모듈을 등록하십시오.

ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new Hibernate4Module());

현재 문서가 좋지 않습니다. 사용 가능한 옵션에 대해서는 Hibernate4Module 코드 를 참조하십시오 .


문제는 흥미로운 것처럼 보이기 때문에 해결하는 것입니다. OP와 동일한 문제가 있으며 위의 모든 트릭이 작동하지 않았습니다.
user1567291

6

나를 위해 작동 벌금 잭슨과 함께 작업 할 때 JSON 무한 재귀 문제 해결

이것이 oneToMany 및 ManyToOne 매핑에서 수행 한 작업입니다.

@ManyToOne
@JoinColumn(name="Key")
@JsonBackReference
private LgcyIsp Key;


@OneToMany(mappedBy="LgcyIsp ")
@JsonManagedReference
private List<Safety> safety;

나는 봄 부팅 응용 프로그램에서 최대 절전 모드 매핑을 사용했다
Prabu M에게

안녕하세요, 훌륭한 튜토리얼과 훌륭한 게시물에 감사드립니다. 그러나 나는 그것을 발견 @JsonManagedReference, @JsonBackReference당신과 관련된 데이터를 제공하지 않습니다 @OneToMany@ManyToOne도 사용하는 경우, 시나리오 @JsonIgnoreProperties관련 엔티티 데이터를 건너 않습니다를. 이것을 해결하는 방법?
Pra_A

5

나에게 가장 좋은 해결책은 @JsonView각 시나리오마다 특정 필터 를 사용 하고 만드는 것입니다. 당신은 또한 사용할 수 @JsonManagedReference@JsonBackReference그러나 그것은 주인이 항상 소유하는 쪽을 참조하는 하나 개의 상황, 결코 반대에 하드 솔루션입니다. 속성을 다르게 다시 주석을 추가해야하는 다른 직렬화 시나리오가있는 경우이를 수행 할 수 없습니다.

문제

두 개의 클래스를 사용 Company하고 Employee그 사이에 주기적 종속성이있는 위치를 사용할 수 있습니다.

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;
    }
}

그리고 ObjectMapper( Spring Boot )를 사용하여 직렬화하려고하는 테스트 클래스 :

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

`@ JsonView`를 사용한 솔루션

@JsonView필터를 사용하고 객체를 직렬화하는 동안 포함 할 필드를 선택할 수 있습니다. 필터는 식별자로 사용되는 클래스 참조 일뿐입니다. 먼저 필터를 만들어 봅시다 :

public class Filter {

    public static interface EmployeeData {};

    public static interface CompanyData extends EmployeeData {};

} 

필터는 @JsonView어노테이션으로 필드를 지정하는 데 사용되는 더미 클래스 이므로 원하는 수만큼을 작성할 수 있습니다. 그것을 실제로 보자.하지만 먼저 우리는 Company클래스 에 주석을 달아야한다 .

public class Company {

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

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

    public Employee getEmployee() {
        return employee;
    }
}

serializer가 View를 사용하도록 Test를 변경하십시오.

@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);
    }
}

이제이 코드를 실행하면 주석이 달린 속성을 직렬화하려고한다고 명시 적으로 말했기 때문에 무한 재귀 문제가 해결되었습니다 @JsonView(Filter.CompanyData.class).

에서 회사의 역 참조에 도달하면 Employee주석이 없는지 확인하고 직렬화를 무시합니다. REST API를 통해 전송할 데이터를 선택할 수있는 강력하고 유연한 솔루션도 있습니다.

Spring을 사용하면 원하는 @JsonView필터로 REST Controllers 메소드에 주석을 달 수 있으며 직렬화는 반환 객체에 투명하게 적용됩니다.

확인해야 할 경우에 사용되는 가져 오기는 다음과 같습니다.

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;

1
이 글은 재귀를 해결하기위한 많은 대안 솔루션을 설명하는 좋은 기사입니다 : baeldung.com/…
Hugo Baés

5

@JsonIgnoreProperties 가 답입니다.

이런 식으로 사용하십시오 ::

@OneToMany(mappedBy = "course",fetch=FetchType.EAGER)
@JsonIgnoreProperties("course")
private Set<Student> students;

Jhipster가 생성 된 코드에서 이것을 사용하는 것을 보았을 때 이것을 자신있게 사용하십시오
ifelse.codes

답변 해주셔서 감사합니다. 그러나 나는 그것을 발견 @JsonManagedReference, @JsonBackReference당신과 관련된 데이터를 제공하지 않습니다 @OneToMany@ManyToOne도 사용하는 경우, 시나리오 @JsonIgnoreProperties관련 엔티티 데이터를 건너 않습니다를. 이것을 해결하는 방법?
Pra_A

4

제 경우에는 다음과 같은 관계를 변경하기에 충분했습니다.

@OneToMany(mappedBy = "county")
private List<Town> towns;

에:

@OneToMany
private List<Town> towns;

다른 관계는 그대로 유지되었습니다.

@ManyToOne
@JoinColumn(name = "county_id")
private County county;

2
Kurt의 솔루션을 사용하는 것이 더 좋습니다. JoinColumn 솔루션은 참조되지 않은 데이터 시체로 끝날 수 있기 때문입니다.
flosk8

1
이것은 실제로 나를 돕는 유일한 것입니다. 상단의 다른 솔루션은 작동하지 않았습니다. 아직도 왜 그런지 모르겠습니다.
Deniss M.

4

어디에서나 com.fasterxml.jackson 을 사용하십시오 . 나는 그것을 찾기 위해 많은 시간을 보냈다.

<properties>
  <fasterxml.jackson.version>2.9.2</fasterxml.jackson.version>
</properties>

<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations -->
<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-annotations</artifactId>
    <version>${fasterxml.jackson.version}</version>
</dependency>

<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>${fasterxml.jackson.version}</version>
</dependency>

그런 다음 @JsonManagedReference및을 사용하십시오 @JsonBackReference.

마지막으로 모델을 JSON으로 직렬화 할 수 있습니다.

import com.fasterxml.jackson.databind.ObjectMapper;

ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(model);

4

@JsonIgnore 를 사용할 수 있지만 외래 키 관계로 인해 액세스 할 수있는 json 데이터는 무시됩니다. 따라서 외래 키 데이터를 필요로하는 경우 (대부분 필요한 경우) @JsonIgnore 가 도움이되지 않습니다. 이러한 상황에서는 아래 해결책을 따르십시오.

BodyStat 클래스가 다시 연수생을 참조 하기 때문에 무한 재귀를 얻습니다. 객체를

BodyStat

@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;

따라서 연수생 에게 위의 부분을 언급 / 생략해야합니다.


1
제 경우에는 작동하지 않습니다. 당신은 봐 주 시겠어요 : github.com/JavaHelper/issue-jackson-boot를 ?
Pra_A

3

나는 또한 같은 문제를 만났다. 내가 사용 @JsonIdentityInfoObjectIdGenerators.PropertyGenerator.class발전기 유형입니다.

그게 내 해결책입니다.

@Entity
@Table(name = "ta_trainee", uniqueConstraints = {@UniqueConstraint(columnNames = {"id"})})
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public class Trainee extends BusinessObject {
...

2
좋은 답변
LAGRIDA

1
나는 똑같은 대답을 할 것입니다 !!! Nice;)
Felipe Desiderati

3

@ManyToOne 엔티티에는 @JsonBackReference를, 엔티티 클래스를 포함하는 @onetomany에는 @JsonManagedReference를 사용해야합니다.

@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;

@ json을 넣으면 자식에 주석을 무시합니다. 아이를 데려가려고 할 때 아이로부터 부모 물건을 얻을 수 없었습니다. 부모 객체가 오지 않는 이유는 @ jsonignore에 의해 무시됩니다. 자녀에게서 부모로, 부모에서 자녀로가는 길을 알려주세요.
Kumaresan Perumal

@JsonIgnore를 사용할 필요가 없습니다. 위의 주석을 사용하고 Getter 및 Setter를 사용하여 부모와 자식의 개체를 얻으십시오. Jsonignore도 같은 작업을 수행하지만 무한 재귀를 만듭니다. 코드를 공유하면 왜 객체를 얻지 못하는지 확인할 수 있습니다. 나를 위해 둘 다오고 있기 때문에.
Shubham

내가하려는 말은. 부모를 데려 갈 때. 부모에게는 자식 개체가 있어야합니다. 어린이 물건을 가져갈 때. 아이는 부모와 함께 가야합니다. 이 시나리오에서는 작동하지 않습니다. 저 좀 도와 주 시겠어요?
Kumaresan Perumal

1

DTO 패턴을 사용하여 주석 최대 절전 모드없이 클래스 TraineeDTO를 만들 수 있으며 Jackson Jackson을 사용하여 Trainee를 TraineeDTO로 변환하고 오류 메시지 disapeare를 빙고 할 수 있습니다 :)


1

속성을 무시할 수 없으면 필드의 가시성을 수정하십시오. 우리의 경우에는 오래된 코드가 여전히 관계가있는 엔티티를 제출하므로 내 경우에는 이것이 수정되었습니다.

    @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
    private Trainee trainee;

@ json을 넣으면 자식에 주석을 무시합니다. 아이를 데려가려고 할 때 아이로부터 부모 물건을 얻을 수 없었습니다. 부모 객체가 오지 않는 이유는 @ jsonignore에 의해 무시됩니다. 자녀에게서 부모로, 부모에서 자녀로가는 길을 알려주세요.
Kumaresan Perumal

0

이 문제가 있었지만 엔티티에 주석을 사용하고 싶지 않았으므로 클래스의 생성자를 작성하여 해결했습니다.이 생성자는이 엔티티를 참조하는 엔티티에 대한 참조를 가져서는 안됩니다. 이 시나리오를 가정 해 봅시다.

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;
}

당신이보기에 클래스 보내려고하면 BA@ResponseBody그것을 무한 루프가 발생할 수 있습니다. 클래스에서 생성자를 작성하고 entityManager이와 같은 쿼리를 만들 수 있습니다 .

"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;
   }

}

그러나이 솔루션에 대한 몇 가지 제한 사항이 있습니다. 생성자에서 List bs에 대한 참조를 만들지 않았습니다 .Hibernate 는 적어도 3.6.10 버전 에서 허용하지 않기 때문에 필요합니다. 뷰에 두 엔티티를 모두 표시하려면 다음을 수행하십시오.

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

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

이 솔루션의 다른 문제는 속성을 추가하거나 제거하면 생성자와 모든 쿼리를 업데이트해야한다는 것입니다.


0

Spring Data Rest를 사용하는 경우 주기적 참조와 관련된 모든 엔티티에 대해 저장소를 작성하여 문제를 해결할 수 있습니다.


0

나는 늦게 왔고 이미 너무 긴 실입니다. 그러나 나는 이것을 알아 내려고 두어 시간을 보냈으며 다른 사례로 내 사례를 제시하고 싶습니다.

JsonIgnore, JsonIgnoreProperties 및 BackReference 솔루션을 모두 시도했지만 이상하게도 픽업되지 않은 것 같습니다.

나는 Lombok을 사용했으며 생성자를 만들고 toString (스택 오버 플로우 오류 스택의 톱 toString)을 재정의하기 때문에 방해 할 수 있다고 생각했습니다.

마지막으로 Lombok의 잘못이 아니 었습니다. 데이터베이스 테이블에서 JPA 엔티티의 자동 NetBeans 생성을 많이 사용하지 않았습니다. 잘 생성되었으며 생성 된 클래스에 추가 된 주석 중 하나는 @XmlRootElement입니다. 일단 제거하면 모든 것이 작동하기 시작했습니다. 오 잘


0

요점은 @JsonIgnore 를 setter 메소드에 다음과 같이 배치하는 입니다. 나의 경우에는.

Township.java

@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;
}

Village.java

@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "townshipId", insertable=false, updatable=false)
Township township;

@Column(name = "townshipId", nullable=false)
Long townshipId;
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.