问题
I have two classes Product
and Categorie
. When I would like to modify the list of products in categorie with categoryRepository.save(c1)
as shown in the code below, this error occurs:
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());
});
};
}
Can anyone have an idea to solve this issue? Thanks.
回答1:
You are having a circular reference in the toString
method generated by Lombok.
Product
is referencingCategorie
ontoString
, which is referencingProduct
, and so on
You could use the exclude a property @ToString
, but it is going to be deprecated soon, so use the @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 refs here and here
回答2:
I assume the @ToString
annotation tells some tool you’re using (Lombok?) to generate a toString method that prints the values of all the fields. Each of the classes refer to the other: Product has a Categorie and Categorie has a list of Product instances. So when the toString implementation prints a Categorie, it calls toString on each Product, which then calls toString on its Categorie, etc. Since Product presumably refers to a Categorie which includes that Product in its products list, the toString calls bounce back and forth until the stack overflows. The solution is to avoid printing either Categorie,products or Product.categorie from the toString method. If you’re using Lombok, try annotating Categorie.products with @ToString.Exclude
.
来源:https://stackoverflow.com/questions/54653734/lombok-java-lang-stackoverflowerror-null-on-tostring-method