我有无限递归的烦人的问题。我的应用程序是作为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。

08-06 19:40