Lombok - java.lang.StackOverflowError: null on toString method
Lombok - java.lang.StackOverflowError: null on toString method
我有两个 类 Product
和 Categorie
。当我想修改带有 categoryRepository.save(c1)
的类别中的产品列表时,如下面的代码所示,出现此错误:
java.lang.WhosebugError: 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
注释告诉您正在使用的某个工具(Lombok?)生成一个 toString 方法来打印所有字段的值。每个 类 都引用另一个:Product 有一个 Categorie,Categorie 有一个 Product 实例列表。因此,当 toString 实现打印一个 Categorie 时,它会在每个 Product 上调用 toString,然后在其 Categorie 上调用 toString,等等。由于 Product 可能指的是在其产品列表中包含该 Product 的 Categorie,因此 toString 调用来回反弹直到堆栈溢出。解决方案是避免从 toString 方法打印 Categorie,products 或 Product.categorie。如果您使用的是 Lombok,请尝试使用 @ToString.Exclude
.
注释 Categorie.products
您在 Lombok 生成的 toString
方法中有一个循环引用。
Product
在 toString
上引用 Categorie
,后者引用 Product
,依此类推
您可以使用排除 a 属性 @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<>();
...
}
我在 Spring JPA 实现中遇到了类似的问题,实体使用 Lombok @Data 注释,它生成 @ToString、@EqualsAndHashCode、@Getter / @Setter 和 @RequiredArgsConstructor一起。然而,@ToString、@EqualsAndHashCode 注释生成的代码具有实体的所有属性,包括通常引用其他实体和其他 一对一 关系的 集合 实体。这会导致循环引用,还会导致延迟集合的加载(JPA 默认以延迟方式加载一对多和多对多)。
添加@ToString.Exclude
或@EqualsAndHashCode.Exclude
会导致代码繁琐,强烈建议避免在JPA 实体上使用@Data 或@ToString、@EqualsAndHashCode。最好使用 IDE 生成 toString、equals、hashCode 并在使用前验证它们(即非空字段与空字段等)。
我有两个 类 Product
和 Categorie
。当我想修改带有 categoryRepository.save(c1)
的类别中的产品列表时,如下面的代码所示,出现此错误:
java.lang.WhosebugError: 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
注释告诉您正在使用的某个工具(Lombok?)生成一个 toString 方法来打印所有字段的值。每个 类 都引用另一个:Product 有一个 Categorie,Categorie 有一个 Product 实例列表。因此,当 toString 实现打印一个 Categorie 时,它会在每个 Product 上调用 toString,然后在其 Categorie 上调用 toString,等等。由于 Product 可能指的是在其产品列表中包含该 Product 的 Categorie,因此 toString 调用来回反弹直到堆栈溢出。解决方案是避免从 toString 方法打印 Categorie,products 或 Product.categorie。如果您使用的是 Lombok,请尝试使用 @ToString.Exclude
.
您在 Lombok 生成的 toString
方法中有一个循环引用。
Product
在toString
上引用Categorie
,后者引用Product
,依此类推
您可以使用排除 a 属性 @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<>();
...
}
我在 Spring JPA 实现中遇到了类似的问题,实体使用 Lombok @Data 注释,它生成 @ToString、@EqualsAndHashCode、@Getter / @Setter 和 @RequiredArgsConstructor一起。然而,@ToString、@EqualsAndHashCode 注释生成的代码具有实体的所有属性,包括通常引用其他实体和其他 一对一 关系的 集合 实体。这会导致循环引用,还会导致延迟集合的加载(JPA 默认以延迟方式加载一对多和多对多)。
添加@ToString.Exclude
或@EqualsAndHashCode.Exclude
会导致代码繁琐,强烈建议避免在JPA 实体上使用@Data 或@ToString、@EqualsAndHashCode。最好使用 IDE 生成 toString、equals、hashCode 并在使用前验证它们(即非空字段与空字段等)。