Spring REST Jackson 对象反序列化因休眠注释而失败
Spring REST Jackson Object deserialization fails with hibernate annotations
我已将我的问题缩小到休眠注释和对象反序列化之间的某种交互。我正在使用 spring 引导和休眠将数据存储到 postgres 数据库中。
反序列化由 jackson 完成,所有三个示例都使用有效的 JSON 字符串,看起来有点像:{"id":-1,"alertType":"someType","alertInfos":[{"id":-1,"description":"somedescription"}],...}
我有一个 class 引用另一个 class:
//bi-directional many-to-one association to AlertInfo
@OneToMany(mappedBy="alert", cascade=CascadeType.ALL)
private List<AlertInfo> alertInfos;
反序列化后我会得到:
Template must not be null or empty! (through reference chain: model.ressource.Alert["alertInfos"]->java.util.ArrayList[0])
Note that something decided ArrayList
to be the implementation of the List
interface
如果我删除 hibernate 注释并更改为 ArrayList
:
,反序列化工作正常
//bi-directional many-to-one association to AlertInfo
//@OneToMany(mappedBy="alert", cascade=CascadeType.ALL)
private ArrayList<AlertInfo> alertInfos;
当然,我不能再将它存储到数据库中,因为 hibernate 不知道这种关系。
谁能告诉我为什么选项三行不通?
这留下了甚至不启动应用程序的逻辑选项:
//bi-directional many-to-one association to AlertInfo
@OneToMany(mappedBy="alert", cascade=CascadeType.ALL)
private ArrayList<AlertInfo> alertInfos;
这导致:
Illegal attempt to map a non collection as a @OneToMany, @ManyToMany or @CollectionOfElements: model.ressource.Alert.alertInfos
可能关注的人:AlertInfo.class方面:
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "alert_id")
private Alert alert;
我怎样才能修复最后一个,使其按预期工作?
编辑 1:
请求的实体:
Alert.class
@Entity
@Table(name = "alerts", schema = "ressource_db", uniqueConstraints = { @UniqueConstraint(columnNames = { "id" }) })
@NamedQuery(name = "Alert.findAll", query = "SELECT a FROM Alert a")
public class Alert implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@SequenceGenerator(sequenceName = "ressource_db.id_seq", name = "AlertIdSequence", allocationSize = 1)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "AlertIdSequence")
private Long id;
@Column(name = "original_id")
private String identifier;
@Transient
private String sender;
@Type(type = "org.hibernate.spatial.GeometryType")
@JsonSerialize(using = GeometrySerializer.class)
@JsonDeserialize(using = GeometryDeserializer.class)
private Geometry geometry;
@Column(name = "last_edit_date_time")
private Timestamp lastEditDateTime;
@Column(name = "msg_status")
private String status;
@Column(name = "msg_type")
private String msgType;
@Type(type = "org.hibernate.spatial.GeometryType")
@JsonSerialize(using = GeometrySerializer.class)
@JsonDeserialize(using = GeometryDeserializer.class)
private Point position;
private String scope;
@Column(name = "sent_date_time")
private Timestamp sent;
@Column(name = "version_count")
private Long versionCount;
@Column(name = "alert_msg")
private String alertmsg;
@Column(name = "is_current")
private boolean isCurrent;
// bi-directional many-to-one association to AlertInfo
@OneToMany(mappedBy = "alert", cascade = CascadeType.ALL)
private List<AlertInfo> alertInfos;
public Alert() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getIdentifier() {
return identifier;
}
public void setIdentifier(String identifier) {
this.identifier = identifier;
}
public String getSender() {
return sender;
}
public void setSender(String sender) {
this.sender = sender;
}
public Geometry getGeometry() {
return geometry;
}
public void setGeometry(Geometry geometry) {
this.geometry = geometry;
}
public Timestamp getLastEditDateTime() {
return lastEditDateTime;
}
public void setLastEditDateTime(Timestamp lastEditDateTime) {
this.lastEditDateTime = lastEditDateTime;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getMsgType() {
return msgType;
}
public void setMsgType(String msgType) {
this.msgType = msgType;
}
public Point getPosition() {
return position;
}
public void setPosition(Point position) {
this.position = position;
}
public String getScope() {
return scope;
}
public void setScope(String scope) {
this.scope = scope;
}
public Timestamp getSent() {
return sent;
}
public void setSent(Timestamp sent) {
this.sent = sent;
}
public Long getVersionCount() {
return versionCount;
}
public void setVersionCount(Long versionCount) {
this.versionCount = versionCount;
}
public String getAlertmsg() {
return alertmsg;
}
public void setAlertmsg(String alertmsg) {
this.alertmsg = alertmsg;
}
public boolean isCurrent() {
return isCurrent;
}
public void setCurrent(boolean isCurrent) {
this.isCurrent = isCurrent;
}
public List<AlertInfo> getAlertInfos() {
return this.alertInfos;
}
public void setAlertInfos(List<AlertInfo> alertInfos) {
this.alertInfos = alertInfos;
}
public AlertInfo addAlertInfo(AlertInfo alertInfo) {
if (getAlertInfos() == null) {
this.alertInfos = new ArrayList<AlertInfo>();
}
getAlertInfos().add(alertInfo);
alertInfo.setAlert(this);
return alertInfo;
}
public AlertInfo removeAlertInfo(AlertInfo alertInfo) {
getAlertInfos().remove(alertInfo);
alertInfo.setAlert(null);
return alertInfo;
}
}
AlertInfo.class
@Entity
@Table(name = "alert_infos", schema = "ressource_db", uniqueConstraints = { @UniqueConstraint(columnNames = { "id" }) })
@NamedQuery(name = "AlertInfo.findAll", query = "SELECT a FROM AlertInfo a")
public class AlertInfo implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@SequenceGenerator(sequenceName = "ressource_db.id_seq", name = "AlertInfoIdSequence", allocationSize = 1)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "AlertInfoIdSequence")
private Long id;
@Column(name = "event_category")
private ArrayList<String> category;
@Transient
private String event;
private String urgency;
private String severity;
private String certainty;
@Transient
private List<CapAlertInfoEventCode> eventCodes;
@Transient
private Timestamp effective;
@Transient
private Timestamp expires;
@Transient
private String senderName;
private String headline;
private String description;
// bi-directional many-to-one association to Alert
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "alert_id")
private Alert alert;
public AlertInfo() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getCertainty() {
return certainty;
}
public void setCertainty(String certainty) {
this.certainty = certainty;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getEvent() {
return event;
}
public void setEvent(String event) {
this.event = event;
}
public String getSeverity() {
return severity;
}
public void setSeverity(String severity) {
this.severity = severity;
}
public String getUrgency() {
return urgency;
}
public void setUrgency(String urgency) {
this.urgency = urgency;
}
public List<CapAlertInfoEventCode> getEventCodes() {
return eventCodes;
}
public void setEventCodes(List<CapAlertInfoEventCode> eventCodes) {
this.eventCodes = eventCodes;
}
public Timestamp getEffective() {
return effective;
}
public void setEffective(Timestamp effective) {
this.effective = effective;
}
public Timestamp getExpires() {
return expires;
}
public void setExpires(Timestamp expires) {
this.expires = expires;
}
public String getSenderName() {
return senderName;
}
public void setSenderName(String senderName) {
this.senderName = senderName;
}
public String getHeadline() {
return headline;
}
public void setHeadline(String headline) {
this.headline = headline;
}
public ArrayList<String> getCategory() {
return category;
}
public void setCategory(ArrayList<String> category) {
this.category = category;
}
public Alert getAlert() {
return alert;
}
public void setAlert(Alert alert) {
this.alert = alert;
}
}
显然,最新的 spring 引导版本已不再存在此问题。如果我有这样的注释,它现在可以工作了
@OneToMany(mappedBy = "alert", cascade = CascadeType.ALL, fetch=FetchType.EAGER)
private List<AlertInfo> alertInfos;
我已将我的问题缩小到休眠注释和对象反序列化之间的某种交互。我正在使用 spring 引导和休眠将数据存储到 postgres 数据库中。
反序列化由 jackson 完成,所有三个示例都使用有效的 JSON 字符串,看起来有点像:{"id":-1,"alertType":"someType","alertInfos":[{"id":-1,"description":"somedescription"}],...}
我有一个 class 引用另一个 class:
//bi-directional many-to-one association to AlertInfo
@OneToMany(mappedBy="alert", cascade=CascadeType.ALL)
private List<AlertInfo> alertInfos;
反序列化后我会得到:
Template must not be null or empty! (through reference chain: model.ressource.Alert["alertInfos"]->java.util.ArrayList[0])
Note that something decided
ArrayList
to be the implementation of theList
interface
如果我删除 hibernate 注释并更改为 ArrayList
:
//bi-directional many-to-one association to AlertInfo
//@OneToMany(mappedBy="alert", cascade=CascadeType.ALL)
private ArrayList<AlertInfo> alertInfos;
当然,我不能再将它存储到数据库中,因为 hibernate 不知道这种关系。
谁能告诉我为什么选项三行不通?
这留下了甚至不启动应用程序的逻辑选项:
//bi-directional many-to-one association to AlertInfo
@OneToMany(mappedBy="alert", cascade=CascadeType.ALL)
private ArrayList<AlertInfo> alertInfos;
这导致:
Illegal attempt to map a non collection as a @OneToMany, @ManyToMany or @CollectionOfElements: model.ressource.Alert.alertInfos
可能关注的人:AlertInfo.class方面:
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "alert_id")
private Alert alert;
我怎样才能修复最后一个,使其按预期工作?
编辑 1:
请求的实体:
Alert.class
@Entity
@Table(name = "alerts", schema = "ressource_db", uniqueConstraints = { @UniqueConstraint(columnNames = { "id" }) })
@NamedQuery(name = "Alert.findAll", query = "SELECT a FROM Alert a")
public class Alert implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@SequenceGenerator(sequenceName = "ressource_db.id_seq", name = "AlertIdSequence", allocationSize = 1)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "AlertIdSequence")
private Long id;
@Column(name = "original_id")
private String identifier;
@Transient
private String sender;
@Type(type = "org.hibernate.spatial.GeometryType")
@JsonSerialize(using = GeometrySerializer.class)
@JsonDeserialize(using = GeometryDeserializer.class)
private Geometry geometry;
@Column(name = "last_edit_date_time")
private Timestamp lastEditDateTime;
@Column(name = "msg_status")
private String status;
@Column(name = "msg_type")
private String msgType;
@Type(type = "org.hibernate.spatial.GeometryType")
@JsonSerialize(using = GeometrySerializer.class)
@JsonDeserialize(using = GeometryDeserializer.class)
private Point position;
private String scope;
@Column(name = "sent_date_time")
private Timestamp sent;
@Column(name = "version_count")
private Long versionCount;
@Column(name = "alert_msg")
private String alertmsg;
@Column(name = "is_current")
private boolean isCurrent;
// bi-directional many-to-one association to AlertInfo
@OneToMany(mappedBy = "alert", cascade = CascadeType.ALL)
private List<AlertInfo> alertInfos;
public Alert() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getIdentifier() {
return identifier;
}
public void setIdentifier(String identifier) {
this.identifier = identifier;
}
public String getSender() {
return sender;
}
public void setSender(String sender) {
this.sender = sender;
}
public Geometry getGeometry() {
return geometry;
}
public void setGeometry(Geometry geometry) {
this.geometry = geometry;
}
public Timestamp getLastEditDateTime() {
return lastEditDateTime;
}
public void setLastEditDateTime(Timestamp lastEditDateTime) {
this.lastEditDateTime = lastEditDateTime;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getMsgType() {
return msgType;
}
public void setMsgType(String msgType) {
this.msgType = msgType;
}
public Point getPosition() {
return position;
}
public void setPosition(Point position) {
this.position = position;
}
public String getScope() {
return scope;
}
public void setScope(String scope) {
this.scope = scope;
}
public Timestamp getSent() {
return sent;
}
public void setSent(Timestamp sent) {
this.sent = sent;
}
public Long getVersionCount() {
return versionCount;
}
public void setVersionCount(Long versionCount) {
this.versionCount = versionCount;
}
public String getAlertmsg() {
return alertmsg;
}
public void setAlertmsg(String alertmsg) {
this.alertmsg = alertmsg;
}
public boolean isCurrent() {
return isCurrent;
}
public void setCurrent(boolean isCurrent) {
this.isCurrent = isCurrent;
}
public List<AlertInfo> getAlertInfos() {
return this.alertInfos;
}
public void setAlertInfos(List<AlertInfo> alertInfos) {
this.alertInfos = alertInfos;
}
public AlertInfo addAlertInfo(AlertInfo alertInfo) {
if (getAlertInfos() == null) {
this.alertInfos = new ArrayList<AlertInfo>();
}
getAlertInfos().add(alertInfo);
alertInfo.setAlert(this);
return alertInfo;
}
public AlertInfo removeAlertInfo(AlertInfo alertInfo) {
getAlertInfos().remove(alertInfo);
alertInfo.setAlert(null);
return alertInfo;
}
}
AlertInfo.class
@Entity
@Table(name = "alert_infos", schema = "ressource_db", uniqueConstraints = { @UniqueConstraint(columnNames = { "id" }) })
@NamedQuery(name = "AlertInfo.findAll", query = "SELECT a FROM AlertInfo a")
public class AlertInfo implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@SequenceGenerator(sequenceName = "ressource_db.id_seq", name = "AlertInfoIdSequence", allocationSize = 1)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "AlertInfoIdSequence")
private Long id;
@Column(name = "event_category")
private ArrayList<String> category;
@Transient
private String event;
private String urgency;
private String severity;
private String certainty;
@Transient
private List<CapAlertInfoEventCode> eventCodes;
@Transient
private Timestamp effective;
@Transient
private Timestamp expires;
@Transient
private String senderName;
private String headline;
private String description;
// bi-directional many-to-one association to Alert
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "alert_id")
private Alert alert;
public AlertInfo() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getCertainty() {
return certainty;
}
public void setCertainty(String certainty) {
this.certainty = certainty;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getEvent() {
return event;
}
public void setEvent(String event) {
this.event = event;
}
public String getSeverity() {
return severity;
}
public void setSeverity(String severity) {
this.severity = severity;
}
public String getUrgency() {
return urgency;
}
public void setUrgency(String urgency) {
this.urgency = urgency;
}
public List<CapAlertInfoEventCode> getEventCodes() {
return eventCodes;
}
public void setEventCodes(List<CapAlertInfoEventCode> eventCodes) {
this.eventCodes = eventCodes;
}
public Timestamp getEffective() {
return effective;
}
public void setEffective(Timestamp effective) {
this.effective = effective;
}
public Timestamp getExpires() {
return expires;
}
public void setExpires(Timestamp expires) {
this.expires = expires;
}
public String getSenderName() {
return senderName;
}
public void setSenderName(String senderName) {
this.senderName = senderName;
}
public String getHeadline() {
return headline;
}
public void setHeadline(String headline) {
this.headline = headline;
}
public ArrayList<String> getCategory() {
return category;
}
public void setCategory(ArrayList<String> category) {
this.category = category;
}
public Alert getAlert() {
return alert;
}
public void setAlert(Alert alert) {
this.alert = alert;
}
}
显然,最新的 spring 引导版本已不再存在此问题。如果我有这样的注释,它现在可以工作了
@OneToMany(mappedBy = "alert", cascade = CascadeType.ALL, fetch=FetchType.EAGER)
private List<AlertInfo> alertInfos;