JPA 双向关系抛出 java.lang.StackOverflowError: null

问题描述 投票:0回答:4

我正在尝试将两个实体与 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 中的测试数据填充表格。

提前致谢。

java spring hibernate jpa circular-reference
4个回答
7
投票

Hibernate OneToMany 或 JPA 双向关系抛出

java.lang.StackOverflowError: null
是一个循环依赖问题,如果您使用
toString()
复杂注释,则可能源自 Lombok 的
@Data
自动生成方法。

要排除某个字段的循环依赖,或者更好的是,如果不需要 toString(),可以使用

@Getter
@Setter
。好吧,当我遇到上述问题时,这些解决方案对我有用。

然后您可以在特定属性上使用

@JsonIgnore

@Getter

@Setter

public class MyClass {

}

3
投票

您的

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,如何排除序列化字段。


0
投票

正确,序列化最终会陷入无限递归,试图序列化彼此引用的对象。

使用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());
    }

0
投票

@ToString(排除=“领导者”) 公开课投票者{ ...... ......

}

© www.soinside.com 2019 - 2024. All rights reserved.