Skip navigation

Monthly Archives: December 2008

I was trying to make an alternative of @MappedSuperclass using Hibernate XML (*.hbm.xml) files. The case is i want every persistent class have default column like ID, CREATED_ON, CREATED_BY, UPDATED_ON, UPDATED_BY – that reside on a superclass, so i don’t have to repeat those column in every mapping files. Unfortunately, basically hibernate do not support this kind of superclass mapping. Maybe the technique here will do just fine, but lack of something that i will tell later.

Nowaday programming style is coding by interface so i use interface for every persistent class and separate it’s implementation. The relationship is one-to-many between Singer and Album.

Here is BaseModel interface that every persistent class will inherits all the properties, followed by it’s concrete class and mapping:
(BaseModel.java)

package hibernate.example.model;

import java.util.Date;

public interface BaseModel {
    public Integer getId();
    public void setId(Integer id);
    public String getCreatedBy();
    public void setCreatedBy(String createdBy);
    public Date getCreatedOn();
    public void setCreatedOn(Date createdOn);
    public String getUpdatedBy();
    public void setUpdatedBy(String updatedBy);
    public Date getUpdatedOn();
    public void setUpdatedOn(Date updatedOn);
    public String getName();
    public void setName(String name);
}

(BaseModelImpl.java)

package hibernate.example.model;

import java.util.Date;

public class BaseModelImpl implements BaseModel {
    private Integer id;
    private String createdBy;
    private Date createdOn;
    private String updatedBy;
    private Date updatedOn;
    private String name;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getCreatedBy() {
        return createdBy;
    }

    public void setCreatedBy(String createdBy) {
        this.createdBy = createdBy;
    }

    public Date getCreatedOn() {
        return createdOn;
    }

    public void setCreatedOn(Date createdOn) {
        this.createdOn = createdOn;
    }

    public String getUpdatedBy() {
        return updatedBy;
    }

    public void setUpdatedBy(String updatedBy) {
        this.updatedBy = updatedBy;
    }

    public Date getUpdatedOn() {
        return updatedOn;
    }

    public void setUpdatedOn(Date updatedOn) {
        this.updatedOn = updatedOn;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

(BaseModel.hbm.xml)

<hibernate-mapping package="hibernate.example.model">
    <class name="BaseModel" abstract="true">
        <id name="id" type="integer" column="ID">
            <generator class="increment"/>
        </id>
       <property name="createdBy" type="string" column="CREATED_BY"/>
       <property name="createdOn" type="timestamp" column="CREATED_ON"/>
       <property name="updatedBy" type="string" column="UPDATED_BY"/>
       <property name="updatedOn" type="timestamp" column="UPDATED_ON"/>
       <property name="name" type="string" column="NAME"/>
    </class>
</hibernate-mapping>

Singer Entity:
(Singer.java)

package hibernate.example.model;

import java.util.Set;

public interface Singer extends BaseModel {
    public Set<Album> getAlbums();
    public void setAlbums( Set<Album> albums );
}

(SingerImpl.java)

package hibernate.example.model;

import java.util.Set;

public class SingerImpl extends BaseModelImpl implements Singer {
    private Set<Album> albums;

    public SingerImpl() {}

    public Set<Album> getAlbums() {
        return albums;
    }

    public void setAlbums(Set<Album> albums) {
        this.albums = albums;
    }
}

(Singer.hbm.xml)

<hibernate-mapping package="hibernate.example.model">
    <union-subclass name="Singer" extends="BaseModel" abstract="true">
        <set name="albums" inverse="true" cascade="all-delete-orphan">
            <key column="ID_SINGER"/>
            <one-to-many class="Album"/>
        </set>
    </union-subclass>

    <union-subclass name="SingerImpl" extends="Singer" table="SINGER"/>
</hibernate-mapping>

Album Entity:
(Album.java)

package hibernate.example.model;

public interface Album extends BaseModel {
    public String getYear();
    public void setYear(String year);
    public Singer getSinger();
    public void setSinger(Singer singer);
}

(AlbumImpl.java)

package hibernate.example.model;

public class AlbumImpl extends BaseModelImpl implements Album {
    private Singer singer;
    private String year;

    public Singer getSinger() {
        return singer;
    }

    public void setSinger(Singer singer) {
        this.singer = singer;
    }

    public String getYear() {
        return year;
    }

    public void setYear(String year) {
        this.year = year;
    }
}

(Album.hbm.xml)

<hibernate-mapping package="hibernate.example.model">
    <union-subclass name="Album" extends="BaseModel" abstract="true">
        <property name="year" type="string" column="YEAR" />

        <many-to-one name="singer" column="ID_SINGER"
            class="Singer" not-null="true" />

    </union-subclass>

    <union-subclass name="AlbumImpl" extends="Album" table="ALBUM" />
</hibernate-mapping>

Here is hibernate.cfg.xml:

<hibernate-configuration>
  <session-factory>
<!--    <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/SCHEMA_NAME</property>
    <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
    <property name="hibernate.connection.username">username</property>
    <property name="hibernate.connection.password">password</property>
    <property name="dialect">org.hibernate.dialect.MySQL5Dialect</property>
-->
    <property name="hibernate.connection.url">jdbc: oracle:thin:@localhost:1521:SID</property>
    <property name="hibernate.connection.driver_class">oracle.jdbc.driver.OracleDriver</property>
    <property name="hibernate.connection.username">username</property>
    <property name="hibernate.connection.password">password</property>
    <property name="dialect">org.hibernate.dialect.Oracle10gDialect</property>

    <!-- DB schema will be updated if needed -->
    <property name="hibernate.hbm2ddl.auto">update</property>

    <mapping resource="hibernate/example/model/BaseModel.hbm.xml" />
    <mapping resource="hibernate/example/model/Singer.hbm.xml" />
    <mapping resource="hibernate/example/model/Album.hbm.xml" />
  </session-factory>
</hibernate-configuration>

Simple test application can look like this:
(TestApp.java)

package hibernate.example.test;

import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import hibernate.example.model.Singer;
import hibernate.example.model.SingerImpl;
import hibernate.example.model.Album;
import hibernate.example.model.AlbumImpl;

import java.util.Date;

public class TestApp {
    private Session session;
    private Transaction tx;

    public TestApp() {
        SessionFactory sessionFac = new Configuration().configure().buildSessionFactory();
        session = sessionFac.openSession();
    }

    public static void main(String args[]) {
        TestApp app = new TestApp();
        app.insertSinger();
        app.insertAlbum();
    }

    // insertSinger
    public void insertSinger() {
        Singer singer = new SingerImpl();
        singer.setCreatedOn( new Date() );
        singer.setCreatedBy( "admin" );
        singer.setName( "Mariah Carey" );

        tx = session.beginTransaction();
        session.save( singer );
        tx.commit();
    }

    // insertAlbum
    public void insertAlbum() {
        Singer singer = (SingerImpl) session.get( SingerImpl.class, 1 );

        Album album = new AlbumImpl();
        album.setCreatedOn( new Date() );
        album.setCreatedBy( "admin" );
        album.setName( "Rainbow" );
        album.setYear( "2000" );
        album.setSinger( singer );

        tx = session.beginTransaction();
        session.save( album );
        tx.commit();
    }
}

Result table will look like:
– Singer table
Singer table
– Album table
Album table

Here or here is full source code. Change *.odt to *.zip, then extract it. Edit hibernate.cfg.xml to match your environtment, and add required library to lib folder.

Dependency Library:
depandency's

NOTE :
Using <union-subclass> Hibernate still treat the mapping as table per concrete class. Every id’s for each persistent class will use the same generated id. And also in Oracle database it doesn’t create Singer foreign key constraint on Album table, so if we dropped Singer table it doesn’t make constraint violation error.

Advertisements