Estoy trabajando en un proyecto de EclipseLink en el que un usuario puede "seguir" a otro, como se puede hacer en los sitios de redes sociales. Tengo esto configurado con una entidad User (que hace referencia a una tabla llamada users ) que tiene una lista de "seguidores" (usuarios que siguen a ese usuario) y otra lista de "seguidores" (usuarios que el usuario sigue). La relación se define en una tabla separada llamada followers que contiene columnas para el ID del usuario seguido ( user_id ) y el siguiente ID del usuario ( follower_id ).
Mi modelo de usuarios se ve así:
@Entity @Table(name = "users") @NamedQuery(name = "User.findAll", query = "SELECT u FROM USER u") public class User { // other attributes @ManyToMany(fetch = FetchType.LAZY) @JoinTable(name = "follower", joinColumns = @JoinColumn( name = "user_id", referencedColumnName = "id"), inverseJoinColumns = @JoinColumn( name = "follower_id", referencedColumnName = "id")) private List<User> followers; @ManyToMany(mappedBy = "followers") private List<User> following; // other getters and setters public List<User> getFollowers() { return this.followers; } public List<User> getFollowing() { return this.following; } } El método getFollowers() parece funcionar bien, pero cuando se llama a getFollowing() recibo un montón de spam de consola que culmina en una StackOverflowException:
com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion (StackOverflowError) (through reference chain: org.eclipse.persistence.indirection.IndirectList[0]- >org.myproject.model.User["followers"]- >org.eclipse.persistence.indirection.IndirectList[0]- >org.myproject.model.User["following"]- ... at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase .serializeFields(BeanSerializerBase.java:518) at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize (BeanSerializer.java:117) at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer .serializeContents(IndexedListSerializer.java:94) at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer .serializeContents(IndexedListSerializer.java:21) ...Avíseme si debo proporcionar más del seguimiento de la pila. ¿Alguna pista?
Cada vez que tiene @OneToMany (una colección), debe agregarle @JsonIgnore o, de lo contrario, provocará un bucle infinito que dará como resultado una excepción de desbordamiento de pila porque sigue buscando entre el padre (el lado) y el hijo ( el lado de muchos) Para obtener más información sobre cómo lidiar con este tipo de problemas, consulte este excelente artículo http://www.baeldung.com/jackson-bidireccional-relationships-and-infinite-recursion
Probé todo lo que encontré en la web y no funcionó. Ninguno de cualquier anotación. Pero encontré una solución después de una gran pelea con este problema.
El primer punto que debe agregar a ambas entidades (no a la relacional) es esta anotación:
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler", "relationClass"}) public class YourClass { ... }Donde "relationClass" es el nombre de la Lista/Conjunto de su clase para las relaciones:
Por ejemplo:
@OneToMany(mappedBy = "yourClass", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true) private Set<RelationClass> relationClass;También debe especificar "hibernateLazyInitializer", "handler" en la anotación o causará un problema de serialización.
Después de eso, si ve la tabla que define la tabla de relaciones y verá filas allí, y en su respuesta JSON ya no habrá ningún bucle. Entonces, creo que la mejor solución también es crear un repositorio para la tabla de relaciones y acceder a los datos desde allí.
¡Espero que ayude a alguien!
Creo que el problema en las respuestas anteriores es el paquete de la anotación. En el artículo http://www.baeldung.com/jackson-bidireccional-relationships-and-infinite-recursion @JsonManagedReference y @JsonBackReference funcionan bien.
Pero el paquete debe ser com.fasterxml.jackson.annotation.
A veces, se pueden importar otros paquetes y no resuelven el problema.
además de agregar
import com.fasterxml.jackson.annotation.JsonIdentityInfo; @JsonIdentityInfo( generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")antes de que la definición de clase del modelo funcione bien.