Spring Boot JPA:在自联接关系中的 JSON 视图上递归
Posted
技术标签:
【中文标题】Spring Boot JPA:在自联接关系中的 JSON 视图上递归【英文标题】:Spring boot JPA: recursion on JSON-view in a self join relationShip 【发布时间】:2020-04-04 03:08:38 【问题描述】:对于我正在尝试构建的项目,我需要从用户类到用户类的多对多关系。(用户有朋友,朋友是用户的朋友)。 当试图用 JPA 让 Json 脱离 SpringBoot 时。我的 JSON 上有一个递归循环。(只有当两个用户是彼此的朋友时才会发生这种情况)
我知道会发生什么,但找不到问题的解决方案。 如您所见,我正在使用不同的视图来“过滤”视图。问题是:如何停止递归?
@Entity
public class User
@Id
@GeneratedValue
@JsonView(JsonViews.UserView.class)
private long userId;
@JsonView(JsonViews.UserView.class)
private String username;
@JsonView(JsonViews.UserView.class)
private String password;
@JsonView(JsonViews.UserView.class)
private String email;
@JsonView(JsonViews.UserView.class)
private String location;
//private String avatar;
@JsonView(JsonViews.UserView.class)
private int ranking;
private String UserStatus;
//Friend Relation Many > Many
@JsonView(JsonViews.UserView.class, JsonViews.FriendWith.class)
@ManyToMany()
private List<User> friendsWith;
@ManyToMany(mappedBy = "friendsWith")
private List<User> friendOf;
@JsonView(JsonViews.UserView.class, JsonViews.Player.class)
@OneToMany(mappedBy = "user")
private List<Player> player;
public User()
this.friendsWith = new ArrayList<>();
this.friendOf = new ArrayList<>();
public User(String username, String password, String email, String location, int ranking)
this();
//this.userId = userId;
this.username = username;
this.password = password;
this.email = email;
this.location = location;
this.ranking = ranking;
// and th usual getters and setters
堆栈:
2019-12-10 22:17:52.414 ERROR 1618 --- [nio-8084-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service()
for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: Infinite recursion (***Error); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion (***Error) (through reference chain: org.hibernate.collection.internal.PersistentBag[0]->
nl.hva.ewa.stratego.backend.models.User["friendsWith"]->
org.hibernate.collection.internal.PersistentBag[0]->
nl.hva.ewa.stratego.backend.models.User["friendsWith"]->
org.hibernate.collection.internal.PersistentBag[0]->
nl.hva.ewa.stratego.backend.models.User["friendsWith"]->
org.hibernate.collection.internal.PersistentBag[0]->
nl.hva.ewa.stratego.backend.models.User["friendsWith"]->
ETC.... ETC.....
为了完整性,JsonViews 类:
public class JsonViews
public class UserView ;
public class AComplete extends UserView ;
public class BComplete extends UserView ;
public class FriendsWith extends UserView ;
public class FriendsOf extends UserView ;
public class Player extends UserView ;
【问题讨论】:
【参考方案1】:试试@JsonIdentityInfo
注解,在这里你可以告诉Jackson什么是POJO id,这样就不会重复了:
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "userId")
public class User
public long userId;
public String name;
public List<User> friends;
这将生成以下 JSON:
"userId" : 11,
"name" : "A",
"friends" : [
"userId" : 22,
"name" : "B",
"friends" : [ 11,
"userId" : 33,
"name" : "C",
"friends" : [ ]
]
]
请注意,在内部用户 B 中,如果用户已添加到 JSON 正文 [ 11,
,则好友列表仅包含 ID。
【讨论】:
这有点工作。[ "userId": 1, "username": "bas", "friendsWith": [ "userId": 2, "username": "dave", "friendsWith": [ 1 ] ] , 2, // Other users ,
现在的事情是我将完整的“用户”视为朋友。但是是否可以只显示 FriendsWith 数组中的 ID。并将 Complete 用户作为下一个完整对象。在这种情况下,有点像 Dave 的 FriendsWith 数组.....
有一个问题,默认情况下您将无法反序列化回朋友,因为杰克逊不知道如何将朋友的 ID 反序列化为 User 对象(想象 userId:3这不在 JSON 的正文中)。您可以为其使用自定义序列化器和反序列化器,但反序列化后的朋友用户对象仍然只有 userId。这可以接受吗?你只需要朋友的ID吗?
我认为这会有所帮助,非常感谢您的帮助
我在想如果你只需要你可以做的 ID:@JsonProperty("friendsIds") public List<Long> getFriendIds() return friends.stream().map(u -> u.userId).collect(Collectors.toList());
和 @JsonIgnore public List<User> friends;
。您仍然需要手动处理反序列化以上是关于Spring Boot JPA:在自联接关系中的 JSON 视图上递归的主要内容,如果未能解决你的问题,请参考以下文章
Spring boot之 JPA/Hibernate/Spring Data
在 Spring Boot 中使用 JPA 从具有 OneToMany 关系的实体中删除对象
Spring Data JPA在Spring Boot中的应用
Spring Boot JPA多对多关系-Rest Web Service无法获取Get All中的所有子属性