101: Spring + Hibernate Entity Manager

Here is a short description on setting up a Spring with Hibernate Entitymanger (JPA) application.

I am asuming that you have a project structure ready

Step 1:

Create jpa configuration file:
repository-jpa.xml

<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
         <property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" />

<bean id="entityManagerFactory"
		class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
		<property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
		<property name="dataSource" ref="dataSource" />
		<property name="persistenceUnitName" value="osm" />
		<property name="jpaProperties">
			<props>
				<prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
			</props>
		</property>
	</bean>
<bean id="jpaVendorAdapter"
		class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
		<property name="showSql" value="false" />
		<property name="generateDdl" value="false" />
		<property name="databasePlatform" value="${database.platform}" />
	</bean>
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
		<property name="jndiName" value="jdbc/nameDS" />
		<property name="resourceRef" value="true" />
	</bean>

NOTE: values like database.platform come from .properties i.e. a resource file
Example:

# DataSource Properties

database.platform=org.hibernate.dialect.Oracle10gDialect
database.driver=oracle.jdbc.driver.OracleDriver
database.url=jdbc:oracle:thin:@localhost:1521:xe
database.user=sa
database.password=sa
hibernate.hbm2ddl.auto=validate

This file is loaded as a resource:
configuration.xml

<bean id="gmPropertyConfigurer"
		class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
		<property name="locations">
			<list>
				<value>database.properties</value>
			</list>
		</property>
	</bean>

Step 2:
You can create DAO / JPA classes. Here is a sample class I am using:
It is always a good idea to write a generic inteface for such classes

public interface IGenericRepository<E> {
	void persist( E entity );

	E merge( E entity );

	void remove( E entity );

	E findById( Long id );

	void executeQuery( String strQuery );

	List <E> executeNativeQuery( String strQuery );
	
	EntityManager getEntityManager();

}

My concrete class:


@Transactional
@Repository
public class JpaGenericRepository<E> implements IGenericRepository <E> {

	private Class <E> entityClass;

	@PersistenceContext
	private EntityManager entityManager;

	@SuppressWarnings("unchecked")
	public JpaGenericRepository() {

		// Get "E" and assign it to this.entityClass
		ParameterizedType genericSuperclass = (ParameterizedType) getClass().getGenericSuperclass();
		java.lang.reflect.Type type = genericSuperclass.getActualTypeArguments()[0];
		if( type instanceof Class ) {
			this.entityClass = (Class <E>) type;
		} else if( type instanceof ParameterizedType ) {
			this.entityClass = (Class <E>) ((ParameterizedType) type).getRawType();
		}

	}

	@Override
	@Transactional(propagation = Propagation.REQUIRES_NEW)
	public void persist( E entity ) {
		entityManager.persist(entity);
		int i =1/0;
	}

	@Override
	@Transactional(propagation = Propagation.REQUIRES_NEW)
	public E merge( E entity ) {
		entity = entityManager.merge(entity);
		return entity;
	}

	@Override
	@Transactional(propagation = Propagation.REQUIRES_NEW)
	public void remove( E entity ) {
		entityManager.remove(entityManager.contains(entity) ? entity : entityManager.merge(entity));
	}

	@Override
	public E findById( Long id ) {
		return entityManager.find(entityClass, id);
	}

	@Override
	@Transactional(propagation = Propagation.REQUIRES_NEW, timeout = 180)
	public void executeQuery( String strQuery ) {
		Query query = entityManager.createNativeQuery(strQuery, entityClass);
		query.executeUpdate();
	}

	@Override
	@Transactional
	public List <E> executeNativeQuery( String strQuery ) {
		Query query = entityManager.createNativeQuery(strQuery, entityClass);
		@SuppressWarnings("unchecked")
		List <E> rs = query.getResultList();
		return rs;
	}

	@Override
	public EntityManager getEntityManager() {
		return entityManager;
	}

}

Repository class as a service


public class JpaProductRepository extends JpaGenericRepository <Product> implements IProductRepository {

}

Now create an xml which has bean definations for the JpaProductRepository:
repository.xml


<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-2.0.xsd"

	default-lazy-init="false" default-dependency-check="none">

		<bean id="productRepositry"
		class="com.gide.csolp.osm.service.repository.jpa.JpaProductRepository" />

</beans>

That is preety much it!

If you have are developing a web application, then your application should load these xml’s via web.xml.

If you are creating a stand alone application you can uses any of the classes to load the application context.

Example application context:

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:lang="http://www.springframework.org/schema/lang"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="
		http://www.springframework.org/schema/lang 
		http://www.springframework.org/schema/lang/spring-lang-2.5.xsd
		http://www.springframework.org/schema/beans 
		http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
		http://www.springframework.org/schema/context 
		http://www.springframework.org/schema/context/spring-context-2.5.xsd"

	default-lazy-init="false" default-dependency-check="none">
	<import resource="classpath:/META-INF/spring/repository.xml" />
	<import resource="classpath:/META-INF/springtest/configuration.xml" />
	<import resource="classpath:/META-INF/springtest/repository-jpa.xml" />
</beans>