我正在尝试将两个实体与 JPA 关联起来,当我运行该项目时,不会抛出错误,但是当我请求获得社区领袖投票者的方法时,我收到下一个异常:
java.lang.StackOverflowError: null
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:245) ~[gson-2.8.5.jar:na]
at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:69) ~[gson-2.8.5.jar:na]
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:127) ~[gson-2.8.5.jar:na]
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:245) ~[gson-2.8.5.jar:na]
at com.google.gson.Gson$FutureTypeAdapter.write(Gson.java:1018) ~[gson-2.8.5.jar:na]
at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:69) ~[gson-2.8.5.jar:na]
at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.write(CollectionTypeAdapterFactory.java:97) ~[gson-2.8.5.jar:na]
at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.write(CollectionTypeAdapterFactory.java:61) ~[gson-2.8.5.jar:na]
at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:69) ~[gson-2.8.5.jar:na]
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:127) ~[gson-2.8.5.jar:na]
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:245) ~[gson-2.8.5.jar:na]
at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:69) ~[gson-2.8.5.jar:na]
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:127) ~[gson-2.8.5.jar:na]
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:245) ~[gson-2.8.5.jar:na]
at com.google.gson.Gson$FutureTypeAdapter.write(Gson.java:1018) ~[gson-2.8.5.jar:na]
at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:69) ~[gson-2.8.5.jar:na]
at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.write(CollectionTypeAdapterFactory.java:97) ~[gson-2.8.5.jar:na]
at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.write(CollectionTypeAdapterFactory.java:61) ~[gson-2.8.5.jar:na]
at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:69) ~[gson-2.8.5.jar:na]
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:127) ~[gson-2.8.5.jar:na]
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:245) ~[gson-2.8.5.jar:na]
at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:69) ~[gson-2.8.5.jar:na]
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:127) ~[gson-2.8.5.jar:na]
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:245) ~[gson-2.8.5.jar:na]
at com.google.gson.Gson$FutureTypeAdapter.write(Gson.java:1018) ~[gson-2.8.5.jar:na]
我就像一个循环,我不知道如何解决这个问题。
这是我的课程:
1)领导实体:
@Entity
@Table(name = "leaders")
public class Leader implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
Long id;
@NotEmpty
String phone;
@NotEmpty
String name;
@OneToMany( mappedBy = "leader", fetch = FetchType.LAZY,cascade = CascadeType.ALL, orphanRemoval = true)
private List<Voter> voters;
public Leader() {
voters = new ArrayList<>();
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getCelular() {
return phone;
}
public void setCelular(String celular) {
this.phone = celular;
}
public String getNombre() {
return name;
}
public void setNombre(String nombre) {
this.name = nombre;
}
public List<Voter> getVotantes() {
return voters;
}
public void setVotantes(List<Voter> votantes) {
this.voters = votantes;
}
public void addVotante(Voter votante){
voters.add(votante);
}
}
2)选民实体:
@Entity
@Table(name = "voters")
public class Voter implements Serializable {
@Id
String id;
String name;
String phone;
String email;
@Column(name = "electoral_school")
String electoralSchool;
@Temporal(TemporalType.DATE)
Date registrationDate;
@ManyToOne(fetch = FetchType.LAZY)
private Leader leader;
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
Sector sector;
@PrePersist
public void prePersist() {
registrationDate = new Date();
}
public String getCedula() {
return id;
}
public void setCedula(String cedula) {
this.id = cedula;
}
public String getNombre() {
return name;
}
public void setNombre(String nombre) {
this.name = nombre;
}
public String getTelefono() {
return phone;
}
public void setTelefono(String telefono) {
this.phone = telefono;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getColegioElectoral() {
return electoralSchool;
}
public void setColegioElectoral(String colegioElectoral) {
this.electoralSchool = colegioElectoral;
}
public Leader getDirigente() {
return leader;
}
public void setDirigente(Leader dirigente) {
this.leader = dirigente;
}
public Date getRegistro() {
return registrationDate;
}
public void setRegistro(Timestamp registro) {
this.registrationDate = registro;
}
}
3)领导者控制器:
@Controller
@RequestMapping("/leader")
public class LeaderController {
@Autowired
IDirigenteService leaderService;
@RequestMapping(value="getVoters/{leader_id}")
@ResponseBody
public String getAll(@PathVariable(value = "leader_id") Long leader_id){
Gson gson = new Gson();
return gson.toJson(leaderService.findById(leader_id).getVotantes());
}
}
我用 import.sql 中的测试数据填充表格。
提前致谢。
Hibernate OneToMany 或 JPA 双向关系抛出
java.lang.StackOverflowError: null
是一个循环依赖问题,如果您使用 toString()
复杂注释,则可能源自 Lombok 的 @Data
自动生成方法。
要排除某个字段的循环依赖,或者更好的是,如果不需要 toString(),可以使用
@Getter
和 @Setter
。好吧,当我遇到上述问题时,这些解决方案对我有用。
然后您可以在特定属性上使用
@JsonIgnore
。
@Getter
@Setter
public class MyClass {
}
您的
Leader
和 Voter
类相互引用,因此序列化进入递归。
将
@JsonIgnoreProperties
添加到相应字段:
@OneToMany( mappedBy = "leader", fetch = FetchType.LAZY,cascade = CascadeType.ALL, orphanRemoval = true)
@JsonIgnoreProperties("leader")
private List<Voter> voters;
和
@ManyToOne(fetch = FetchType.LAZY)
@JsonIgnoreProperties("voters")
private Leader leader;
PS:哎呀,这是给 Jackson 的,不是给 gson 的。但想法是相同的 - 看看here,如何排除序列化字段。
正确,序列化最终会陷入无限递归,试图序列化彼此引用的对象。
使用Gson序列化引用类型时,尝试使用排除策略。
在下面的代码片段中,我通知 Gson 排除
Leader
类中用 ManyToOne
注释的字段:
@RequestMapping(value="getVoters/{leader_id}")
@ResponseBody
public String getAll(@PathVariable(value = "leader_id") Long leader_id){
ExclusionStrategy strategy = new ExclusionStrategy() {
@Override
public boolean shouldSkipField(FieldAttributes field) {
return field.getDeclaringClass() == Leader.class &&
field.getAnnotation(OneToMany.class) != null;
}
@Override
public boolean shouldSkipClass(Class<?> clazz) {
return false;
}
};
Gson gson = new GsonBuilder().disableHtmlEscaping()
.addSerializationExclusionStrategy(strategy)
.create();
return gson.toJson(leaderService.findById(leader_id).getVotantes());
}
@ToString(排除=“领导者”) 公开课投票者{ ...... ......
}