У меня есть приложение Spring Boot, которое использует Spring JPA.
У меня есть следующие классы:
Negozio
@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;
}
Cassiere
@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;
}
}
ResponsabileNegozio
@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;
}
}
На самом деле я могу зарегистрировать нового Negozio через репозиторий JPA, но когда я получаю этого Negozio по его ID для возврата это в контроллере отдыха, у меня есть следующее исключение:
{
"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 и GestoreCatalo go, сообщение об ошибке будет содержать «GestoreCatalo go» вместо «Cassiere» только потому, что я поменял порядок декларации.
В чем проблема этого кода?