Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring JPA bi-directional cannot evaluate toString

I have resolved JSON recursive loop with @JsonIdentityInfothrough to Baeldung's blog1 (Thanks)

But now, another error occurs :

Method threw 'java.lang.StackOverflowError' exception. Cannot evaluate com.mezoo.tdc.model.Payment.toString()

Here my Registration object :

    @Entity
    @Table(name="Registration")
    @JsonIdentityInfo( generator = ObjectIdGenerators.PropertyGenerator.class, property = "uuid")
    public class Registration implements Serializable {

       /*some private variables..*/

      // Bidirectional relationship
      @OneToMany(mappedBy="registration", cascade = {CascadeType.PERSIST, CascadeType.REMOVE, CascadeType.MERGE}, fetch = FetchType.LAZY)
      private List<Payment> payment;

                @Override
      public String toString() {
         return MoreObjects.toStringHelper(this)
            .add("payment", payment)
            .toString();
         }
    }

Now, Payment object :

    @Entity
    @Table(name="Payment")
    @JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "uuid")
    public class Payment implements Serializable {
       @ManyToOne
       @JoinColumn(name = "registration")
       private Registration registration;

       @Override
       public String toString() {
       return MoreObjects.toStringHelper(this)
            .add("registration", registration)
            .toString();
       }
    }

This is, what I see in debugger :

debug screenshot

Please, what is wrong and why ?

like image 679
Mezoo Avatar asked Oct 26 '16 15:10

Mezoo


3 Answers

Remove toString method.

In case you are using Lombok:

Check you Entity/DAO class you might be using @Data annotation from lombok which by default includes getter and setters. Change it to @Getters and @Setter in case you need those and remove @Data annotation.

like image 50
Rishabh Agarwal Avatar answered Nov 15 '22 08:11

Rishabh Agarwal


Well, my guess is that Registration.toString() prints the string representation of each payment in the list, and since Payment.toString() includes the string representation of Registration, Registration.toString() is called again, which in turn calls Payment.toString() again, and so on.

Try to return an empty string in Payment.toString() to see if the problem goes away.

like image 30
crizzis Avatar answered Nov 15 '22 08:11

crizzis


in your Registration.toString() you are calling a Payment.toString() and on your Payment.toString() you are calling Registration.toString()

You have created a loop in toString

  @Override
  public String toString() {
     return MoreObjects.toStringHelper(this)
        .add("payment", payment) //<----------- REMOVE THIS
        .toString();
  }

or

   @Override
   public String toString() {
   return MoreObjects.toStringHelper(this)
        .add("registration", registration) //<----------- REMOVE THIS
        .toString();
   }

Or better... remove both

like image 22
ValerioMC Avatar answered Nov 15 '22 09:11

ValerioMC