JPA Bidirectional relationship throws java.lang.StackOverflowError: null

纵饮孤独 提交于 2019-12-11 02:49:50

问题


i'm trying to relate two entities with JPA, when i run the project don't throws me errors but when i request the method that get me the Voters of a Comunity Leader i get the next Exception:

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]

I'ts like a loop, i don't khow how to resolve this.

Here are my classes:

1)Leader Entity :

@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)Voter Entity :

@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)LeaderController :

@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());

    }

}

I fill the tables with test data in import.sql.

Thanks in advance.


回答1:


Your Leader and Voter classes has references for each other, so serialization go into recursion.

Add @JsonIgnoreProperties to corresponding fields:

@OneToMany( mappedBy = "leader", fetch = FetchType.LAZY,cascade = CascadeType.ALL, orphanRemoval = true)
@JsonIgnoreProperties("leader")
private List<Voter> voters;

and

@ManyToOne(fetch = FetchType.LAZY)
@JsonIgnoreProperties("voters")
private Leader leader;

PS: Oops, it's for jackson, not for gson. But idea is the same - take a look here, how to exclude fields for serialization.




回答2:


Correct, the serialization ends up in an infinite recursion trying to serialize the objects that reference each other.

When using Gson to serialize referenced types, try using an exclusion strategy.

In the following snippet I've informed Gson to exclude fields in the Leader class annotated with 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());
    }


来源:https://stackoverflow.com/questions/54775257/jpa-bidirectional-relationship-throws-java-lang-stackoverflowerror-null

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!