在spring中,我的类之间有一些一对多的关系。当我试图获取所有数据时,这是一个类似无限递归的错误,下面是整个错误消息。
at com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serialize(CollectionSerializer.java:25) ~[jackson-databind-2.9.6.jar:2.9.6]
at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:727) ~[jackson-databind-2.9.6.jar:2.9.6]
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:719) ~[jackson-databind-2.9.6.jar:2.9.6]
我有两个类,它们通过OneToMany Relationship 相互连接
用户类别
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;
@OneToMany(mappedBy = "User")
private List<Conversation> Conversation;
会话类
public class Conversation {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
@JoinColumn(name = "User_id")
private User User;
结果截图
屏幕截图结果
我不知道为什么会发生这种情况,但也许是因为和Failure类的关系。
存储库类
@Query(nativeQuery = true, value = "SELECT * FROM `conversation` WHERE 1")
public List<Conversation> findAllConv();
控制器类
@Autowired
private ConversationRepository conv;
@GetMapping("/GetAllConversation")
public List<Conversation> getAllConv()
{
return conv.findAllConv();
}
完整跟踪
2021-05-14 12:58:57.306 ERROR 1540 --- [nio-8020-exec-1] w.s.e.ErrorMvcAutoConfiguration$SpelView : Cannot render error page for request [/survey/GetAllConversation/] and exception [Could not write JSON: Infinite recursion (StackOverflowError); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion (StackOverflowError) (through reference chain: org.club.entities.User_$$_jvstf65_b["conversation"]->org.hibernate.collection.internal.PersistentBag[0]->org.club.entities.Conversation["user"]-
一般使用关系时,可以调整"获取";以及";级联";类型获取意味着,如果与要加载的条目相关的所有条目都已加载,而级联则与传递给相关对象的当前条目上的操作相关。
第1版:我建议您尝试将fetch
类型设置为lazy,至少对于Conversation
类:
@ManyToOne(fetch = FetchType.LAZY)
除此之外,我建议使用从CrudRepository
继承的存储库,以便您可以使用派生查询。
第2版:在看到堆栈跟踪之后,问题就清楚了。Jackson试图将Conversation
对象绑定到JSON,但由于User
类中的Conversation引用,遇到了一个无休止的循环。
有两种方法可以解决这个问题。如果仍要插入Conversation
引用的User
对象,则可以添加@JsonIgnore
注释。
@JsonIgnore
@OneToMany(mappedBy = "User")
private List<Conversation> Conversation;
如果你根本不关心用户,那么你也可以将其添加到对话对象中的用户引用中:
@JsonIgnore
@JoinColumn(name = "User_id")
private User User;
如果以后遇到问题,还可以考虑将存储库返回的Conversation
对象映射到专门为JSON映射而创建的特定数据传输对象。
根据stacktrace和数据模型判断,问题在于User和Converstaion类之间存在双向关系。
用户有一个对话项目列表,然后链接回用户。序列化时,这会创建一个无限循环:
序列化用户->序列化他的对话->序列化coveration.user->连载他的谈话等。
避免这种情况的一种方法是用@JsonIgnore
注释converstaion中的User字段,这样在序列化用户时,你会得到他的对话,但由于Jackson会忽略引用,所以你不会从堆栈中得到错误。
异常消息在这里非常清楚:无限递归(StackOverflowError
我遇到了同样的问题,并通过以下方法解决了它。首先我有两节课。
public class Entite implements Serializable {
static final long serialVersionUID = 3L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int entiteId;
private String entiteName;
private String affectation, Wilayas, type, Mougattaa;
// @JsonBackReference
@OneToMany(mappedBy = "entite", fetch = FetchType.LAZY, cascade = CascadeType.MERGE)
@JsonIgnore
// @JoinTable(name = "dep_ent_TABLE",
// joinColumns = @JoinColumn(name = "entite_id"),
// inverseJoinColumns = @JoinColumn(name = "department_id")
// )
// ( cascade = CascadeType.REMOVE)
private Set<Department> departments;
// private Department department;
protected Entite() {
departments = new HashSet<>();
}
}
另一类是
public class Department {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int departmentId;
@Column(name = "department_name")
private String departmentName;
@Column(name = "department_url")
private String departmentUrl;
@Column(name = "department_titre")
private String departmentTitre;
// @OneToMany(mappedBy = "department", cascade = CascadeType.REMOVE)
@ManyToOne
// @JsonIgnore
// @JsonManagedReference
private Entite entite;
public Department() {
// entites = new HashSet<>();
}
}
通过添加@JsonIgnore
在代码的这一行之上
private Set<Department> departments;
让它发挥作用。