Recursão infinita com o problema JSON de Jackson e JPA do Hibernate

412

Ao tentar converter um objeto JPA que tenha uma associação bidirecional em JSON, continuo recebendo

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

Tudo o que eu encontrei é esse tópico que basicamente conclui com a recomendação de evitar associações bidirecionais. Alguém tem uma idéia para uma solução alternativa para este bug da primavera?

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

Partes de codigo:

Objeto de negócios 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 ...

Objeto de negócios 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;

Controlador:

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

Implementação pela JPA do estagiário 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();
    }
}

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>
Ta Sas
fonte
Adicionar @Transienta Trainee.bodyStats.
precisa saber é
A partir de 2017, @JsonIgnorePropertiesé a solução mais limpa. Confira a resposta de Zammel AlaaEddine para obter mais detalhes.
Utku
Como é a culpa desta primavera?
Nathan Hughes

Respostas:

293

Você pode usar @JsonIgnorepara interromper o ciclo.

axtavt
fonte
1
@ Ben: Na verdade eu não sei. Talvez o suporte não tenha sido ativado: wiki.fasterxml.com/JacksonJAXBAnnotations
axtavt
40
Desde o Jackson 1.6, existe uma solução melhor: você pode usar duas novas anotações para resolver problemas de recursão infinita sem ignorar os getters / setters durante a serialização. Veja minha resposta abaixo para obter detalhes.
Kurt Bourbaki
1
@axtavt Obrigado pela resposta perfeita. Aliás, eu vim com outra solução: você pode simplesmente evitar criar getter para esse valor, para que o Spring não possa acessá-lo enquanto cria JSON (mas não acho que seja adequado a todos os casos, então sua resposta é melhor)
Semyon Danilov 28/02
11
Todas as soluções acima parecem precisar alterar os objetos de domínio adicionando anotações. Se eu serializar classes de terceiros, não tenho como modificá-las. Como posso evitar esse problema?
Jianwu Chen
2
esta solução não funciona em algumas situações. No banco de dados relacional com jpa, se você colocar @JsonIgnorevocê vai nulo em "chave estrangeira" quando você atualizar a entidade ...
magro
629

JsonIgnoreProperties [atualização de 2017]:

Agora você pode usar JsonIgnoreProperties para suprimir a serialização de propriedades (durante a serialização) ou ignorar o processamento das propriedades JSON lidas (durante a desserialização) . Se não é isso que você procura, continue lendo abaixo.

(Obrigado a As Zammel AlaaEddine por apontar isso).


JsonManagedReference e JsonBackReference

Desde o Jackson 1.6, você pode usar duas anotações para resolver o problema de recursão infinita sem ignorar os getters / setters durante a serialização: @JsonManagedReferencee @JsonBackReference.

Explicação

Para que Jackson funcione bem, um dos dois lados do relacionamento não deve ser serializado, a fim de evitar o loop infinito que causa o erro de fluxo de pilha.

Então, Jackson pega a parte avançada da referência (sua Set<BodyStat> bodyStatsna classe Trainee) e a converte em um formato de armazenamento semelhante ao json; esse é o chamado processo de empacotamento . Então, Jackson procura a parte de trás da referência (ou seja, Trainee traineena classe BodyStat) e a deixa como está, não a serializando. Essa parte do relacionamento será reconstruída durante a desserialização ( desserialização ) da referência futura.

Você pode alterar seu código assim (pulo as partes inúteis):

Objeto de negócios 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;

Objeto de negócios 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;

Agora tudo deve funcionar corretamente.

Se você quiser mais informações, escrevi um artigo sobre os problemas de Json e Jackson Stackoverflow no Keenformatics , meu blog.

EDITAR:

Outra anotação útil que você pode verificar é @JsonIdentityInfo : ao usá-lo, toda vez que Jackson serializar seu objeto, ele adicionará um ID (ou outro atributo de sua escolha) a ele, para que ele não seja "digitalizado" novamente toda vez. Isso pode ser útil quando você tiver um loop em cadeia entre objetos mais inter-relacionados (por exemplo: Pedido -> Linha de pedidos -> Usuário -> Pedido e novamente).

Nesse caso, você precisa ter cuidado, pois pode ser necessário ler os atributos do seu objeto mais de uma vez (por exemplo, em uma lista de produtos com mais produtos que compartilham o mesmo vendedor), e essa anotação impede que você faça isso. Sugiro sempre dar uma olhada nos logs do firebug para verificar a resposta do Json e ver o que está acontecendo no seu código.

Fontes:

Kurt Bourbaki
fonte
29
Obrigado pela resposta clara. Esta é uma solução mais conveniente do que recolocar @JsonIgnorea referência.
Utku Özdemir
3
Este é definitivamente o caminho certo para fazê-lo. Se você fizer isso do lado do servidor, porque usa Jackson lá, não importa qual o mapeador json que você usa no lado do cliente e não precisará definir o filho como manual do link pai. Isso simplesmente funciona. Obrigado Kurt
flosk8
1
Explicação agradável e detalhada e uma abordagem definitivamente melhor e mais descritiva do que @JsonIgnore.
Piotr Nowicki
2
Obrigado! O @JsonIdentityInfo trabalhou para referências cíclicas que envolviam várias entidades em muitos ciclos sobrepostos.
N00b 21/05
1
Não consigo fazer isso funcionar pela minha vida. Acho que tenho uma configuração bastante semelhante, mas obviamente entendi algo errado, pois não consigo obter nada além de infinitos erros de recurisão:
swv
103

A nova anotação @JsonIgnoreProperties resolve muitos dos problemas com as outras opções.

@Entity

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

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

Confira aqui. Funciona como na documentação:
http://springquay.blogspot.com/2016/01/new-approach-to-solve-json-recursive.html

tero17
fonte
@tero - Com essa abordagem, também não obtemos dados associados à entidade.
Pra_A 6/08/19
@PAA HEY PAA Eu acho que está associado à entidade! por que você diz isso ?
precisa saber é
1
@ tero17 como você gerencia a recursão infinita quando tem mais de 2 classes? Por exemplo: Classe A -> Classe B -> Classe C -> Classe A. Eu tentei com JsonIgnoreProperties sem sorte
Villat
@ Villat este é outro problema a ser resolvido, sugiro abrir uma nova demanda por isso.
precisa saber é
+1 para o exemplo de código, como um novato em Jackson, o uso de @JsonIgnoreProperties não ficou totalmente claro ao ler o JavaDoc
Wecherowski
47

Além disso, usando o Jackson 2.0+ você pode usar @JsonIdentityInfo. Isso funcionou muito melhor para minhas aulas de hibernação do que @JsonBackReferencee @JsonManagedReference, o que teve problemas para mim e não resolveu o problema. Basta adicionar algo como:

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

e deve funcionar.

Marcus
fonte
Você pode explicar "Isso funcionou muito melhor"? Existe um problema com a referência gerenciada?
Utku Özdemir
@ UtkuÖzdemir Adicionei detalhes sobre @JsonIdentityInfona minha resposta acima.
Kurt Bourbaki
1
essa é a melhor solução que encontramos até agora, porque quando usamos "@JsonManagedReference", o método get retornou os valores com êxito, sem nenhum erro de stackoverflow. Mas, quando tentamos salvar os dados usando a postagem, ele retornou um erro 415 (erro de mídia não suportado)
cuser
1
Adicionei @JsonIdentityInfoanotações às minhas entidades, mas isso não resolve o problema de recursão. Somente @JsonBackReferencee @JsonManagedReferenceresolve, mas eles são remover propriedades mapeadas do JSON.
Oleg Abrazhaev 15/07
19

Além disso, o Jackson 1.6 tem suporte para lidar com referências bidirecionais ... o que parece o que você está procurando ( esta entrada de blog também menciona o recurso)

E a partir de julho de 2011, também há " jackson-module-hibernate " que pode ajudar em alguns aspectos ao lidar com objetos do Hibernate, embora não necessariamente este em particular (que requer anotações).

StaxMan
fonte
Os links estão inoperantes, você se importa de atualizá-los ou editar sua resposta.
GetMeARemoteJob
9

Isso funcionou perfeitamente bem para mim. Adicione a anotação @JsonIgnore na classe filho em que você menciona a referência à classe pai.

@ManyToOne
@JoinColumn(name = "ID", nullable = false, updatable = false)
@JsonIgnore
private Member member;
Manjunath BR
fonte
2
Eu acho que @JsonIgnoreignora esse atributo de ser recuperado para o lado do cliente. E se eu precisar desse atributo com seu filho (se ele tiver um filho)?
Khasan 24-7
6

Agora existe um módulo Jackson (para Jackson 2) projetado especificamente para lidar com problemas de inicialização lenta do Hibernate ao serializar.

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

Basta adicionar a dependência (observe que existem diferentes dependências para o Hibernate 3 e Hibernate 4):

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

e registre o módulo ao inicializar o ObjectMapper de Jackson:

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

A documentação atualmente não é ótima. Veja o código Hibernate4Module para opções disponíveis.

Shane
fonte
O que o problema faz é resolver então, porque parece interessante. Eu tenho o mesmo problema que o OP e todos os truques, incluindo acima, não funcionaram.
user1567291
6

Trabalhando bem para mim Resolver o problema de recursão infinita do Json ao trabalhar com Jackson

Foi o que fiz no mapeamento oneToMany e ManyToOne

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


@OneToMany(mappedBy="LgcyIsp ")
@JsonManagedReference
private List<Safety> safety;
Prabu M
fonte
Eu tenho usado o mapeamento de hibernação no aplicativo de inicialização primavera
Prabu M
Olá Autor, Obrigado pelos bons tutoriais e ótimas postagens. No entanto, descobri que @JsonManagedReference, @JsonBackReferencenão fornece os dados associados @OneToManye o @ManyToOnecenário, também quando o uso @JsonIgnorePropertiesignora os dados da entidade associada. Como resolver isso?
Pra_A 6/08/19
5

Para mim, a melhor solução é usar @JsonViewe criar filtros específicos para cada cenário. Você também pode usar @JsonManagedReferencee @JsonBackReference, no entanto, é uma solução codificada para apenas uma situação, em que o proprietário sempre faz referência ao lado proprietário e nunca ao contrário. Se você tiver outro cenário de serialização em que precisará anotar novamente o atributo de maneira diferente, não poderá.

Problema

Vamos usar duas classes Companye Employeeonde você tem uma dependência cíclica entre elas:

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

E a classe de teste que tenta serializar usando 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);
    }
}

Se você executar esse código, obterá o:

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

Solução usando `@ JsonView`

@JsonViewpermite usar filtros e escolher quais campos devem ser incluídos ao serializar os objetos. Um filtro é apenas uma referência de classe usada como identificador. Então, primeiro vamos criar os filtros:

public class Filter {

    public static interface EmployeeData {};

    public static interface CompanyData extends EmployeeData {};

} 

Lembre-se de que os filtros são classes fictícias, usadas apenas para especificar os campos com a @JsonViewanotação, para que você possa criar quantos quiser e precisar. Vamos vê-lo em ação, mas primeiro precisamos anotar nossa Companyclasse:

public class Company {

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

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

    public Employee getEmployee() {
        return employee;
    }
}

e mude o teste para que o serializador use a exibição:

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

Agora, se você executar esse código, o problema da Recursão Infinita será resolvido, porque você disse explicitamente que deseja serializar os atributos que foram anotados @JsonView(Filter.CompanyData.class).

Quando atinge a referência anterior da empresa no Employee, verifica se não está anotado e ignora a serialização. Você também tem uma solução poderosa e flexível para escolher quais dados deseja enviar por meio de suas APIs REST.

Com o Spring, você pode anotar seus métodos dos controladores REST com o @JsonViewfiltro desejado e a serialização é aplicada de forma transparente ao objeto retornado.

Aqui estão as importações usadas, caso você precise verificar:

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;
fabioresner
fonte
1
Este é um bom artigo explicando muitas soluções alternativas para resolver recursões: baeldung.com/…
Hugo Baés
5

@JsonIgnoreProperties é a resposta.

Use algo como isto ::

@OneToMany(mappedBy = "course",fetch=FetchType.EAGER)
@JsonIgnoreProperties("course")
private Set<Student> students;
ifelse.codes
fonte
Use esta confiança como eu já vi Jhipster usa isso em seu código gerado
ifelse.codes
Obrigado pela resposta. No entanto, descobri que @JsonManagedReference, @JsonBackReferencenão fornece os dados associados @OneToManye o @ManyToOnecenário, também quando o uso @JsonIgnorePropertiesignora os dados da entidade associada. Como resolver isso?
Pra_A 6/08/19
4

No meu caso, foi o suficiente para mudar a relação de:

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

para:

@OneToMany
private List<Town> towns;

outra relação permaneceu como estava:

@ManyToOne
@JoinColumn(name = "county_id")
private County county;
Klapsa2503
fonte
2
Eu acho que é melhor usar a solução de Kurt. Como a solução JoinColumn pode terminar em corpos mortos de dados não referenciados.
Flsk8
1
Esta é realmente a única coisa que me ajudou. Nenhuma outra solução do topo funcionou. Eu ainda não tenho certeza por que ...
Deniss M.
4

Certifique-se de usar com.fasterxml.jackson em todos os lugares. Passei muito tempo para descobrir.

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

Então use @JsonManagedReferencee @JsonBackReference.

Por fim, você pode serializar seu modelo para JSON:

import com.fasterxml.jackson.databind.ObjectMapper;

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

Você pode usar @JsonIgnore , mas isso ignorará os dados json que podem ser acessados ​​devido ao relacionamento de Chave Estrangeira. Portanto, se você solicitar os dados da chave estrangeira (na maioria das vezes exigimos), o @JsonIgnore não ajudará. Em tal situação, siga a solução abaixo.

você está recebendo recursão infinita, devido à classe BodyStat referindo novamente o objeto Trainee

BodyStat

@ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@JoinColumn(name="trainee_fk")
private Trainee trainee;

Estagiário

@OneToMany(mappedBy = "trainee", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@Column(nullable = true)
private Set<BodyStat> bodyStats;

Portanto, você deve comentar / omitir a parte acima no Trainee

RAJ KASHWAN
fonte
1
No meu caso, não está funcionando. Você poderia dar uma olhada: github.com/JavaHelper/issue-jackson-boot ?
Pra_A 06/08/19
3

Eu também encontrei o mesmo problema. Eu usei @JsonIdentityInfoo ObjectIdGenerators.PropertyGenerator.classtipo de gerador.

Essa é a minha solução:

@Entity
@Table(name = "ta_trainee", uniqueConstraints = {@UniqueConstraint(columnNames = {"id"})})
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public class Trainee extends BusinessObject {
...
Arif Acar
fonte
2
A boa resposta
LAGRIDA
1
Eu responderia a mesma coisa !!! Bom;)
Felipe Desiderati
3

Você deve usar @JsonBackReference com a entidade @ManyToOne e @JsonManagedReference com @onetomany contendo classes de entidade.

@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;
Shubham
fonte
Se eu colocar a anotação @ jsonIgnore na criança. Não pude obter o objeto pai do filho. Quando tento levar o filho. por que o objeto pai não está chegando, ele é ignorado por @ jsonignore. diga-me o caminho para passar de filho para pai e pai para filho.
Kumaresan Perumal
Não é necessário usar o @JsonIgnore, basta usar as anotações acima e obter objetos de pai e filho usando Getters e setters. e Jsonignore também está fazendo o mesmo, mas criará uma recursão infinita. Se você compartilhar seu código, posso verificar por que você não está recebendo objetos. Porque para mim ambos estão chegando.
Shubham
Eu quis dizer. ao tomar um pai. O pai deve vir com o objeto filho. ao pegar um objeto filho. A criança deve vir com os pais. Não está funcionando neste cenário. Podes ajudar-me, por favor?
Kumaresan Perumal
1

você pode usar o padrão DTO para criar a classe TraineeDTO sem qualquer anotação hiberbnate e pode usar o jackson mapper para converter Trainee em TraineeDTO e bingo a mensagem de erro desaparece :)

Dahar Youssef
fonte
1

Se você não pode ignorar a propriedade, tente modificar a visibilidade do campo. No nosso caso, tínhamos código antigo ainda enviando entidades com o relacionamento, portanto, no meu caso, essa era a correção:

    @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
    private Trainee trainee;
Scott Langeberg
fonte
Se eu colocar a anotação @ jsonIgnore na criança. Não pude obter o objeto pai do filho. Quando tento levar o filho. por que o objeto pai não está chegando, ele é ignorado por @ jsonignore. diga-me o caminho para passar de filho para pai e pai para filho.
Kumaresan Perumal
0

Eu tinha esse problema, mas não queria usar anotação em minhas entidades, então resolvi criando um construtor para minha classe; esse construtor não deve ter uma referência de volta às entidades que fazem referência a essa entidade. Vamos dizer esse cenário.

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

Se você tentar enviar para a exibição a classe Bou Acom @ResponseBodyela, poderá causar um loop infinito. Você pode escrever um construtor em sua classe e criar uma consulta entityManagercomo esta.

"select new A(id, code, name) from A"

Esta é a classe com o construtor.

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

}

No entanto, existem algumas restrições sobre esta solução, como você pode ver, no construtor não fiz referência à Lista bs porque o Hibernate não permite, pelo menos na versão 3.6.10.Final , então quando eu precisar para mostrar as duas entidades em uma exibição, faça o seguinte.

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

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

O outro problema com esta solução é que, se você adicionar ou remover uma propriedade, deverá atualizar seu construtor e todas as suas consultas.

OJVM
fonte
0

Caso você esteja usando o Spring Data Rest, o problema pode ser resolvido criando Repositórios para cada Entidade envolvida em referências cíclicas.

Morik
fonte
0

Estou atrasado e já é um tópico tão longo. Mas passei algumas horas tentando descobrir isso também e gostaria de dar meu caso como outro exemplo.

Tentei as soluções JsonIgnore, JsonIgnoreProperties e BackReference, mas, estranhamente, era como se não fossem apanhadas.

Eu usei o Lombok e pensei que talvez isso interfira, pois ele cria construtores e substitui o toString (vi toString na stackoverflowerror stack).

Finalmente, não foi culpa de Lombok - usei a geração automática de entidades JPA do NetBeans a partir de tabelas de banco de dados, sem pensar muito - bem, e uma das anotações adicionadas às classes geradas foi @XmlRootElement. Depois que o removi, tudo começou a funcionar. Ah bem.

hello_earth
fonte
0

O objetivo é colocar o @JsonIgnore no método setter da seguinte maneira. No meu caso.

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;
zawhtut
fonte