我有无限递归的烦人的问题。我的应用程序是作为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;
}
}
事件变更
@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与Incident,Comment和IncidentChange具有OneToMany关系。
事件与AppUser之间存在ManyToOne关系(重要的是TWICE),
一对多评论,
一对一更改日志
评论与AppUser有ManyToOne关系,
多对一事件
ChangeLog与事件具有OneToOne关系,
一对多事件更改
IncidentChange与ChangeLog具有ManyToOne关系,
多对一到AppUser
我知道AppUser处于事件中,并且处于注释中,该事件嵌套在事件中,与IncidentChange处于相同的情况,但是嵌套得更深。
这是一些想要检查如何创建AppUser和事件的人的代码https://bitbucket.org/StabloPL/backendsimpleticketsystem/src/76e6bd107e68c82614fbc040b95f041fd7f51d28/src/main/java/com/djagiellowicz/ticketsystem/backendsimpleticketsystem/model/?at=master
IncidentController,AppUserControler和IncidentService,AppUserService可能会使某些人感兴趣。
当我创建用户(通过邮递员以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中删除这些信息。
最佳答案
您必须覆盖Lombok的注释...使用@Data
时,必须使用类中的所有字段隐式调用@EqualsAndHashCode
。无限递归源自用于映射关系的字段。每个类中的@EqualsAndHashCode
排除集合字段。例如,您可以在AppUser类上添加注释@EqualsAndHashCode(exclude={"userRoleSet", "createdIncidentsList","assignedToIncidentsList","commentList","incidentChangeList"})
以覆盖@Data
默认策略。您必须在每个模型类上执行此操作,直到没有无限递归错误为止。
另外...您的类之间具有循环依赖关系。序列化对象时,应删除所有循环依赖项。最好的解决方案是序列化DTO,而不是实体。创建没有循环依赖关系的DTO应该可以解决此问题。在序列化/反序列化过程中,您可以使用AppUserDTO,其中包含事件列表,一个IncidentDTO列表,但未引用AppUser。