我的无限递归问题非常烦人。我的应用程序正在构建为Spring Rest API,我使用Lombok生成构造函数和getter以及setter。我的模特很少。
AppUser - 可能是最大的一个。
@NoArgsConstructor
@AllArgsConstructor
@Data
@Entity
public class AppUser {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String login;
private String name;
private String surname;
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
private String password;
public AppUser(String login, String password, UserRole userRole) {
this.login = login;
this.password = password;
this.userRoleSet = new HashSet<>();
this.userRoleSet.add(userRole);
}
public AppUser(String login, String name, String surname, String password) {
this.login = login;
this.name = name;
this.surname = surname;
this.password = password;
}
@OneToMany(mappedBy = "appUser",fetch = FetchType.EAGER)
private Set<UserRole> userRoleSet;
@OneToMany(mappedBy = "createdBy")
private List<Incident> createdIncidentsList;
@OneToMany(mappedBy = "assignedTo")
private List<Incident> assignedToIncidentsList;
@OneToMany(mappedBy = "postedBy")
private List<Comment> commentList;
@OneToMany(mappedBy = "appUser")
private List<IncidentChange> incidentChangeList;
}
事件
@Data
@Entity
public class Incident {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
private String description;
private LocalDateTime creationDate;
private IncidentStatus status;
@OneToMany(mappedBy = "incident", cascade = CascadeType.ALL)
private List<Comment> commentList;
@ManyToOne
private AppUser createdBy;
@ManyToOne
private AppUser assignedTo;
@OneToOne(cascade = CascadeType.ALL)
private ChangeLog changeLog;
public Incident(String title, String description) {
this.title = title;
this.description = description;
this.creationDate = LocalDateTime.now();
this.status = IncidentStatus.NEW;
this.commentList = new ArrayList<>();
this.changeLog = new ChangeLog();
}
public Incident(){
}
public Incident(String title, String description, LocalDateTime creationDate, IncidentStatus status, List<Comment> commentList, AppUser assignedTo, AppUser createdBy, ChangeLog changeLog) {
this.title = title;
this.description = description;
this.creationDate = creationDate;
this.status = status;
this.commentList = commentList;
this.changeLog = changeLog;
}
}
注释
@Data
@NoArgsConstructor
@Entity
public class Comment {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String description;
private LocalDateTime creationDate;
@ManyToOne
private AppUser postedBy;
@ManyToOne
private Incident incident;
}
修改记录
@Data
@Entity
public class ChangeLog {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@OneToOne
private Incident incident;
@OneToMany(mappedBy = "changeLog")
private List<IncidentChange> incidentChangeList;
public ChangeLog(){
this.incidentChangeList = new ArrayList<>();
}
public ChangeLog(Incident incident, List<IncidentChange> incidentChangeList) {
this.incident = incident;
this.incidentChangeList = incidentChangeList;
}
}
IncidentChange
@Data
@NoArgsConstructor
@Entity
public class IncidentChange {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String description;
private LocalDateTime changeDate;
@ManyToOne
private ChangeLog changeLog;
@ManyToOne
private AppUser appUser;
}
简而言之就是这样:
AppUser与事件,评论和事件变更有一个关系。
事件与AppUser有很多关系(TWICE很重要),
OneToMany评论,
OneToOne to ChangeLog
评论与AppUser有很多关系,
ManyToOne事件发生
ChangeLog具有与事件的OneToOne关系,
OneToMany to IncidentChange
IncidentChange具有与ChangeLog的ManyToOne关系,
ManyToOne到AppUser
我知道AppUser处于事件状态,并且在Comment中嵌套在Incident中,与IncidentChange相同,但它的嵌套更深。
以下是想要检查如何创建AppUser和突发事件的人员的代码https://bitbucket.org/StabloPL/backendsimpleticketsystem/src/76e6bd107e68c82614fbc040b95f041fd7f51d28/src/main/java/com/djagiellowicz/ticketsystem/backendsimpleticketsystem/model/?at=master IncidentController,AppUserControler和IncidentService,AppUserService都是可能让人感兴趣的东西。
当我创建用户(通过Postman作为JSON),之后我获取它,没有问题一切正常。当我创建事件并将其分配给特定的人时,我无法获取事件,也无法获取此特定用户。其他页面,其中没有创建事件的用户获取没有任何问题。这同样适用于未分配createdBy用户的事件。一切都保存到数据库,没有任何问题。
当我尝试获取事件时,Hibernate / Spring抛出了这个错误。当然有点削减。
java.lang.IllegalStateException: Cannot call sendError() after the response has been committed
at org.apache.catalina.connector.ResponseFacade.sendError(ResponseFacade.java:472) ~[tomcat-embed-core-8.5.29.jar:8.5.29]
at javax.servlet.http.HttpServletResponseWrapper.sendError(HttpServletResponseWrapper.java:129) ~[tomcat-embed-core-8.5.29.jar:8.5.29]
at javax.servlet.http.HttpServletResponseWrapper.sendError(HttpServletResponseWrapper.java:129) ~[tomcat-embed-core-8.5.29.jar:8.5.29]
2018-04-24 11:39:43.731 ERROR 18300 --- [nio-8080-exec-4] 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 (StackOverflowError); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion (StackOverflowError) (through reference chain: com.djagiellowicz.ticketsystem.backendsimpleticketsystem.model.AppUser["createdIncidentsList"]->org.hibernate.collection.internal.PersistentBag[0]->com.djagiellowicz.ticketsystem.backendsimpleticketsystem.model.Incident["createdBy"]->com.djagiellowicz.ticketsystem.backendsimpleticketsystem.model.AppUser["createdIncidentsList"]->org.hibernate.collection.internal.PersistentBag[0]->
java.lang.StackOverflowError: null
我该如何解决?我必须知道AppUser发布了哪条评论,同样适用于Incident和IncidentChange,我不想从Incident / IncidentChange / Comment
中删除这些信息答案 0 :(得分:2)
您必须覆盖Lombok的注释...当您使用@Data
时,您隐式使用类中的所有字段调用@EqualsAndHashCode
。无限递归从您用于映射关系的字段中引发。每个类中@EqualsAndHashCode
以排除集合字段。例如,您可以在AppUser类上添加annotatio @EqualsAndHashCode(exclude={"userRoleSet", "createdIncidentsList","assignedToIncidentsList","commentList","incidentChangeList"})
以覆盖@Data
默认策略。您必须在每个模型类上执行此操作,直到没有无限递归错误。
此外......您的类之间存在循环依赖关系。序列化对象时,应删除所有循环依赖项。最好的解决方案是序列化DTO而不是实体。创建没有循环依赖关系的DTO应该可以解决这个问题。在序列化/反序列化中,您可以使用包含事件列表的AppUserDTO,一个不带AppUser参考的IncidentDTO列表。
答案 1 :(得分:1)
您可以将@JsonIgnore
注释放在您不希望包含在JSON中的字段中。
如果您想要更灵活,可以使用@JsonView
注释。
您还可以使用@JsonManagedReference
和@JsonBackReference
。
您使用的是由您自己决定的。如果您真的不需要前端的属性,我建议您使用@JsonIgnore
。如果在某种情况下您可能需要一个属性而不是另一个属性,我会使用@JsonView
。