不写JSON:无限递归(StackOverflowError);嵌套异常是 com.fasterxml.jackson.databind.JsonMappingException: 无限递归

not write JSON: Infinite recursion (StackOverflowError); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion

我正在开发 Spring Boot + Data Jpa + Postgres + Swaggerfox 示例。在这个例子中,我遇到了以下错误。

错误:

2019-08-06 20:29:02.449  WARN 24884 --- [nio-8080-exec-1] o.h.e.loading.internal.LoadContexts      : HHH000100: Fail-safe cleanup (collections) : org.hibernate.engine.loading.internal.CollectionLoadContext@4b0cc859<rs=HikariProxyResultSet@1568394184 wrapping org.postgresql.jdbc.PgResultSet@439cca7d>
2019-08-06 20:29:02.449  WARN 24884 --- [nio-8080-exec-1] o.h.e.loading.internal.LoadContexts      : HHH000100: Fail-safe cleanup (collections) : org.hibernate.engine.loading.internal.CollectionLoadContext@2b3b519c<rs=HikariProxyResultSet@1558688075 wrapping org.postgresql.jdbc.PgResultSet@749887a>
2019-08-06 20:29:02.449  WARN 24884 --- [nio-8080-exec-1] o.h.e.loading.internal.LoadContexts      : HHH000100: Fail-safe cleanup (collections) : org.hibernate.engine.loading.internal.CollectionLoadContext@2a2ad6ca<rs=HikariProxyResultSet@1350054348 wrapping org.postgresql.jdbc.PgResultSet@fc02ed0>
2019-08-06 20:29:02.449  WARN 24884 --- [nio-8080-exec-1] o.h.e.loading.internal.LoadContexts      : HHH000100: Fail-safe cleanup (collections) : org.hibernate.engine.loading.internal.CollectionLoadContext@7e063905<rs=HikariProxyResultSet@324722253 wrapping org.postgresql.jdbc.PgResultSet@35c774e7>
2019-08-06 20:29:02.449  WARN 24884 --- [nio-8080-exec-1] o.h.e.loading.internal.LoadContexts      : HHH000100: Fail-safe cleanup (collections) : org.hibernate.engine.loading.internal.CollectionLoadContext@49a76813<rs=HikariProxyResultSet@1730994902 wrapping org.postgresql.jdbc.PgResultSet@479f6959>
2019-08-06 20:29:02.449  WARN 24884 --- [nio-8080-exec-1] o.h.e.loading.internal.LoadContexts      : HHH000100: Fail-safe cleanup (collections) : org.hibernate.engine.loading.internal.CollectionLoadContext@89ebebe<rs=HikariProxyResultSet@2103425508 wrapping org.postgresql.jdbc.PgResultSet@6f08306>
2019-08-06 20:29:02.449  WARN 24884 --- [nio-8080-exec-1] o.h.e.loading.internal.LoadContexts      : HHH000100: Fail-safe cleanup (collections) : org.hibernate.engine.loading.internal.CollectionLoadContext@74e5843b<rs=HikariProxyResultSet@1775874661 wrapping org.postgresql.jdbc.PgResultSet@488cfe5f>
2019-08-06 20:29:02.449  WARN 24884 --- [nio-8080-exec-1] o.h.e.loading.internal.LoadContexts      : HHH000100: Fail-safe cleanup (collections) : org.hibernate.engine.loading.internal.CollectionLoadContext@359ac2be<rs=HikariProxyResultSet@60954866 wrapping org.postgresql.jdbc.PgResultSet@37708fb8>
2019-08-06 20:29:02.449  WARN 24884 --- [nio-8080-exec-1] o.h.e.loading.internal.LoadContexts      : HHH000100: Fail-safe cleanup (collections) : org.hibernate.engine.loading.internal.CollectionLoadContext@6fec0131<rs=HikariProxyResultSet@2098642686 wrapping org.postgresql.jdbc.PgResultSet@403d6495>

BaseEntity.java

@Data
@NoArgsConstructor
@AllArgsConstructor
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public class BaseEntity {
    @CreatedDate
    @Column(name = "createdDate", nullable = false, updatable = false)
    private Instant createdDate;

    @LastModifiedDate
    @Column(name = "lastUpdateDate", nullable = false)
    private Instant lastUpdateDate;

    @Column(name = "createUser", nullable = false, length = 50)
    private String createUser;

    @Column(name = "lastUpdateUser", length = 50)
    private String lastUpdateUser;
}

Category.java

@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = true)
@Entity
@Table(name = "category")
public class Category extends BaseEntity implements java.io.Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = IDENTITY)
    @Column(name = "CATEGORY_ID", unique = true, nullable = false)
    private Integer categoryId;

    @Column(name = "NAME", nullable = false, length = 10)
    private String name;

    @Column(name = "[DESC]", nullable = false)
    private String desc;

    @ManyToMany(fetch = FetchType.LAZY, mappedBy = "categories")
    private Set<Stock> stocks = new HashSet<>(0);


    @Builder(builderMethodName = "cBuilder")
    public Category(Integer categoryId, String name, String desc, Set<Stock> stocks,
            Instant createdDate,Instant lastUpdateDate, String createUser, String lastUpdateUser) {
        super(createdDate, lastUpdateDate, createUser, lastUpdateUser);
        this.categoryId = categoryId;
        this.name = name;
        this.desc = desc;
        this.stocks = stocks;
    }   
}

Stock.java

@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = true)
@Entity
@Table(name = "stock", uniqueConstraints = { @UniqueConstraint(columnNames = "STOCK_NAME"),
        @UniqueConstraint(columnNames = "STOCK_CODE") })
public class Stock extends BaseEntity implements java.io.Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = IDENTITY)
    @Column(name = "STOCK_ID", unique = true, nullable = false)
    private Integer stockId;

    @Column(name = "STOCK_CODE", unique = true, nullable = false, length = 10)
    private String stockCode;

    @Column(name = "STOCK_NAME", unique = true, nullable = false, length = 20)
    private String stockName;

    @ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinTable(name = "stock_category", catalog = "mkyongdb", joinColumns = {
            @JoinColumn(name = "STOCK_ID", nullable = false, updatable = false) }, inverseJoinColumns = {
                    @JoinColumn(name = "CATEGORY_ID", nullable = false, updatable = false) })
    private Set<Category> categories = new HashSet<>(0);

    @Builder(builderMethodName = "sBuilder")
    public Stock(Integer stockId, String stockCode, String stockName, Set<Category> categories, Instant createdDate,
            Instant lastUpdateDate, String createUser, String lastUpdateUser) {
        super(createdDate, lastUpdateDate, createUser, lastUpdateUser);
        this.stockId = stockId;
        this.stockCode = stockCode;
        this.stockName = stockName;
        this.categories = categories;
    }
}

启动时:http://localhost:8080/swagger-ui.html#/Category_Management 出现上述错误:

主应用程序

@SpringBootApplication
@EnableJpaAuditing
public class MyExampleApplication implements CommandLineRunner {

    public static void main(String[] args) {
        SpringApplication.run(MyExampleApplication.class, args);
    }

    @Autowired
    private StockRepository stockRepository;
    @Autowired
    private CategoryRepository categoryRepository;

    @Override
    public void run(String... args) throws Exception {
        Stock stock = Stock.sBuilder().stockCode("7052").stockName("PADINI").createUser("John Doe")
                .lastUpdateUser("John Doe").build();

        Category category1 = Category.cBuilder().name("CONSUMER").desc("CONSUMER COMPANY").createUser("John Doe")
                .lastUpdateUser("John Doe").build();

        Category category2 = Category.cBuilder().name("INVESTMENT").desc("INVESTMENT COMPANY").createUser("Neha Parate")
                .lastUpdateUser("Neha Parate").build();

        Set<Category> categories = new HashSet<>();
        categories.add(category1);
        categories.add(category2);

        stock.setCategories(categories);
        stockRepository.save(stock);
    }
}

注意:如果我使用许多块建议的 @JsonIgnore,那么我也会丢失对象关联的实体数据,但我也希望显示所有数据 + 关联的实体数据。

您遇到的问题是循环引用。

@JsonManagedReference@JsonBackReference用于处理循环引用。

@JsonManagedReference 用于目标 POJO 的子引用。

@JsonBackReference用于对应的子class。它被放置在反向引用 属性 上。

Circular Reference