代码之家  ›  专栏  ›  技术社区  ›  Kyle Krull

有没有办法为Hibernate托管对象声明最终字段?

  •  22
  • Kyle Krull  · 技术社区  · 16 年前

    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... */
    }
    

    final ,并且必须有一个无参数构造函数,以便Hibernate框架可以实例化该类并设置其字段。

    但事情是这样的-我 只要我能避免,我就不喜欢让我的类以任何方式可变(Java实践:不可变对象是实现这一点的有力理由)。所以 即使我将每个字段声明为“final”,有没有办法让Hibernate工作

    我知道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 注释当然是虚构的,但似乎不应该是遥不可及的。

    6 回复  |  直到 10 年前
        1
  •  13
  •   Tadeusz Kopec for Ukraine yespbs    16 年前

    不可变对象是指没有修改其状态(即其字段)的方法的对象。字段不必是最终字段。因此,您可以删除所有的mutator,并将Hibernate配置为使用字段access而不是accessor,或者您可以将no-arg构造函数和mutator标记为不推荐使用。这有点变通,但总比什么都没有好。

        2
  •  13
  •   C-Otto    9 年前

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

    这一切都是由于对Java1.5内存模型的更改而实现的,这些更改是为了启用序列化/反序列化而进行的(允许final不是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... */
    

    }

        3
  •  8
  •   Robert Munteanu    16 年前

    这听起来似乎不是Hibernate的用例,因为它执行的许多操作都涉及可变状态:

    • 合并对象
    • 脏状态检查
    • 冲洗变化

    也就是说,如果您担心不变性,您可以选择在对象周围提供包装,并使用复制构造函数:

    public class FinalEvent {
        private final Integer id;
    
        public FinalEvent(Event event) {
            id = event.id;
        }
    }
    


    现在我想起来了,hibernate会话通常是线程绑定的,这至少使最终的字段安全发布的一个好处无效。

    你在寻找最终领域的其他好处吗?

        4
  •  4
  •   George    16 年前

    这个问题也困扰了我很长时间。我最近尝试的一个想法是,为模型类定义只读接口,让DAO和任何工厂在对象上返回这些接口。这意味着,即使实现是可变的,但一旦离开DAO/factory对象,就不能再对其进行调整。

    像这样:

    public interface Grape {
      public Color getColor();
    }
    
    public class HibernateGrapeDao {
      public Grape findGrape(int grapeId) {
        HibernateGrape grape = hibernate.find(...
        return grape;
      }
    }
    
    class HibernateGrape implements Grape {
     ....
    }
    

        5
  •  2
  •   Brian Kent    16 年前

    您可以通过使用构建器模式来实现所需的结果。我读了一本书 posting 不久前,在Hibernate论坛上讨论了这个想法(尽管我自己从未实现过…)

        6
  •  0
  •   rogfor    11 年前

    用@Access(AccessType.FIELD)注释类,然后可以将字段设置为最终字段。这样地:

    @Access(AccessType.FIELD)
    public final class Event {
    
        private final Long id;
        private final String title;
        private final Date date;
    
        private Event() {
            id = null;
            title = null;
            date = null;
        }
    
        public Event(Long id, String title, Date date) {
            this.id = id;
            this.title = title;
            this.date = date;
        }
    }