Recursión infinita con Jackson JSON e Hibernate JPA

412

Cuando trato de convertir un objeto JPA que tiene una asociación bidireccional en JSON, sigo obteniendo

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

Todo lo que encontré es este hilo que básicamente concluye con la recomendación de evitar las asociaciones bidireccionales. ¿Alguien tiene una idea para una solución alternativa para este error de primavera?

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

Fragmentos de código:

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

Implementación JPA del aprendiz 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
fuente
Añadir @Transienta Trainee.bodyStats.
phil294
A partir de 2017, @JsonIgnorePropertieses la solución más limpia. Mira la respuesta de Zammel AlaaEddine para más detalles.
Utku
¿Cómo es la culpa de esta primavera?
Nathan Hughes

Respuestas:

294

Puede usar @JsonIgnorepara romper el ciclo.

axtavt
fuente
1
@Ben: En realidad no lo sé. Quizás su soporte no estaba habilitado: wiki.fasterxml.com/JacksonJAXBAnnotations
axtavt
40
Desde Jackson 1.6 hay una mejor solución: puede usar dos nuevas anotaciones para resolver un problema de recursión infinita sin ignorar los captadores / establecedores durante la serialización. Vea mi respuesta a continuación para más detalles.
Kurt Bourbaki
1
@axtavt Gracias por la respuesta perfecta. Por cierto, vine con otra solución: simplemente puede evitar crear getter para este valor, por lo que Spring no podrá acceder a él mientras crea JSON (pero no creo que se adapte a cada caso, por lo que su respuesta es mejor)
Semyon Danilov
11
Parece que todas las soluciones anteriores necesitan cambiar los objetos de dominio agregando anotaciones. Si serializo clases de terceros que no tengo forma de modificarlas. ¿Cómo puedo evitar este problema?
Jianwu Chen
2
Esta solución no funciona en algunas situaciones. En la base de datos relacional con jpa, si lo pone @JsonIgnore, será nulo en "clave externa" cuando actualice la entidad ...
Slim
629

JsonIgnoreProperties [Actualización 2017]:

Ahora puede usar JsonIgnoreProperties para suprimir la serialización de propiedades (durante la serialización) o ignorar el procesamiento de las propiedades de JSON leídas (durante la deserialización) . Si esto no es lo que estás buscando, sigue leyendo a continuación.

(Gracias a As Zammel AlaaEddine por señalar esto).


JsonManagedReference y JsonBackReference

Desde Jackson 1.6 puede usar dos anotaciones para resolver el problema de recursión infinita sin ignorar los captadores / establecedores durante la serialización: @JsonManagedReferencey @JsonBackReference.

Explicación

Para que Jackson funcione bien, uno de los dos lados de la relación no debe ser serializado, para evitar el ciclo infite que causa su error de desbordamiento de pila.

Entonces, Jackson toma la parte hacia adelante de la referencia (su Set<BodyStat> bodyStatsen la clase de Aprendiz), y la convierte en un formato de almacenamiento similar a json; Este es el llamado proceso de clasificación . Luego, Jackson busca la parte posterior de la referencia (es decir, Trainee traineeen la clase BodyStat) y la deja como está, sin serializarla. Esta parte de la relación se reconstruirá durante la deserialización ( desarme ) de la referencia directa.

Puede cambiar su código de esta manera (omito las partes inútiles):

Objeto comercial 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 comercial 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;

Ahora todo debería funcionar correctamente.

Si desea más información, escribí un artículo sobre los problemas de Json y Jackson Stackoverflow en Keenformatics , mi blog.

EDITAR:

Otra anotación útil que puede verificar es @JsonIdentityInfo : al usarla, cada vez que Jackson serialice su objeto, agregará una ID (u otro atributo de su elección) para que no lo "escanee" por completo cada vez. Esto puede ser útil cuando tiene un bucle de cadena entre objetos más interrelacionados (por ejemplo: Order -> OrderLine -> User -> Order y otra vez).

En este caso, debe tener cuidado, ya que podría necesitar leer los atributos de su objeto más de una vez (por ejemplo, en una lista de productos con más productos que comparten el mismo vendedor), y esta anotación lo impide. Sugiero que siempre eche un vistazo a los registros de Firebug para verificar la respuesta de Json y ver qué está sucediendo en su código.

Fuentes:

Kurt Bourbaki
fuente
29
Gracias por una respuesta clara. Esta es una solución más conveniente que poner @JsonIgnorede nuevo la referencia.
Utku Özdemir
3
Esta es definitivamente la forma correcta de hacerlo. Si lo hace así en el lado del servidor porque usa Jackson allí, no importa qué mapeador json use en el lado del cliente y no tiene que configurar el manual del enlace del niño al padre. Simplemente funciona Gracias Kurt
flosk8
1
Agradable, explicación detallada y definitivamente un enfoque mejor y más descriptivo que @JsonIgnore.
Piotr Nowicki
2
¡Gracias! @JsonIdentityInfo trabajó para referencias cíclicas que involucraron múltiples entidades en muchos bucles superpuestos.
n00b
1
No puedo hacer que esto funcione por mi vida. Creo que tengo una configuración bastante similar, pero obviamente tengo algo mal ya que no puedo obtener nada más que errores de recidiva infinita:
swv
103

La nueva anotación @JsonIgnoreProperties resuelve muchos de los problemas con las otras opciones.

@Entity

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

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

Compruébalo aquí. Funciona igual que en la documentación:
http://springquay.blogspot.com/2016/01/new-approach-to-solve-json-recursive.html

tero17
fuente
@tero: con este enfoque también no obtenemos datos asociados con la entidad.
Pra_A
@PAA HEY PAA ¡Creo que está asociado con la entidad! por qué dices eso ?
tero17
1
@ tero17 ¿cómo gestionas la recursión infinita cuando tienes más de 2 clases? Por ejemplo: Clase A -> Clase B -> Clase C -> Clase A. Intenté con JsonIgnoreProperties sin suerte
Villat
@Villat, este es otro problema a resolver, sugiero abrir una nueva demanda para eso.
tero17
+1 para el ejemplo de código, como novato de Jackson, el uso de @JsonIgnoreProperties no fue del todo claro al leer
JavaDoc
47

Además, puede usar Jackson 2.0+ @JsonIdentityInfo. Esto funcionó mucho mejor para mis clases de hibernación que @JsonBackReferencey @JsonManagedReference, que tenía problemas para mí y no resolvió el problema. Solo agrega 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 {

y debería funcionar

Marcus
fuente
¿Puede explicar "Esto funcionó mucho mejor"? ¿Hay algún problema con la referencia administrada?
Utku Özdemir
@ UtkuÖzdemir Agregué detalles sobre @JsonIdentityInfomi respuesta anterior.
Kurt Bourbaki
1
Esta es la mejor solución que hemos encontrado hasta ahora, porque cuando usamos "@JsonManagedReference", el método get devolvió los valores con éxito sin ningún error de stackoverflow. Pero, cuando intentamos guardar datos usando la publicación, devolvió un error de 415 (error de soporte no compatible)
cuser
1
He agregado @JsonIdentityInfoanotaciones a mis entidades, pero no resuelve el problema de recursión. Solo @JsonBackReferencey @JsonManagedReferenceresuelve, pero se eliminan las propiedades mapeadas de JSON.
Oleg Abrazhaev
19

Además, Jackson 1.6 tiene soporte para manejar referencias bidireccionales ... que parece ser lo que está buscando ( esta entrada de blog también menciona la característica)

Y a partir de julio de 2011, también hay " jackson-module-hibernate ", que podría ayudar en algunos aspectos del manejo de objetos Hibernate, aunque no necesariamente este en particular (que requiere anotaciones).

StaxMan
fuente
Los enlaces están muertos, ¿te importaría actualizarlos o editar tu respuesta?
GetMeARemoteJob
9

Esto funcionó perfectamente bien para mí. Agregue la anotación @JsonIgnore en la clase secundaria donde menciona la referencia a la clase primaria.

@ManyToOne
@JoinColumn(name = "ID", nullable = false, updatable = false)
@JsonIgnore
private Member member;
Manjunath BR
fuente
2
Creo que @JsonIgnoreignora este atributo de ser recuperado al lado del cliente. ¿Qué sucede si necesito este atributo con su hijo (si tiene un hijo)?
Khasan 24-7
6

Ahora hay un módulo Jackson (para Jackson 2) diseñado específicamente para manejar los problemas de inicialización diferida de Hibernate al serializar.

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

Simplemente agregue la dependencia (tenga en cuenta que hay diferentes dependencias para Hibernate 3 e Hibernate 4):

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

y luego registre el módulo al inicializar el ObjectMapper de Jackson:

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

La documentación actualmente no es genial. Consulte el código Hibernate4Module para ver las opciones disponibles.

Shane
fuente
Lo que el problema hace es resolverlo, porque parece interesante. Tengo el mismo problema que el OP y todos los trucos incluidos anteriormente no han funcionado.
user1567291
6

Funciona bien para mí Resolver el problema de recursión infinita de Json al trabajar con Jackson

Esto es lo que he hecho en OneToMany y ManyToOne Mapping

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


@OneToMany(mappedBy="LgcyIsp ")
@JsonManagedReference
private List<Safety> safety;
Prabu M
fuente
He utilizado el mapeo de hibernación en la aplicación de arranque de primavera
Prabu M
Hola autor, gracias por los buenos tutoriales y excelentes publicaciones. Sin embargo, me encontré con que @JsonManagedReference, @JsonBackReferenceno le da los datos asociados con @OneToManyy @ManyToOneescenario, también cuando se utiliza @JsonIgnorePropertiesno omitir datos de la entidad asociada. ¿Cómo resolver esto?
Pra_A
5

Para mí, la mejor solución es usar @JsonViewy crear filtros específicos para cada escenario. También puede usar @JsonManagedReferencey @JsonBackReference, sin embargo, es una solución codificada para una sola situación, donde el propietario siempre hace referencia al lado propietario, y nunca al contrario. Si tiene otro escenario de serialización donde necesita volver a anotar el atributo de manera diferente, no podrá hacerlo.

Problema

Usemos dos clases, Companyy Employeedonde tenga una dependencia cíclica entre ellas:

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

Y la clase de prueba que intenta 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);
    }
}

Si ejecuta este código, obtendrá lo siguiente:

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

Solución usando `@ JsonView`

@JsonViewle permite usar filtros y elegir qué campos se deben incluir al serializar los objetos. Un filtro es solo una referencia de clase utilizada como identificador. Así que primero creemos los filtros:

public class Filter {

    public static interface EmployeeData {};

    public static interface CompanyData extends EmployeeData {};

} 

Recuerde, los filtros son clases ficticias, solo se utilizan para especificar los campos con la @JsonViewanotación, para que pueda crear tantos como desee y necesite. Vamos a verlo en acción, pero primero tenemos que anotar nuestra Companyclase:

public class Company {

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

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

    public Employee getEmployee() {
        return employee;
    }
}

y cambie la Prueba para que el serializador use la Vista:

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

Ahora, si ejecuta este código, se resuelve el problema de recursión infinita, porque ha dicho explícitamente que solo desea serializar los atributos que se anotaron con @JsonView(Filter.CompanyData.class) .

Cuando llega a la referencia posterior para la compañía en el Employee, verifica que no esté anotada e ignora la serialización. También tiene una solución potente y flexible para elegir qué datos desea enviar a través de sus API REST.

Con Spring puede anotar sus métodos de Controladores REST con el @JsonViewfiltro deseado y la serialización se aplica de forma transparente al objeto que regresa.

Aquí están las importaciones utilizadas en caso de que necesite 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
fuente
1
Este es un buen artículo que explica muchas soluciones alternativas para resolver las recurrencias
Hugo Baés
5

@JsonIgnoreProperties es la respuesta.

Usa algo como esto ::

@OneToMany(mappedBy = "course",fetch=FetchType.EAGER)
@JsonIgnoreProperties("course")
private Set<Student> students;
ifelse.codes
fuente
Use esto con confianza ya que he visto que Jhipster usa esto en su código generado
ifelse.codes
Gracias por la respuesta. Sin embargo, me encontré con que @JsonManagedReference, @JsonBackReferenceno le da los datos asociados con @OneToManyy @ManyToOneescenario, también cuando se utiliza @JsonIgnorePropertiesno omitir datos de la entidad asociada. ¿Cómo resolver esto?
Pra_A
4

En mi caso fue suficiente para cambiar la relación de:

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

a:

@OneToMany
private List<Town> towns;

otra relación se mantuvo como estaba:

@ManyToOne
@JoinColumn(name = "county_id")
private County county;
Klapsa2503
fuente
2
Creo que es mejor usar la solución de Kurt. Porque la solución JoinColumn puede terminar en cuerpos muertos de datos sin referencia.
flosk8
1
Esto es en realidad lo único que me ayudó. Ninguna otra solución de la parte superior funcionó. Todavía no estoy seguro de por qué ...
Deniss M.
4

Asegúrese de usar com.fasterxml.jackson en todas partes. Pasé mucho tiempo para descubrirlo.

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

Luego usa @JsonManagedReferencey @JsonBackReference.

Finalmente, puede serializar su modelo a JSON:

import com.fasterxml.jackson.databind.ObjectMapper;

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

Puede usar @JsonIgnore , pero esto ignorará los datos json a los que se puede acceder debido a la relación de clave externa. Por lo tanto, si necesita los datos de la clave externa (la mayor parte del tiempo que necesitamos), entonces @JsonIgnore no lo ayudará. En tal situación, siga la siguiente solución.

está obteniendo una recursión infinita, debido a que la clase BodyStat vuelve a referirse al objeto Trainee

BodyStat

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

Aprendiz

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

Por lo tanto, debe comentar / omitir la parte anterior en Aprendiz

RAJ KASHWAN
fuente
1
En mi caso, no funciona. ¿Podrías echar un vistazo: github.com/JavaHelper/issue-jackson-boot ?
Pra_A
3

También me encontré con el mismo problema. Solía @JsonIdentityInfo's ObjectIdGenerators.PropertyGenerator.classtipo de generador.

Esa es mi solución:

@Entity
@Table(name = "ta_trainee", uniqueConstraints = {@UniqueConstraint(columnNames = {"id"})})
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public class Trainee extends BusinessObject {
...
Arif Acar
fuente
2
La buena respuesta
LAGRIDA
1
Yo respondería lo mismo !!! Nice;)
Felipe Desiderati
3

Debe usar @JsonBackReference con la entidad @ManyToOne y @JsonManagedReference con las clases de entidad que contienen @onetomany.

@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
fuente
Si pongo anotación @ jsonIgnore en el niño. No pude obtener el objeto padre del niño. Cuando trato de tomar el niño. @ jsonignore ignora por qué el objeto padre no viene. dime la manera de pasar de un niño a otro y de padre a hijo.
Kumaresan Perumal
No es necesario usar @JsonIgnore solo use las anotaciones anteriores y Para obtener los objetos de padre e hijo Mediante Getters y setters. y Jsonignore también está haciendo lo mismo, pero creará una recursión infinita. Si comparte su código, entonces puedo verificar por qué no obtiene objetos. Porque para mí ambos vienen.
Shubham el
Quise decir. cuando toma un padre. El padre debe venir con un objeto hijo. al tomar un objeto hijo. El niño debe venir con un padre. No está funcionando en este escenario. ¿Me podría ayudar?
Kumaresan Perumal
1

puede usar el patrón DTO crear la clase TraineeDTO sin ninguna hibernación de anotación y puede usar jackson mapper para convertir Trainee a TraineeDTO y desaparecer el mensaje de error :)

Dahar Youssef
fuente
1

Si no puede ignorar la propiedad, intente modificar la visibilidad del campo. En nuestro caso, teníamos código antiguo que aún enviaba entidades con la relación, por lo que en mi caso, esta fue la solución:

    @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
    private Trainee trainee;
Scott Langeberg
fuente
Si pongo anotación @ jsonIgnore en el niño. No pude obtener el objeto padre del niño. Cuando trato de tomar el niño. @ jsonignore ignora por qué el objeto padre no viene. dime la manera de pasar de un niño a otro y de padre a hijo.
Kumaresan Perumal
0

Tuve este problema, pero no quería usar anotaciones en mis entidades, así que resolví creando un constructor para mi clase, este constructor no debe tener una referencia a las entidades que hacen referencia a esta entidad. Digamos este escenario.

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

Si intenta enviar a la vista la clase Bo Acon @ResponseBodyella puede causar un bucle infinito. Puede escribir un constructor en su clase y crear una consulta entityManagercomo esta.

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

Esta es la clase con el constructor.

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

}

Sin embargo, hay algunas restricciones sobre esta solución, como puede ver, en el constructor no hice referencia a List bs, esto se debe a que Hibernate no lo permite, al menos en la versión 3.6.10.Final , así que cuando necesito para mostrar ambas entidades en una vista, hago lo siguiente.

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

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

El otro problema con esta solución es que si agrega o elimina una propiedad, debe actualizar su constructor y todas sus consultas.

OJVM
fuente
0

En caso de que esté utilizando Spring Data Rest, el problema se puede resolver creando repositorios para cada entidad involucrada en referencias cíclicas.

Morik
fuente
0

Llego tarde y ya es un hilo tan largo. Pero también pasé un par de horas tratando de resolver esto, y me gustaría dar mi caso como otro ejemplo.

Probé las soluciones JsonIgnore, JsonIgnoreProperties y BackReference, pero, curiosamente, fue como si no hubieran sido recogidas.

Usé Lombok y pensé que tal vez interfiera, ya que crea constructores y anula toString (saw toString en stackoverflowerror stack).

Finalmente, no fue culpa de Lombok: utilicé la generación automática de NetBeans de entidades JPA a partir de tablas de bases de datos, sin pensarlo demasiado, bueno, y una de las anotaciones que se agregaron a las clases generadas fue @XmlRootElement. Una vez que lo eliminé, todo comenzó a funcionar. Oh bien.

hola_ tierra
fuente
0

El punto es colocar @JsonIgnore en el método setter de la siguiente manera. en mi 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
fuente