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;