我在使用Spring Boot 2.0,Hibernate和Spring Data REST的项目中工作。 FrontEnd with React。
我认为用户可以与多家公司联系(他拥有多家公司)
当我尝试使用UserRepository或CompanyRepository获取某些实体时,我收到错误:无法写入JSON:无限递归(StackOverflowError);嵌套异常是com.fasterxml.jackson.databind.JsonMappingException:无限递归(StackOverflowError)。
我必须使用Projections限制前往FrontEnd的数据,因为我需要指向实体的链接,由Projections自动生成。
关注实体:
@Entity
public class User implements UserDetails {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id_user")
protected Long id;
@OneToMany(cascade= { CascadeType.MERGE }, fetch = FetchType.EAGER, mappedBy="user")
private List<Company> companyList;
// Other data
// Getters and Setters
}
@Entity
public class Company extends CadastroEmpresaUnica {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id_company")
protected Long id;
@ManyToOne(cascade= { CascadeType.MERGE })
@JoinColumn(name="id_user", nullable = false)
private User user;
// Other data
// Getters and Setters
}
预测:
@Projection(name = "userProjection", types = { User.class })
public interface UserProjection {
List<CompanyProjection> getCompanyList();
// Other Getters
}
@Projection(name = "companyProjection", types = { Company.class })
public interface CompanyProjection {
UserProjection getUser();
// Other Getters
}
我们正在使用的其中一个存储库:
@RepositoryRestResource(collectionResourceRel = "company", path = "companies", excerptProjection = CompanyProjection.class)
public interface CompanyRepository extends PagingAndSortingRepository<Company, Long>, CompanyRepositoryCustom, JpaSpecificationExecutor<Company> {}
搜索双向无限递归我发现了关于&#39; @JsonManagedReference&#39;的内容。和&#39; @JsonBackReference&#39;,始终直接在实体中使用。所以我试着在我的预测中使用它并且它有效。所以它解决了我的无限递归问题,但它产生了另一个问题,我无法从我的公司访问我的用户(因为显然&#39; @JsonBackReference&#39;不能让它停止递归)。 /> 以下是此解决方案的预测:
@Projection(name = "userProjection", types = { User.class })
public interface UserProjection {
@JsonManagedReference
List<CompanyProjection> getCompanyList();
// Other Getters
}
@Projection(name = "companyProjection", types = { Company.class })
public interface CompanyProjection {
@JsonBackReference
UserProjection getUser();
// Other Getters
}
再多搜索一下我在实体中使用过的@ JsonIdentityInfo&#39;所以我试图删除其他Json注释并使用&#39; @JsonIdentityInfo&#39;在我的投影中。如下例所示:
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property="id")
@Projection(name = "userProjection", types = { User.class })
public interface UserProjection {
Long getId();
List<CompanyProjection> getCompanyList();
// Other Getters
}
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property="id")
@Projection(name = "companyProjection", types = { Company.class })
public interface CompanyProjection {
Long getId();
UserProjection getUser();
// Other Getters
}
它没有用。现在Json无限递归再次发生 我是Spring Data REST的新手,我真的想通过Spring Data Rest了解更好的Projections,阅读Spring文档和Stackoverflow主题。我想知道我做错了什么,当然,如果我以错误的方式使用预测,但我需要继续这个项目。
答案 0 :(得分:1)
首先是SDR docs双向关系))
要解决这种情况,请尝试在公司实体中向User getter添加以下内容:
@RestResource(exported = false)
@JsonIgnore
public User getUser() {...}
您也可以尝试使用注释does not like。
此外,我认为如果您只需要获得用户的公司(以及公司的用户),您就不需要使用预测。 SDR中的相关资源就像这样导出(在您的情况下):
/users/{id}/companies
/companies/{id}/users
答案 1 :(得分:1)
有点难看,但简单的解决方案可能是另一个投影(例如CompanyWithoutUserProjection),它可以阻止你的递归。
CompanyProjection {
UserProjection getUser();
//other getters
}
UserProjection {
List<CompanyWithoutUserProjection> getCompanyList();
//other getters
}
CompanyWithoutUserProjection {
//other getters
}
答案 2 :(得分:1)
我们找到的最好方法是使用Jackson注释@JsonIgnoreProperties,这应该在父列表中使用,以便在孩子身上使用自己。但是,经过几次尝试后,似乎这个注释不适用于预测,特别是对于Spring Data REST 按照正确的方式举例:
@Projection(name = "userProjection", types = { User.class })
public interface UserProjection {
@JsonIgnoreProperties({"user"})
List<CompanyProjection> getCompanyList();
// Other Getters
}
@Projection(name = "companyProjection", types = { Company.class })
public interface CompanyProjection {
UserProjection getUser();
// Other Getters
}
我们为此Spring Data REST问题发送ticket并已被接受。我们相信在不久的将来它会被纠正,我们可以使用它
现在,我们调整我们的投影,以便列表对象可以使用原始投影的“推导”,忽略导致无限递归的属性。
按照示例:
@Projection(name = "userProjection", types = { User.class })
public interface UserProjection {
List<CompanyProjectionWithoutUser> getCompanyList();
// Other Getters
// Projection without the User, that couses infinite recursion
public interface CompanyProjectionWithoutUser extends CompanyProjection {
@Override
@JsonIgnore
UserProjection getUser();
}
}
@Projection(name = "companyProjection", types = { Company.class })
public interface CompanyProjection {
UserProjection getUser();
// Other Getters
}