Spring JPA双向关联无法评估toString方法。

42
我已经通过Baeldung博客1解决了JSON递归循环问题,使用了@JsonIdentityInfo。谢谢。
但是现在,又出现了另一个错误:
Method threw 'java.lang.StackOverflowError' exception. Cannot evaluate com.mezoo.tdc.model.Payment.toString()

这是我的注册对象:

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

现在,支付对象:
    @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();
       }
    }

这是我在调试器中看到的:

debug screenshot

请问,出了什么问题?为什么?


这只是一个IDE的错误(警告)。 - Mezoo
4个回答

92

移除toString方法。

如果您使用Lombok:

检查您的实体/DAO类,您可能正在使用来自Lombok@Data注释,默认情况下包括getter和setter。 如果需要这些,请将其更改为@Getters@Setter删除@Data注释。


3
我曾经使用了@Data注释,现在我将其删除并改为使用_@Getters_和_@Setters_,问题得到解决。谢谢。 - Amir
2
正是我在寻找的。 - logbasex
13
不要改变 @Data 注解,你可以用 @ToString.Exclude 替换导致错误的区域。 - fatih
@Fatih 另一个很棒的选择。 - Rishabh Agarwal
那就是答案! - Erick Audet
你还没有解释为什么 #toString 会导致异常。 - emeraldhieu

28

我的猜测是Registration.toString()会打印列表中每个支付的字符串表示形式,而由于Payment.toString()包括Registration的字符串表示形式,因此再次调用Registration.toString(),这反过来又调用了Payment.toString(),如此往复。

尝试在Payment.toString()中返回一个空字符串,看看问题是否解决。


1
返回一个空字符串解决了问题。但这意味着toString方法现在是多余的。是否可以通过更好的JPA映射配置来解决这个问题?我正在使用Lombok @Data注释toString方法,这可能会导致问题吗? - Benjamin Slabbert
2
如果我理解正确的话,@Data 暗示了 @ToString,它会获取类的所有字段并在 toString() 中打印它们。所以是的,@Data 很可能是这里的问题。至于映射,除非你觉得不需要双向关联,否则没有什么可以改进的,它是完全有效的。问题出在生成 toString() 的方式上。 - crizzis
1
Lombok支持排除单个字段不被添加到自动生成的toString()方法中。在您想要从自动生成的toString()方法中排除的字段上添加@ToString.Exclude注解即可。 - Przemek
我知道这已经过时了,但是我在一个仅具有多个OneToOne关系的对象上进行存储库查询。解决方案是消除@Data并仅使用Setters Getters RequiredArgsConstructor。希望对你有所帮助。 - cp.

4
在您的 `Registration.toString()` 中,您调用了 `Payment.toString()`,而在 `Payment.toString()` 中,您又调用了 `Registration.toString()`。
您在 `toString` 方法中创建了一个循环。
  @Override
  public String toString() {
     return MoreObjects.toStringHelper(this)
        .add("payment", payment) //<----------- REMOVE THIS
        .toString();
  }

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

或者更好的做法是将两者都删除。

1
如果您正在使用 lombok,则可以按照以下方式从 toString() 中排除映射:
@Entity
    @Table(name="Registration")
    @JsonIdentityInfo( generator = ObjectIdGenerators.PropertyGenerator.class, property = "uuid")
@ToString(exclude = {"payment"})
    public class Registration implements Serializable {
..
..
..Your code
}

同样适用于付款实体。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接