首页 > 解决方案 > Spring JPA“一对多”加载的对象属于错误的类

问题描述

我有一个使用 Spring JPA 的 Spring Boot 应用程序。

我有这些课程:

内戈齐奥

@Entity
public class Negozio {
    @Id
    private String piva;

    private String nome;

    @OneToOne
    @JoinColumn
    private Posizione posizione;

    @OneToOne(mappedBy = "negozio", targetEntity = ResponsabileNegozio.class)
    private ResponsabileNegozio responsabile;

    @OneToMany(mappedBy = "negozio")
    private Set<ProdottoNegozio> prodottiEsposti;

    @OneToMany(mappedBy = "negozio")
    private Set<NegozioLocker> locker;

    @OneToMany(mappedBy = "negozio")
    private Set<RiderNegozio> rider;

    @OneToMany(mappedBy = "negozio")
    private Set<GestoreCatalogo> gestoriCatalogo;

    @OneToMany(mappedBy = "negozio", targetEntity = Cassiere.class)
    private Set<Cassiere> cassieri;

    @SuppressWarnings("unused")
    private Negozio() {

    }

    public Negozio(String piva, String nome, Posizione posizione) {
        this.piva = piva;
        this.nome = nome;
        this.posizione = posizione;
    }

    public String getNome() {
        System.out.println("getting nome");
        return nome;
    }

    public void setNome(String nome) {
        this.nome = nome;
    }

    public String getPiva() {
        System.out.println("getting piva");
        return piva;
    }

    public Posizione getPosizione() {
        System.out.println("getting posizione");
        return posizione;
    }

    public String getResponsabile() {
        System.out.println("getting responsabile NEW");
        return responsabile == null ? null : responsabile.getEmail();
    }

    public Set<ProdottoNegozio> getProdottiEsposti() {
        System.out.println("getting prodotti");
        return prodottiEsposti == null ? Set.of() : this.prodottiEsposti;
    }

    public Set<Locker> getLocker() {
        System.out.println("getting locker");
        return locker == null ? Set.of() : locker.stream().map(ln -> ln.getLocker()).collect(Collectors.toSet());
    }

    public Set<RiderNegozio> getRider() {
        System.out.println("getting rider NEW");
        return rider == null ? Set.of() : rider;
    }

    public Set<Rider> getRiders() {
        System.out.println("getting rider");
        if (rider == null)
            System.out.println("NegozioRider==null");
        else {
            System.out.println("Rider size " + rider.size());
            System.out.println("To string " + rider.toString());
        }

        Set<Rider> sr = rider.stream().map(rn -> rn.getRider()).collect(Collectors.toSet());

        System.out.println("sr done ");
        System.out.println("sr size " + sr.size());
        System.out.println("sr to string " + sr.toString());

        return rider == null ? Set.of() : sr;
    }

    public void setPosizione(Posizione posizione) {
        this.posizione = posizione;
    }

    public Set<Cassiere> getCassieri() {
//here I have some problems so I tried to print some info for manual debug
        System.out.println("getting cassieri");
        if (cassieri == null)
            System.out.println("Cassieri==null");
        else {
            System.out.println("info");
            System.out.println("class " + ((Object) cassieri).getClass().getName());
//here i discover that the runtime type is PersistentSet
            PersistentSet ps = ((PersistentSet) cassieri);
            System.out.println("info2"); //this is the last printed line
            System.out.println("iterator " + ps.iterator().toString()); //this line isn't printed at all, neither the lines below;
            System.out.println("Cassieri size " + ps.size());
            cassieri.stream().findFirst().ifPresent((cassiere) -> {
                System.out.println("trovato");
                System.out.println("email " + cassiere.getEmail());
                System.out.println("nome " + cassiere.getNome());
            });
        }
        return cassieri == null ? Set.of() : cassieri;
    }

    public Set<GestoreCatalogo> getGestoriCatalogo() {
        System.out.println("getting gestoricatalogo");
        return gestoriCatalogo == null ? Set.of() : gestoriCatalogo;
    }

卡西尔

@Entity
public class Cassiere extends Persona {
    private static final long serialVersionUID = 8953780944252571288L;

    @ManyToOne
    @JoinColumn
    private Negozio negozio;

    @SuppressWarnings("unused")
    private Cassiere() {

    }

    public Cassiere(String email, String nome, String cognome, Negozio negozio) {
        super(email, nome, cognome);
        this.negozio = negozio;
        this.roles.add(Roles.CASSIERE);
    }

    public Negozio getNegozio() {
        return negozio;
    }
}

负责任的内戈齐奥

@Entity
public class ResponsabileNegozio extends Persona {
    private static final long serialVersionUID = -7244028674492067048L;

    @OneToOne
    @JoinColumn
    private Negozio negozio;

    @SuppressWarnings("unused")
    private ResponsabileNegozio() {

    }

    public ResponsabileNegozio(String email, String nome, String cognome, Negozio negozio) {
        super(email, nome, cognome);
        this.negozio = negozio;
        this.roles.add(Roles.RESPONSABILE_NEGOZIO);
    }

    public ResponsabileNegozio(String email, String nome, String cognome) {
        this(email, nome, cognome, null);
    }

    public Negozio getNegozio() {
        return negozio;
    }

    public void setNegozio(Negozio negozio) {
        this.negozio = negozio;
    }
}

实际上,我可以通过 JPA Repository 注册一个新的 Negozio,但是当我通过它的 ID 获取该 Negozio 以将其返回到休息控制器时,我有以下异常:

{
    "timestamp": "2020-03-08T16:04:45.698+0000",
    "status": 500,
    "error": "Internal Server Error",
    "message": "Could not write JSON: Object [id=resemail@a.it] was not of the specified subclass [com.github.backcamino.emporio.models.GestoreCatalogo] : loaded object was of wrong class class com.github.backcamino.emporio.models.ResponsabileNegozio; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Object [id=resemail@a.it] was not of the specified subclass [com.github.backcamino.emporio.models.GestoreCatalogo] : loaded object was of wrong class class com.github.backcamino.emporio.models.ResponsabileNegozio (through reference chain: com.github.backcamino.emporio.models.Negozio[\"gestoriCatalogo\"])",
    "path": "/negozi/0123456789"
}

非常奇怪的行为是,如果在 Negozio 类中我交换了 Cassiere 和 GestoreCatalogo 的声明顺序,错误消息将包含“GestoreCatalogo”而不是“Cassiere”,只是因为我交换了声明顺序。

这段代码的问题在哪里?

标签: javaspringspring-data-jpaspring-data

解决方案


推荐阅读