英文:
Spring JPA One To Many Infinite Recursion
问题
以下是您提供的代码的翻译部分:
这是我的 Posts 类
@Data
@Entity
@Table(name = "posts")
@EntityListeners(AuditingEntityListener.class)
public class Posts {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "post_id")
private Long post_id;
@ManyToOne
@JoinColumn(name = "user_id", nullable = false)
private Users user;
@Column(name = "description")
private String description;
@Column(name="images")
private String images;
@Column(name="tags")
private String tags;
@OneToMany(
fetch = FetchType.LAZY,
mappedBy = "post",
cascade = CascadeType.ALL,
orphanRemoval = true
)
@JsonIgnoreProperties(value = { "comments", "hibernateLazyInitializer", "handler" }, allowSetters = true)
//@JsonManagedReference
private List<Comments> comments;
@LastModifiedDate
@Column(name = "last_updated")
private Date lastUpdated;
public void addComments(Comments comment) {
this.comments.add(comment);
}
}
这是我的 PostDTO 类
@Data
public class PostDTO {
private Long post_id;
private UserDTO user;
private String description;
private String images;
private String tags;
private List<CommentsDTO> comments;
private Date lastUpdated;
}
这是我的 Comments 类
@Data
@Entity
@Table(name = "comments")
@EntityListeners(AuditingEntityListener.class)
public class Comments {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name="comment_id")
private Long comment_id;
@OneToOne
@JoinColumn(name = "user_id")
private Users user;
@Column(name = "description")
private String description;
@Column(name="images")
private String images;
@ManyToOne
@JoinColumn(name ="post_id" , nullable = false)
@JsonIgnoreProperties(value = { "post", "hibernateLazyInitializer", "handler" }, allowSetters = true)
//@JsonBackReference
private Posts post;
@Column(name="last_updated")
@LastModifiedDate
private Date lastUpdated;
}
这是我的 CommentsDTO 类
@Data
public class CommentsDTO {
private Long comment_id;
private UserDTO user;
private String description;
private PostDTO post;
private String images;
private Date lastUpdated;
}
这是我的 REST Controller
@GetMapping
public @ResponseBody ResponseEntity<List<PostDTO>> getAll() throws Exception {
return new ResponseEntity<List<PostDTO>>(service.getAll(), HttpStatus.OK);
}
这是我的 service
public List<PostDTO> getAll() throws Exception {
return repo.findAll()
.stream()
.map(this::convert)
.collect(Collectors.toList());
}
private PostDTO convert(Posts e) {
return mapper.map(e, PostDTO.class);
}
希望这对您有所帮助。如果您有任何问题,请随时问我。
英文:
im trying to return to a JPA data (converted to DTO, ofcourse) where it has a @OneToMany
and @ManyToOne
bidirectional relationship. Im currently apply thing fix. The problem is that the output is recusrive. comments has post has comments then has posts (comments -> post -> coments -> so on..).
I only wnat to have something like this
{
"post_id": 1
"user": {
// user data
},
"description": "some description",
"images": "{images,images}",
"tags": "{tags, tags}",
"comments": [
{
//some comments data
},
{
//some comments data
}
]
"lastUpdated": "2020-04-08T14:23:18.000+00:00"
}
Here are my code
This is my Posts.class
@Data
@Entity
@Table(name = "posts")
@EntityListeners(AuditingEntityListener.class)
public class Posts {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "post_id")
private Long post_id;
@ManyToOne
@JoinColumn(name = "user_id", nullable = false)
private Users user;
@Column(name = "description")
private String description;
@Column(name="images")
private String images;
@Column(name="tags")
private String tags;
@OneToMany(
fetch = FetchType.LAZY,
mappedBy = "post",
cascade = CascadeType.ALL,
orphanRemoval = true
)
@JsonIgnoreProperties(value = { "comments" ,"hibernateLazyInitializer", "handler" }, allowSetters = true)
//@JsonManagedReference
private List<Comments> comments;
@LastModifiedDate
@Column(name = "last_updated")
private Date lastUpdated;
public void addComments(Comments comment) {
this.comments.add(comment);
}
}
Here is my PostDTO.class
@Data
public class PostDTO {
private Long post_id;
private UserDTO user;
private String description;
private String images;
private String tags;
private List<CommentsDTO> comments;
private Date lastUpdated;
}
This is my Comments.class
@Data
@Entity
@Table(name = "comments")
@EntityListeners(AuditingEntityListener.class)
public class Comments {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name="comment_id")
private Long comment_id;
@OneToOne
@JoinColumn(name = "user_id")
private Users user;
@Column(name = "description")
private String description;
@Column(name="images")
private String images;
@ManyToOne
@JoinColumn(name ="post_id" , nullable = false)
@JsonIgnoreProperties(value = { "post" ,"hibernateLazyInitializer", "handler" }, allowSetters = true)
//@JsonBackReference
private Posts post;
@Column(name="last_updated")
@LastModifiedDate
private Date lastUpdated;
}
Here is my CommentsDTO.class
@Data
public class CommentsDTO {
private Long comment_id;
private UserDTO user;
private String description;
private PostDTO post;
private String images;
private Date lastUpdated;
}
Here is my REST Controller
@GetMapping
public @ResponseBody ResponseEntity<List<PostDTO>> getAll() throws Exception {
return new ResponseEntity<List<PostDTO>>(service.getAll(), HttpStatus.OK);
}
Here is my service
public List<PostDTO> getAll() throws Exception {
return repo.findAll()
.stream()
.map(this::convert)
.collect(Collectors.toList());
}
private PostDTO convert(Posts e) {
return mapper.map(e, PostDTO.class);
}
Hope someone can shed light on my issue. Kinda lost as of this time.
答案1
得分: 1
问题在于当你将 Post
转换为 PostDTO
时,通过使用 ModelMapper,它会调用 Post
的所有字段的 getter 方法来为 PostDTO
设置值。因此,对于这个语句 mapper.map(e, PostDTO.class)
,会发生递归调用。
所以,只需从 CommentDTO
中移除 private PostDTO post
字段,
然后 ModelMapper 就不会尝试设置 PostDTO->comment->post
字段。
在DTO中不需要双向关系。DTO 完全是关于你想在响应中展示什么内容。
英文:
Problem is when you convert Post
into PostDTO
then by using ModelMapper it calls all field's getter of Post for PostDTO
. So this happened recursively for this
mapper.map(e, PostDTO.class)
So, just remove private PostDTO post
from CommentDTO ,
then modelmapper don't try to set PostDTO->comment-> post field.
And you don't need bidirectional relation in DTO. DTO is all about what you want to show in response.
答案2
得分: 0
你正在错误的类上打破了JSON序列化循环。
你正在发送一个PostDTO
列表,但是将JsonBackReference
应用于Comments
,将JsonManagedReference
应用于Posts
。
更新
注意,ObjectMapper
类,JsonManagedReference
和JsonBackReference
可能来自2个包:
- com.fasterxml.jackson.databind.ObjectMapper
- com.fasterxml.jackson.annotation.JsonManagedReference
- com.fasterxml.jackson.annotation.JsonBackReference
或者:
- org.codehaus.jackson.map.ObjectMapper
- org.codehaus.jackson.annotate.JsonManagedReference
- org.codehaus.jackson.annotate.JsonBackReference
如果它们之间不一致,不匹配的注释将被忽略,您在序列化期间仍将遇到无限循环。
英文:
You are breaking the json serialization cycle on the wrong class.
You are sending a list of PostDTO
, but applied JsonBackReference
to Comments
and JsonManagedReference
to Posts
Update
Note that ObjectMapper
class, JsonManagedReference
and JsonBackReference
may from 2 packages
- com.fasterxml.jackson.databind.ObjectMapper
- com.fasterxml.jackson.annotation.JsonManagedReference
- com.fasterxml.jackson.annotation.JsonBackReference
or:
- org.codehaus.jackson.map.ObjectMapper
- org.codehaus.jackson.annotate.JsonManagedReference
- org.codehaus.jackson.annotate.JsonBackReference
If you are not consistent between all of them, the mis-matched annotation will be ignored and you will still experience infinite loop during serialization.
答案3
得分: 0
使用 JsonIgnoreProperties 与管理和反向引用。
@Data
@Entity
@Table(name = "comments")
@EntityListeners(AuditingEntityListener.class)
public class Comments {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "comment_id")
private Long comment_id;
@OneToOne
@JoinColumn(name = "user_id")
private Users user;
@Column(name = "description")
private String description;
@Column(name = "images")
private String images;
@ManyToOne
@JoinColumn(name = "post_id", nullable = false)
@JsonIgnoreProperties(value = { "comments", "hibernateLazyInitializer", "handler" }, allowSetters = true)
@JsonBackReference
private Posts post;
@Column(name = "last_updated")
@LastModifiedDate
private Date lastUpdated;
}
你的 Post 类应该是
@Data
@Entity
@Table(name = "posts")
@EntityListeners(AuditingEntityListener.class)
public class Posts {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "post_id")
private Long post_id;
@ManyToOne
@JoinColumn(name = "user_id", nullable = false)
private Users user;
@Column(name = "description")
private String description;
@Column(name = "images")
private String images;
@Column(name = "tags")
private String tags;
@OneToMany(
fetch = FetchType.LAZY,
mappedBy = "post",
cascade = CascadeType.ALL,
orphanRemoval = true
)
@JsonIgnoreProperties(value = { "post", "hibernateLazyInitializer", "handler" }, allowSetters = true)
@JsonManagedReference
private List<Comments> comments;
@LastModifiedDate
@Column(name = "last_updated")
private Date lastUpdated;
public void addComments(Comments comment) {
this.comments.add(comment);
}
}
此外,我建议使用 Getter 和 Setter 注释而不是 @Data。因为 ToString() 方法会导致递归。
英文:
Use JsonIgnoreProperties along with Manage and backreference .
@Data
@Entity
@Table(name = "comments")
@EntityListeners(AuditingEntityListener.class)
public class Comments {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name="comment_id")
private Long comment_id;
@OneToOne
@JoinColumn(name = "user_id")
private Users user;
@Column(name = "description")
private String description;
@Column(name="images")
private String images;
@ManyToOne
@JoinColumn(name ="post_id" , nullable = false)
@JsonIgnoreProperties(value = { "comments" ,"hibernateLazyInitializer", "handler" }, allowSetters = true)
@JsonBackReference
private Posts post;
@Column(name="last_updated")
@LastModifiedDate
private Date lastUpdated;
}
And Your Post class should be
@Data
@Entity
@Table(name = "posts")
@EntityListeners(AuditingEntityListener.class)
public class Posts {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "post_id")
private Long post_id;
@ManyToOne
@JoinColumn(name = "user_id", nullable = false)
private Users user;
@Column(name = "description")
private String description;
@Column(name="images")
private String images;
@Column(name="tags")
private String tags;
@OneToMany(
fetch = FetchType.LAZY,
mappedBy = "post",
cascade = CascadeType.ALL,
orphanRemoval = true
)
@JsonIgnoreProperties(value = { "post" ,"hibernateLazyInitializer", "handler" }, allowSetters = true)
@JsonManagedReference
private List<Comments> comments;
@LastModifiedDate
@Column(name = "last_updated")
private Date lastUpdated;
public void addComments(Comments comment) {
this.comments.add(comment);
}
}
Also I would suggest to Use Getter and Setter annotation instead of @Data .Because Tostring() method will cause recursion also .
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论