Lombok - java.lang.StackOverflowError: null для метода toString - PullRequest
0 голосов
/ 12 февраля 2019

У меня есть два класса Product и Categorie.Когда я хочу изменить список продуктов в категории с помощью 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());
            });

        };
    }

Может у кого-нибудь есть идея, чтобы решить эту проблемувопрос?Спасибо.

Ответы [ 2 ]

0 голосов
/ 12 февраля 2019

У вас есть циклическая ссылка в методе toString, сгенерированном Lombok.

  • Product ссылается на Categorie на toString, который ссылается на Product, и такна

Вы можете использовать свойство exclude @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 здесь и здесь

0 голосов
/ 12 февраля 2019

Я предполагаю, что аннотация @ToString сообщает некоторому инструменту, который вы используете (Lombok?), Для генерации метода toString, который печатает значения всех полей.Каждый из классов ссылается на другой: у продукта есть категория, а у категории есть список экземпляров продукта.Поэтому, когда реализация toString печатает Категорию, она вызывает toString для каждого Продукта, которая затем вызывает toString для своей Категории и т. Д. Поскольку Продукт, вероятно, ссылается на Категорию, которая включает этот Продукт в свой список продуктов, вызовы toString возвращаются назад и вперед до тех пор, покастек переполняется.Решение состоит в том, чтобы избежать печати категорий, продуктов или Product.categorie из метода toString.Если вы используете Lombok, попробуйте пометить Category.products с помощью @ToString.Exclude.

...