首页 > 解决方案 > Spring JPA 从 JpaRepository 返回无限递归

问题描述

我有一个像这样的控制器类


@Controller
public class ExerciseController {
    private static final Logger logger = LogManager.getLogger(ExerciseController.class);

    private final ExerciseRepository exerciseRepository;

    @Autowired
    public ExerciseController(ExerciseRepository exerciseRepository) {
        this.exerciseRepository = exerciseRepository;
    }
    
    @PostMapping("/exercises")
    public ResponseEntity<Exercise> createExercise(@RequestBody Exercise exercise) {
        Exercise savedExercise = exerciseRepository.save(exercise);
        return new ResponseEntity<Exercise>(savedExercise,HttpStatus.CREATED);
    }

    @RequestMapping("/exercises/{id}")
    public ResponseEntity<Exercise> getExerciseById(@PathVariable int id) {
        Exercise exercise = exerciseRepository.getOne(id);
        return new ResponseEntity<Exercise>(exercise, HttpStatus.OK);
    }
}

链接到这个控制器的存储库是一个简单的 JpaRepository 像这样

package com.company.app.repository;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import com.company.app.model.Exercise;

@Repository
public interface ExerciseRepository extends JpaRepository<Exercise, Integer> {
    Exercise findById(int id);
}

When I try to hit the endpoint associated with /exercises/{id} I get infinite recursion. The Exercise model is set up like so

package com.company.app.model;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinColumns;
import javax.persistence.ManyToOne;
import javax.persistence.MapsId;
import javax.persistence.Table;

import lombok.Data;

@Entity
@Table(name="exercise")
@Data
public class Exercise {
    
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int id;
    
    @MapsId("chapterId")
    @JoinColumns({
        @JoinColumn(name="chapterId", referencedColumnName="id"),
    })
    @ManyToOne
    private Chapter chapter;

    private String exercise;

    private String answer;

    private String question;

    private String a;
    
    private String b;

    private String c;
}

I'd like to know why this is returning infinite recursion? The error that I am receiving is

2021-04-02 19:30:28.120 ERROR 110200 --- [nio-8080-exec-6] s.e.ErrorMvcAutoConfiguration$StaticView : Cannot render error page for request [/exercises/1] and exception [Could not write JSON: Infinite recursion (StackOverflowError); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion (StackOverflowError) (through reference chain: com.company.app.model.Account["user"]->

Chapter implementation

package com.company.app.model;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinColumns;
import javax.persistence.ManyToOne;
import javax.persistence.MapsId;
import javax.persistence.Table;

import lombok.Data;

@Entity
@Table(name="chapter")
@Data
public class Chapter {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int id;
    
    private String title;
    
    @MapsId("bookId")
    @JoinColumns({
        @JoinColumn(name="bookId", referencedColumnName="id"),
    })
    @ManyToOne
    private Book book;

}

标签: springjpa

解决方案


发生这种情况是因为默认情况下为所有字段创建 equals/hashCode/toString 实现的注释,因此您在这些方法之间和@Data之间存在无限循环。ExerciseChapter

我建议您通过添加@EqualsAndHashCode.Excludeand @ToString.Excludeon chapterand字段来排除这些exercise字段。


推荐阅读