In most applications, it is necessary to generate universally a unique object ID. Often, this information which is used like primary key in database, is generated via an Oracle sequencer or procedure. And its value is not really predictable. So, here, an simple solution used in an application with a layer ORM (object-relational mapping) like Hibernate:

First, it’s singleton ID generator class:

import java.util.UUID;

public class IdGenerator {

    public static String createId() {
        UUID uuid = java.util.UUID.randomUUID();
        return uuid.toString();
    }
}

This class returns IDs with values:

dde70a56-c67d-47cb-8c0f-5e12f9b9595f
22bf5545-ceb3-454c-8e71-b11198c16bcc
a8d7f70f-6f3c-49af-8def-396d1f19465d

More, the previous generator is used in an abstract class whose inherits the POJO class used in the ORM layer:

public abstract class AbstractPersistentObject {
    private String id = IdGenerator.createId();
    private Integer version = null;

    [...]
}

So, the Id information is always initialized from the object’s creation.

Finally, the POJO class extends this abstract class:

public class Document extends AbstractPersistentObject {

    private int num;
    private int year;
    private String type = null;
    [...]
}

The HBM file corresponding to the Document POJO persistence class “Document.hbm.xml”:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class table="Document" name="com.ho.data.production.Document" discriminator-value="Document">
        <id name="id" column="c_id" type="string"><generator class="assigned" /></id>
        <discriminator column="class" type="java.lang.String"/>
        <version name="version" column="c_version" unsaved-value="null" />
        <property unique="true" not-null="true" column="c_num" type="int" name="num"/>
        <property not-null="true" column="c_year" type="int" name="year"/>
        <property column="c_type" type="java.lang.String" name="type"/>
    </class>
</hibernate-mapping>

To conclude with this simple post/example, here, the classes used in ORM layer in order to take into account the fact that the ID information is always initialized:

The class DAO used in ORM layer:

@Repository("documentDao")
@Scope("singleton")
public class DocumentDaoHibernateImpl extends GenericDaoImpl<Document, String> implements DocumentDao {

	@Autowired
	public DocumentDaoHibernateImpl(@Qualifier("sessionFactory") SessionFactory sessionFactory) {
		super(sessionFactory, Document.class);
	}
	[...]
}
public interface DocumentDao extends GenericDao<Document, String> {

	[...]
}
import java.io.Serializable;
import java.util.List;

public interface GenericDao<T, PK extends Serializable> {
	PK create(T persistentObject);

	T get(PK id);

	List<T> getAll();

	void update(T persistentObject);
	
	void createOrUpdate(T persistentObject);

	void delete(T persistentObject);
}

The generic component ‘GenericDaoImpl’:

import java.io.Serializable;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.Hibernate;
import org.hibernate.SessionFactory;
import org.hibernate.proxy.HibernateProxy;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Transactional(propagation=Propagation.MANDATORY)
public class GenericDaoImpl<T, PK extends Serializable> extends HibernateDaoSupport implements GenericDao<T, PK> {


	//private SessionFactory sessionFactory;
	private Class<T> type;

	public GenericDaoImpl(SessionFactory sessionFactory, Class<T> type) {
		super.setSessionFactory(sessionFactory);
		this.type = type;
	}

//	public GenericDaoImpl(Class<T> type) {
//		this.type = type;
//	}

	@SuppressWarnings("unchecked")
	public PK create(T o) {
		return (PK) getSession().save(o);
	}

	@SuppressWarnings("unchecked")
	@Transactional(propagation=Propagation.REQUIRED, readOnly=true)
	public T get(PK id) {
		T value = (T) getSession().get(type, id);
		if (value == null) {
            return null;
        }

        if (value instanceof HibernateProxy) {
			Hibernate.initialize(value);
	        value = (T) ((HibernateProxy) value).getHibernateLazyInitializer().getImplementation();
        }
        return value;
		//return (T) getSession().get(type, id);
	}

	@SuppressWarnings("unchecked")
	@Transactional(propagation=Propagation.REQUIRED, readOnly=true)
	public List<T> getAll() {
		Criteria crit = getSession().createCriteria(type);
		return crit.list();
	}
	
	public void createOrUpdate(T o) {
		//Sometimes, if createOrUpdate be called with proxy then uncomment this part
//		Class clazz = null;
//        if (o instanceof HibernateProxy) {
//        	clazz = ((HibernateProxy) o).getHibernateLazyInitializer().getImplementation().getClass();
//        } else {
//        	clazz = o.getClass();
//        }
//		if (clazz.isInstance(AbstractPersistentObject.class)) {
//			if (((AbstractPersistentObject) o).isCreation()) {
//				getSession().saveOrUpdate(o);
//			} else {
//				getSession().merge(o);
//			}
//		} else {
//			throw new RuntimeException("this method support only AbstractPersistentObject");
//		}
		
		if (o instanceof AbstractPersistentObject) {
			if (((AbstractPersistentObject) o).isCreation()) {
				getSession().saveOrUpdate(o);
			} else {
				getSession().merge(o);
			}
		} else {
			throw new RuntimeException("this method support only AbstractPersistentObject");
		}
		
		
		//getSession().saveOrUpdate(o);
	}


	public void update(T o) {
		getSession().update(o);
	}

	public void delete(T o) {
		getSession().delete(o);
	}

//	public Session getSession() {
//		boolean allowCreate = true;
//		return SessionFactoryUtils.getSession(sessionFactory, allowCreate);
//	}
//
//	public void setSessionFactory(SessionFactory sessionFactory) {
//		this.sessionFactory = sessionFactory;
//	}
}

Best regards,

Huseyin OZVEREN