Jackson JSON 和 Hibernate JPA 的无限递归
Infinite Recursion with Jackson JSON and Hibernate JPA
我想通过 OnetoMany
和 ManytoOne
双向关系映射将一些数据存储到数据库中。虽然在邮递员中请求持久数据得到无限行响应。
下面是我的代码:
实体
public class Author {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer author_id;
private String name;
private String language;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "author")
private Set<Book> book;
// getter setter
}
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String title;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "author_id")
private Author author;
// getter setter
}
服务
@Override
public Author insertAuthor(Author author) {
Set<Book> bookList = new HashSet<>();
Book book = new Book();
book.setTitle(book.getTitle());
bookList.add(book);
book.setAuthor(author);
author.setBook(bookList);
return authorRepo.save(author);
}
控制器
@RestController
public class PojoController {
@Autowired
private PojoService pojoService;
@RequestMapping(value="/book", method = RequestMethod.POST)
public Author addBookCourse(@RequestBody Author author) {
return this.pojoService.insertAuthor(author);
}
}
请求
{
"language": "english",
"name": "Banjamin franklin",
"book": [{
"title": "Theory Of Everything"
},
{
"title": "A Brief Story Of Time"
}]
}
输出
{
"author_id": 1,
"name": "Banjamin franklin",
"language": "english",
"book": [
{
"id": 1,
"title": null,
"author": {
"author_id": 1,
"name": "Banjamin franklin",
"language": "english",
"book": [
{
"id": 1,
"title": null,
"author": {
"author_id": 1,
"name": "Banjamin franklin",
"language": "english",
"book": [
{
"id": 1,
"title": null,
"author": {
"author_id": 1,
"name": "Banjamin franklin",
"language": "english",
"book": [
{
"id": 1,
"title": null,
more 7460 line
.......
.......
.......
{
"timestamp": "2021-11-30T10:25:03.957+00:00",
"status": 200,
"error": "OK",
"trace": "org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: Infinite recursion (WhosebugError); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion (WhosebugError) (through reference chain: com.rest.RestApiPojo.Entity.Author[\"book\"]->org.hibernate.collection.internal.PersistentSet[0]->com.rest.RestApiPojo.Entity.Book[\"author\"]->com.rest.RestApiPojo.Entity.Author[\"book\"]->org.hibernate.collection.internal.PersistentSet[0]->com.rest.RestApiPojo.Entity.Book[\"author\"]
}
你需要使用@JsonManagedReference
和@JsonBackReference
来让Jackson更好地处理Author
和Book
之间的关系:
public class Author {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer author_id;
private String name;
private String language;
@JsonManagedReference
@OneToMany(cascade = CascadeType.ALL, mappedBy = "author")
private Set<Book> book;
// getter setter
}
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String title;
@JsonBackReference
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "author_id")
private Author author;
// getter setter
}
您还有其他选择(例如使用 @JsonIdentityInfo
)来处理这个无限递归问题,但这是最常见的解决方案。您可以在以下在线资源 https://www.baeldung.com/jackson-bidirectional-relationships-and-infinite-recursion.
中查看所有其他可能的方法
此外,在您的服务中,您正在创建一个全新的 Book
并将其标题设置为 book.setTitle(book.getTitle());
,这基本上什么都不做。事实上,你甚至不需要做你在那里做的大部分事情,因为 Book
个实例已经在 Author
中,你只需要在每个 Book
上设置 Author
]实例如下:
@Override
public Author insertAuthor(Author author) {
for (Book book : author.getBook()) {
book.setAuthor(author);
}
return authorRepo.save(author);
}
最后,考虑将Author
中的book
属性改成books
,因为它包含多本书(之后你需要调整你的代码)。
我想通过 OnetoMany
和 ManytoOne
双向关系映射将一些数据存储到数据库中。虽然在邮递员中请求持久数据得到无限行响应。
下面是我的代码:
实体
public class Author {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer author_id;
private String name;
private String language;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "author")
private Set<Book> book;
// getter setter
}
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String title;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "author_id")
private Author author;
// getter setter
}
服务
@Override
public Author insertAuthor(Author author) {
Set<Book> bookList = new HashSet<>();
Book book = new Book();
book.setTitle(book.getTitle());
bookList.add(book);
book.setAuthor(author);
author.setBook(bookList);
return authorRepo.save(author);
}
控制器
@RestController
public class PojoController {
@Autowired
private PojoService pojoService;
@RequestMapping(value="/book", method = RequestMethod.POST)
public Author addBookCourse(@RequestBody Author author) {
return this.pojoService.insertAuthor(author);
}
}
请求
{
"language": "english",
"name": "Banjamin franklin",
"book": [{
"title": "Theory Of Everything"
},
{
"title": "A Brief Story Of Time"
}]
}
输出
{
"author_id": 1,
"name": "Banjamin franklin",
"language": "english",
"book": [
{
"id": 1,
"title": null,
"author": {
"author_id": 1,
"name": "Banjamin franklin",
"language": "english",
"book": [
{
"id": 1,
"title": null,
"author": {
"author_id": 1,
"name": "Banjamin franklin",
"language": "english",
"book": [
{
"id": 1,
"title": null,
"author": {
"author_id": 1,
"name": "Banjamin franklin",
"language": "english",
"book": [
{
"id": 1,
"title": null,
more 7460 line
.......
.......
.......
{
"timestamp": "2021-11-30T10:25:03.957+00:00",
"status": 200,
"error": "OK",
"trace": "org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: Infinite recursion (WhosebugError); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion (WhosebugError) (through reference chain: com.rest.RestApiPojo.Entity.Author[\"book\"]->org.hibernate.collection.internal.PersistentSet[0]->com.rest.RestApiPojo.Entity.Book[\"author\"]->com.rest.RestApiPojo.Entity.Author[\"book\"]->org.hibernate.collection.internal.PersistentSet[0]->com.rest.RestApiPojo.Entity.Book[\"author\"]
}
你需要使用@JsonManagedReference
和@JsonBackReference
来让Jackson更好地处理Author
和Book
之间的关系:
public class Author {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer author_id;
private String name;
private String language;
@JsonManagedReference
@OneToMany(cascade = CascadeType.ALL, mappedBy = "author")
private Set<Book> book;
// getter setter
}
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String title;
@JsonBackReference
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "author_id")
private Author author;
// getter setter
}
您还有其他选择(例如使用 @JsonIdentityInfo
)来处理这个无限递归问题,但这是最常见的解决方案。您可以在以下在线资源 https://www.baeldung.com/jackson-bidirectional-relationships-and-infinite-recursion.
此外,在您的服务中,您正在创建一个全新的 Book
并将其标题设置为 book.setTitle(book.getTitle());
,这基本上什么都不做。事实上,你甚至不需要做你在那里做的大部分事情,因为 Book
个实例已经在 Author
中,你只需要在每个 Book
上设置 Author
]实例如下:
@Override
public Author insertAuthor(Author author) {
for (Book book : author.getBook()) {
book.setAuthor(author);
}
return authorRepo.save(author);
}
最后,考虑将Author
中的book
属性改成books
,因为它包含多本书(之后你需要调整你的代码)。