【问题标题】:Lombok - java.lang.StackOverflowError: null on toString methodLombok - java.lang.StackOverflowError:toString 方法为空
【发布时间】:2019-07-06 07:34:11
【问题描述】:

我有两个课程ProductCategorie。当我想修改categoryRepository.save(c1) 类别中的产品列表时,如下代码所示,出现此错误:

 java.lang.StackOverflowError: null
    at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:449) ~[na:1.8.0_191]
        at java.lang.StringBuilder.append(StringBuilder.java:136) ~[na:1.8.0_191]
        at org.sid.entities.Product.toString(Product.java:12) ~[classes/:na]
        at java.lang.String.valueOf(String.java:2994) ~[na:1.8.0_191]
        at java.lang.StringBuilder.append(StringBuilder.java:131) ~[na:1.8.0_191]
        at java.util.AbstractCollection.toString(AbstractCollection.java:462) ~[na:1.8.0_191]
        at java.lang.String.valueOf(String.java:2994) ~[na:1.8.0_191]
        at java.lang.StringBuilder.append(StringBuilder.java:131) ~[na:1.8.0_191]
        at org.sid.entities.Categorie.toString(Categorie.java:15) ~[classes/:na]
        at java.lang.String.valueOf(String.java:2994) ~[na:1.8.0_191]

@Document
@Data @AllArgsConstructor @NoArgsConstructor @ToString
public class Categorie {
    @Id
    private String id;
    private String name;
    @DBRef
    @JsonIgnore
    private Collection<Product> products=new ArrayList<>();

@Document
@Data @AllArgsConstructor @NoArgsConstructor @ToString
public class Product {
    @Id
    private String id;
    private String name;
    private double price;
    @DBRef
    private Categorie categorie;

@Bean
    CommandLineRunner start(CategoryRepository categoryRepository, ProductRepository productRepository){

        return args -> {
            categoryRepository.deleteAll();
            Stream.of("c1 Ordinateur","c2 Imprimente").forEach(c->{
                categoryRepository.save(new Categorie(c.split(" ")[0],c.split(" ")[1],new ArrayList<>()));
            });
            categoryRepository.findAll().forEach(System.out::println);

            productRepository.deleteAll();
            Categorie c1=categoryRepository.findById("c1").get();
            Stream.of("P1","P2","P3","P4").forEach(name->{
               Product p= productRepository.save(new Product(null,name,Math.random()*1000,c1));
               c1.getProducts().add(p);
               categoryRepository.save(c1);
            });

productRepository.findAll().forEach(p->{
                System.out.println(p.toString());
            });

        };
    }

任何人都有解决这个问题的想法吗?谢谢。

【问题讨论】:

  • 看起来您的 toString() 类别和/或产品方法中有一个循环。

标签: java mongodb spring-boot jakarta-ee lombok


【解决方案1】:

您在 Lombok 生成的 toString 方法中有一个循环引用。

  • ProducttoString 上引用 Categorie,而 toString 又在引用 Product,依此类推

您可以使用排除属性@ToString,但它很快就会被弃用,因此请使用@ToString.Exclude

@Document
@Data @AllArgsConstructor @NoArgsConstructor @ToString
public class Product {
  ...

  @ToString.Exclude
  private Categorie categorie;

  ...
}

@Document
@Data @AllArgsConstructor @NoArgsConstructor @ToString
public class Categorie {
  ...

  @ToString.Exclude
  private Collection<Product> products=new ArrayList<>();

  ...
}

Lombok 参考 herehere

【讨论】:

  • 谢谢大家的帮助。
  • 这有帮助,但我无法了解上下文。你能详细说明一下吗?
【解决方案2】:

我假设 @ToString 注释告诉您正在使用的某个工具(Lombok?)生成一个 toString 方法,该方法打印所有字段的值。每个类都相互引用:Product 有一个 Categorie,Categorie 有一个 Product 实例列表。因此,当 toString 实现打印一个类别时,它会在每个 Product 上调用 toString,然后在其类别上调用 toString,等等。由于 Product 可能是指在其产品列表中包含该产品的类别,因此 toString 调用来回反弹,直到堆栈溢出。解决方案是避免从 toString 方法打印 Categorie,products 或 Product.categorie。如果您使用的是 Lombok,请尝试使用 @ToString.Exclude 注释 Categorie.products。

【讨论】:

    【解决方案3】:

    我在 Spring JPA 实现中遇到了类似的问题,并且实体被 Lombok @Data 注释,它同时产生 @ToString、@EqualsAndHashCode、@Getter / @Setter 和 @RequiredArgsConstructor。但是,@ToString、@EqualsAndHashCode 注释生成的代码具有实体的所有属性,包括通常引用其他实体和其他 一对一 关系实体的 集合。这会导致循环引用,也会导致加载惰性集合(JPA 默认以惰性方式加载一对多和多对多)。

    添加@ToString.Exclude@EqualsAndHashCode.Exclude 会导致代码繁琐,强烈建议避免在JPA 实体上使用@Data 或@ToString、@EqualsAndHashCode。最好使用 IDE 生成 toString、equals、hashCode 并在使用前验证它们(即非 null 与 null 字段等)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-07-16
      • 2016-05-24
      • 2021-06-21
      • 1970-01-01
      • 1970-01-01
      • 2021-05-21
      • 2018-05-06
      • 2019-09-14
      相关资源
      最近更新 更多