Version 2

    Hibernate doesn't require that persistent classes extend a base class. That is not meant to imply that its necessarily a bad thing. You might like to consider defining a base class for your application's persistent classes. For example, the following base class implements the "Active Record" pattern:

    public class Persistent implements Lifecycle, Validatable, Serializable {
       
       protected Serializable _id;
       protected int _version;
    
       public Serializable getIdentifier() {
          return _id;
       }
       public void setIdentifier(Serializable id) {
          _id = id;
       }
       public int getVersion() {
          return _version;
       }
       public void setVersion(int version) {
          _version = version;
       }
    
       public Long persist() throws HibernateException, SQLException {
          HibernateSession.currentSession().saveOrUpdate(this);
          return _id;
       }
       public void delete() throws HibernateException, SQLException {
          HibernateSession.currentSession().delete(this);
       }
       public void refresh() throws HibernateException, SQLException {
          HibernateSession.currentSession().load(this, _id);
       }
       public void lock() throws HibernateException, SQLException {
          HibernateSession.currentSession().lock(this, LockMode.UPGRADE);
       }
    
       public boolean onSave(Session s) throws CallbackException {
          return NO_VETO;
       }
       public boolean onDelete(Session s) throws CallbackException {
          return NO_VETO;
       }
       public boolean onUpdate(Session s) throws CallbackException {
          return NO_VETO;
       }
       public void onLoad(Session s, Serializable id) {
          _id = id;
       }
    
       public void validate() throws ValidationFailure {
       }
    }
    

     

    This implementation uses the HibernateSession class described in Sessions and transactions.

    Now Lizard inherits Persistent:

    public class Lizard extends Persistent {
    
        private float _bodyTemperature;
        private float _weight;
    
        public float getBodyTemperature() { return _bodyTemperature; }
        public void setBodyTemperature(float bodyTemperature) {
            _bodyTemperature = bodyTemperature;
        }
        public float getWeight() { return _weight; }
        public void setWeight(float weight{
            _weight = weight
        }
    
       public void validate() throws ValidationFailure {
           if (_weight<0) throw new ValidationFailure("negative weight");
       }
    }
    

     

    And is mapped as follows

    <class name="Lizard" table="LIZARDS"/>
        <id name="id" unsaved-value="null">
            <generator class="hilo"/>
        </id>
        <version name="version"/>
        <property name="bodyTemperature"/>
        <property name="weight"/>
    </class>
    

    Here's a variation that forces the developer to perform a version check before updating an object. This implementation might be useful with the application version checking approach described in the documentation. (As opposed to Hibernate's automatic version checking.)

    The "application version checking" approach is where we

    • Load an object in the first transaction and copy its properties (but not the object itself) into the UI layer (using a Data Transfer Object, for example)
    • Modify the copied properties from the UI
    • Reload the object in a new transaction and copy the modified properties "back" to the object

     

    This is typical of any application that manages critical data, such as online banking transactions, where data integrity is vital. Hibernate's built-in version checking is obviously a must, but this additional check ensures the integrity of any data that may have been updated while the end-user was entering changes.

    public class Persistent implements Lifecycle, Validatable, Serializable {
       
       protected Long _id;
       protected int _version;
       protected boolean _versionCheckRequired;
    
       public Long getIdentifier() {
          return _id;
       }
       public void setIdentifier(Long id) {
          _id = id;
       }
       public int getVersion() {
          return _version;
       }
       public void setVersion(int version) {
          _version = version;
       }
    
       public Long persist() throws HibernateException, SQLException {
          HibernateSession.currentSession().saveOrUpdate(this);
          return _id;
       }
       public void delete() throws HibernateException, SQLException {
          HibernateSession.currentSession().delete(this);
       }
       public void refresh() throws HibernateException, SQLException {
          HibernateSession.currentSession().load(this, _id);
       }
       public void lock() throws HibernateException, SQLException {
          HibernateSession.currentSession().lock(this, LockMode.UPGRADE);
       }
       public void checkVersion(int version) throws StaleObjectException {
          if (version != _version) {
             throw new StaleObjectException();
          }
          _versionCheckRequired = false;
       }
    
       public boolean onSave(Session s) throws CallbackException {
          return NO_VETO;
       }
       public boolean onDelete(Session s) throws CallbackException {
          return NO_VETO;
       }
       public boolean onUpdate(Session s) throws CallbackException {
          return NO_VETO;
       }
       public void onLoad(Session s, Serializable id) throws CallbackException {
          _versionCheckRequired = true;
          onLoad(s, (Long) id);
       }
       protected void onLoad(Session s, Long id) throws CallbackException {
       }
    
       public void validate() throws ValidationFailure {
          if (_versionCheckReqired) {
             throw new ValidationFailure("version check is required");
          }
       }
    }
    

     

    One consequence of this pattern is that all of your Persistent subclasses, and all of the business logic that uses them, are tightly coupled to Hibernate via the HibernateException thrown throughout.  This can make it very difficult to move away from Hibernate to a different persistence framework.