Lombok - java.lang.StackOverflowError:toString方法为null

问题描述 投票:0回答:2

我有两个类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());
            });

        };
    }

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

java mongodb spring-boot java-ee lombok
2个回答
3
投票

你在龙目岛生成的toString方法中有一个循环引用。

  • ProductCategorie上引用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<>();

  ...
}

龙目岛引用herehere


2
投票

我假设@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。

© www.soinside.com 2019 - 2024. All rights reserved.