java - 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”,只是因为我交换了声明顺序。
这段代码的问题在哪里?
解决方案
推荐阅读
- x509certificate - Hashicorp Vault - 外部证书管理
- sass - Sass:背景位置如何在背景尺寸过大的悬停效果中工作
- html - 视频上的按钮叠加
- r - 基于离散值的阴影颜色(更改“亮度”)
- php - php artisan migrate-laravel 的问题
- excel - Excel Vba如何避免重复迭代文件夹
- kubernetes-helm - Helm 图表标签和选择器
- sql - 查询插入行号以对结果进行分页
- javascript - 捕获设备位置时在导航器地理定位中找不到高度参数需要知道使用什么传感器来检测位置 GPS/Wifi
- list - 关闭 nats 列表上的引理