0

I am getting infinite recursion below error.

Resolved [org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: Infinite recursion (StackOverflowError); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion (StackOverflowError) (through reference chain: org.hibernate.collection.internal.PersistentBag[0]->com.dms.bean.DMSDocumentClass$HibernateProxy$u3IXr3xN["groups"]->org.hibernate.collection.internal.PersistentBag[0]->com.dms.bean.DMSGroupBean["docClasses"]->org.hibernate.collection.internal.PersistentBag[0]->com.dms.bean.DMSDocumentClass$HibernateProxy$u3IXr3xN["groups"]->org.hibernate.collection.internal.PersistentBag[0]->com.dms.bean.DMSGroupBean["docClasses"]->org.hibernate.collection.internal.PersistentBag[0]->com.dms.bean.DMSDocumentClass$HibernateProxy$u3IXr3xN["groups"]->org.hibernate.collection.internal.PersistentBag[0]->com.dms.bean.DMSGroupBean["docClasses"]->org.hibernate.collection.internal.PersistentBag[0]->com.dms.bean.DMSDocumentClass$HibernateProxy$u3IXr3xN["groups"]->org.hibernate.collection.internal.PersistentBag[0]->com.dms.bean.DMSGroupBean["docClasses"]->org.hibernate.collection.internal.PersistentBag[0]->com.dms.bean.DMSDocumentClass$HibernateProxy$u3IXr3xN["groups"]->org.hibernate.collection.internal.PersistentBag[0]->com.dms.bean.DMSGroupBean["docClasses"]->org.hibernate.collection.internal.PersistentBag[0]->com.dms.bean.DMSDocumentClass$HibernateProxy$u3IXr3xN["groups"]->org.hibernate.collection.internal.PersistentBag[0]->com.dms.bean.DMSGroupBean["docClasses"]->org.hibernate.collection.internal.PersistentBag[0]->com.dms.bean.DMSDocumentClass$HibernateProxy$u3IXr3xN["groups"]->org.hibernate.collection.internal.PersistentBag[0]->com.dms.bean.DMSGroupBean["docClasses"]]

Below is my code

    @Entity
    @Table(name="DMS_Document_Class")
    public class DMSDocumentClass {

        @Id
        @GeneratedValue(strategy=GenerationType.AUTO)
        @Column(name="DocumentClass_Index_ID")
        private long docClassindexID;


        @ManyToMany(fetch = FetchType.LAZY)
        @JoinTable(name = "DOCCLASS_GROUP", 
        joinColumns = {@JoinColumn(referencedColumnName ="DocumentClass_Index_ID")}, inverseJoinColumns = {@JoinColumn(referencedColumnName="groupID")})
        private List<DMSGroupBean> groups;


        @Column(name="Document_Class_Name")
        private String documentClassName;

        @Column(name="Document_Priority")
        private int documentPriority;

        @Column(name="createdDate")
        private Date createdDate;

        @Column(name="createdBy")
        private String createdBy;

another class

    @Entity
    @Table(name="DMS_Group", indexes= @Index(columnList="groupName"),
                uniqueConstraints={@UniqueConstraint(columnNames={"groupName"})})
    public class DMSGroupBean {

        @Id
        @GeneratedValue(strategy=GenerationType.AUTO)
        @Column(name="groupID")
        private long groupID;

        @Column(name="groupName")
        private String groupName;

        @Column(name="createDate")
        private Date createDate;

        @ManyToMany(mappedBy = "groups",fetch = FetchType.LAZY)
        private List<DMSUser> users;

        @ManyToMany(mappedBy = "groups",fetch = FetchType.LAZY)
        private List<DMSDocumentClass> docClasses;

        @Transient
        private String status;

I am unable to understand why I am getting this error while getting this value on UI.

    @Transactional
        public HashMap<String, Object> getDocListByFolderID(@NonNull long folderID, HttpSession session) {



            DMSFolder currentFolder = folderRepo.findById(folderID).get();

            List<DMSDocument> documents =  documentRepository.findByDocumentFolderID(folderID);

            List<DMSFolder> fetchedSubfolders = folderRepo.findByParentFolderID(folderID);

            //Allow those folder which has rights for this user
            DMSUser userInfo = (DMSUser) session.getAttribute("userinfo");
            List<DMSGroupBean> groups = userInfo.getGroups();//userInfo.getGroupRights();

            List<DMSFolder> finalSubfolders = fetchFinalSubFolders(groups, fetchedSubfolders);

            DMSFolder parentFolder = null;
            if(currentFolder.getParentFolderID() != 0) {
                parentFolder = folderRepo.findById(currentFolder.getParentFolderID()).get();
            }


            HashMap<String, Object> docList = new HashMap<String, Object>();

            docList.put("currentFolder", currentFolder);
            docList.put("documents", documents);
            docList.put("subfolders", finalSubfolders);
            docList.put("parentFolder", parentFolder);

            return docList;
        }
SternK
  • 11,649
  • 22
  • 32
  • 46
  • 1
    Does this answer your question? [Infinite Recursion with Jackson JSON and Hibernate JPA issue](https://stackoverflow.com/questions/3325387/infinite-recursion-with-jackson-json-and-hibernate-jpa-issue) – SternK Mar 13 '20 at 14:30

2 Answers2

1

You get this StackOverflowException as you have a bi-directional relationship of your JPA entities. When Jackson tries to deserialize it, it follows your object graph which never ends as DMSGroupBean and DMSDocumentClass are referencing itself.

Consider using @JsonIgnore on one site of the relationsship like:

@Entity
@Table(name="DMS_Group", indexes= @Index(columnList="groupName"),
            uniqueConstraints={@UniqueConstraint(columnNames={"groupName"})})
public class DMSGroupBean {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    @Column(name="groupID")
    private long groupID;

    @Column(name="groupName")
    private String groupName;

    @Column(name="createDate")
    private Date createDate;

    @ManyToMany(mappedBy = "groups",fetch = FetchType.LAZY)
    private List<DMSUser> users;

    @ManyToMany(mappedBy = "groups",fetch = FetchType.LAZY)
    @JsonIgnore // here
    private List<DMSDocumentClass> docClasses;

    @Transient
    private String status;

}
rieckpil
  • 10,470
  • 3
  • 32
  • 56
1

As already stated, it's the bi-directional mapping that's causing the issue. JsonIgnore will solve your issue, however, I would recommend that you use JsonManagedReference and JsonBackReference. The difference being that JsonIgnore will serialize the field as null, whereas the JsonBackReference will serialize the collection with its Ids (via the JsonIdentityInfo annotation applied to the class).

 @Entity
@Table(name="DMS_Group", indexes= @Index(columnList="groupName"),
            uniqueConstraints={@UniqueConstraint(columnNames={"groupName"})})
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class,property = "groupID")
public class DMSGroupBean {

   @ManyToMany(mappedBy = "groups",fetch = FetchType.LAZY)
   @JsonManageReference
   private List<DMSDocumentClass> docClasses;

and

@Entity
@Table(name="DMS_Document_Class")
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class,property = "docClassindexID")
public class DMSDocumentClass {

    @ManyToMany(fetch = FetchType.LAZY)
    @JoinTable(name = "DOCCLASS_GROUP", 
    joinColumns = {@JoinColumn(referencedColumnName ="DocumentClass_Index_ID")}, inverseJoinColumns = {@JoinColumn(referencedColumnName="groupID")})
    @JsonBackReference
    private List<DMSGroupBean> groups;
lane.maxwell
  • 5,002
  • 1
  • 20
  • 30