有没有办法为休眠管理的对象声明最终字段?

2022-09-01 17:15:07

我刚刚开始使用Hibernate,到目前为止我看到的所有示例看起来都非常像Hibernate文档中的教程:

package org.hibernate.tutorial.domain;
import java.util.Date;

public class Event {

    private Long id;
    private String title;
    private Date date;

    public Event() {}

    /* Accessor methods... */
}

具体来说:没有一个字段被声明为 ,并且必须有一个无参数构造函数,以便 Hibernate 框架可以实例化类并设置其字段。final

但事情就是这样 - 我真的不喜欢在我可以避免的时候以任何方式使我的类可变(Java实践:不可变对象为这样做提供了一个非常有力的论据)。那么,有没有办法让Hibernate工作,即使我宣布每个字段都是“final”的呢

我知道Hibernate使用Reflerated来实例化其类,因此需要能够调用某种类型的构造函数,而不会冒着选择错误的构造函数或将错误的值传递给其参数之一的风险,因此调用no-arg构造函数并一次设置一个字段可能更安全。但是,难道不应该向Hibernate提供必要的信息,以便它可以安全地实例化不可变对象吗?

public class Event {

    private final Long id;
    private final String title;
    private final Date date;

    public Event(@SetsProperty("id") Long id,
        @SetsProperty("title") String title,
        @SetsProperty("date") Date date) {

        this.id = id;
        this.title = title;
        this.date = new Date(date.getTime());
    }

    /* Accessor methods... */
}

注释当然是虚构的,但似乎不应该遥不可及。@SetsProperty


答案 1

实际上,在JDK 1.5+中,休眠可以处理(通过反射)更改最终字段。创建一个受保护的默认构造函数(),将字段设置为一些默认值/null等...休眠可以并且将在实例化对象时覆盖这些值。

这一切都是可能的,这要归功于对Java 1.5内存模型的更改 - 感兴趣的更改(允许final不是那么最终的)在启用序列化/反序列化的地方。

public class Event {

private final Long id;
private final String title;
private final Date date;

// Purely for serialization/deserialization
protected Event() {
    id = null;
    title = null;
    date = null;
}

public Event(Long id, String title, Data date) {
    this.id = id;
    this.title = title;
    this.date = date;
}

/* Accessor methods... */

}


答案 2

不可变对象是指没有修改其状态(即其字段)的方法的对象。字段不必是最终的。因此,您可以删除所有赋值函数并将 Hibernate 配置为使用字段访问而不是访问器,或者只需将 no-arg 构造函数和赋值函数标记为已弃用。这是一个有点解决方法,但总比没有好。


推荐