4
votes

I am trying some hibernate.The following is the pojo I am using,

@Entity
@Table(name = "person")
public class Person {

    @Id
    @GeneratedValue
    @Column(name = "person_id")
    private long person_id;


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


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


    @OneToMany(fetch = FetchType.EAGER, mappedBy = "person" )
    private Set<Phone> phone;

        //Getters ande Setters

}


@Entity
@Table(name = "phone")
public class Phone{

    @Id
    @GeneratedValue
    @Column(name = "phone_id")
    private long phone_id;


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

         @ManyToOne(cascade = CascadeType.MERGE,fetch = FetchType.EAGER)
    @JoinColumn(name = "person_id")
    private Person person ;

        //Getters ande Setters


}

What I want is when I fetch a record from person and need corresponding all phone details. (Like Select * from person) I have around 1360 data in person and nearly double in phone. But for some reason error is thrown. I am not able to see full error stack . Below is the error I am getting.

at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:505) ~[jackson-databind-2.4.6.jar:2.4.6] at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:639) ~[jackson-databind-2.4.6.jar:2.4.6] at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:152) ~[jackson-databind-2.4.6.jar:2.4.6] at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:505) ~[jackson-databind-2.4.6.jar:2.4.6] at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:639) ~[jackson-databind-2.4.6.jar:2.4.6] at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:152) ~[jackson-databind-2.4.6.jar:2.4.6] at com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serializeContents(CollectionSerializer.java:117) ~[jackson-databind-2.4.6.jar:2.4.6] at com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serializeContents(CollectionSerializer.java:23) ~[jackson-databind-2.4.6.jar:2.4.6] at .....

I was not able to post all error that I got

3
this part of error log is useless. We need first part of error log to help - Yusuf K.
It seems stackoverflow exception occured when serializing your objects, person to phone and phone to person relation causes endless loop - Yusuf K.
Yes even I thought the same. But why it happened. Is my approach method correct ? - Learner
İt is not about hibernate, its root is jackson. - Yusuf K.
So what Can i do now? - Learner

3 Answers

10
votes

Using JsonManagedReference and JsonBackReference annotations may solve your problem.

While jackson trying to convert objects to json, visits objects and their attributes. So if objects have bi-directional relations, for jackson we need to think about cyclic dependencies. Jackson starts serialize person and see the phone list and take a phone from list and start serialize phone and sees person in phone and take person from phone and start serilize it bla bla bla so this is an endless loop. If jackson sees these annotations, stops and breaks the loop.

Give it a try as below code;

@Entity
@Table(name = "person")
public class Person {

    @Id
    @GeneratedValue
    @Column(name = "person_id")
    private long person_id;    

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

    @Column(name = "Address")
    private String Address;
    @JsonManagedReference
    @OneToMany(fetch = FetchType.EAGER, mappedBy = "person" )
    private Set<Phone> phone;

    // Getters and Setters

}

@Entity
@Table(name = "phone")
public class Phone{

    @Id
    @GeneratedValue
    @Column(name = "phone_id")
    private long phone_id;

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

    @ManyToOne(cascade = CascadeType.MERGE,fetch = FetchType.EAGER)
    @JoinColumn(name = "person_id")
    @JsonBackReference
    private Person person;

    // Getters and Setters

}
1
votes

You can alternatively use @JsonIdentityInfo on classes

@Entity
@JsonIdentityInfo(generator=ObjectIdGenerators.IntSequenceGenerator.class, property="@id")
@Table(name = "phone")
public class Phone {

}

@Entity
@JsonIdentityInfo(generator=ObjectIdGenerators.IntSequenceGenerator.class, property="@id")
@Table(name = "person")
public class Person {

}
1
votes

I was also getting the same error. Using @JsonBackReference and @JsonManagedReference was still giving me error so I used @JsonIdentityInfo and it worked like a charm.

Below are my classes :-

BookModel :

@Data
@Entity
@Table(name = "book")
@JsonIdentityInfo(generator=ObjectIdGenerators.IntSequenceGenerator.class, property="bookId")
public class BookModel implements Serializable{

    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "book_id")
    private int bookId;
    
    
    @Column(name="book_name")
    private String bookName;
    
    @Column(name="book_author")
    private String bookAuthor;
    
    @Column(name="book_publish_date")
    private Date bookPublishDate;
    
    @Column(name="book_price")
    private double bookPrice;
    
    @OneToMany(mappedBy = "book_model")
    List<BookImagesModel>  bookImagesModels;
    //getters and setters
    //default constructor

}

BookImagesModel :

@Data
@Entity
@Table(name = "book_images")
@JsonIdentityInfo(generator=ObjectIdGenerators.IntSequenceGenerator.class, property="imageId")
public class BookImagesModel implements Serializable {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "image_id")
    private long imageId;

    @ManyToOne
    @JoinColumn(name = "book_id")
    private BookModel book_model;

    
    @Column(name = "image_path")
    private String imagePath;

//getters and setters
        //default constructor

}

I used Mysql8 database with spring boot.

Output after running: