Spring 3: Implement CRUD pattern using JPA Dao support

11 10 2011

In this blog I’m going to implement spring jpa using eclipleLink.
First of all add the following snippet to your pom.xml

<dependencies>
  <dependency>
    <groupId>org.eclipse.persistence</groupId>
    <artifactId>eclipselink</artifactId>
    <version>2.0.0</version>
    <scope>compile</scope>
       ...
  </dependency>
</dependencies>
      ...
<repositories>
  <repository>
     <id>EclipseLink Repo</id>
     <url>http://www.eclipse.org/downloads/download.php?r=1&nf=1&file=/rt/eclipselink/maven.repo</url>
     <!-- use this for javax.persistence
     <snapshots>
        <enabled>true</enabled>
     </snapshots> -->
  </repository>    
      ...
 

After I copied all classes generated through hibernate in a package named com.biancama.spring3.model.eclipselink.
I’ve done that because date fileds must be annoted with @Temporal
So I create a structure of classes to have CRUD functionality

package com.biancama.spring3.dao;

import java.io.Serializable;

public interface CRUDAccess <K extends Serializable, E> {

	public K getKey(E entity);

	public E merge(E entity);

	public void persist(E entity);

	public void remove(E entity);

	public E findById(K id);

}

package com.biancama.spring3.dao.eclipselink;

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

import org.eclipse.persistence.expressions.Expression;
import org.eclipse.persistence.queries.DatabaseQuery;
import org.eclipse.persistence.queries.ReadAllQuery;

import com.biancama.spring3.dao.CRUDAccess;

public interface EclipseLinkCrudAccess<K extends Serializable, E> extends
		CRUDAccess<K, E> {

	List<E> executeNamedQuery(String queryName, Map<String, Object> parameterMap);

	List<E> executeNamedQuery(String queryName);

	int getCount(String countField, Expression expr);

	List<E> executeReadAllQuery(ReadAllQuery readAllQuery, int first, int rows);

	List<E> executeDatabaseQuery(DatabaseQuery q);

	int deleteById(K id);
}

package com.biancama.spring3.dao.eclipselink;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;

import javax.persistence.Query;

import org.eclipse.persistence.expressions.Expression;
import org.eclipse.persistence.jpa.JpaEntityManager;
import org.eclipse.persistence.queries.DatabaseQuery;
import org.eclipse.persistence.queries.ReadAllQuery;
import org.eclipse.persistence.queries.ReportQuery;
import org.eclipse.persistence.queries.ReportQueryResult;
import org.eclipse.persistence.sessions.Session;
import org.springframework.orm.jpa.support.JpaDaoSupport;
import org.springframework.stereotype.Repository;

@Repository
public abstract class EclipseLinkCrudAccessAbstractJPASupport<K extends Serializable, E>
		extends JpaDaoSupport implements EclipseLinkCrudAccess<K, E> {

	private final Class<E> persistentClass;

	protected EntityManager entityManager;
	
	@SuppressWarnings("unchecked")
	public EclipseLinkCrudAccessAbstractJPASupport() {
		this.persistentClass = (Class<E>) ((ParameterizedType) getClass()
				.getGenericSuperclass()).getActualTypeArguments()[1];
	}

	protected Class<E> getEntityClass() {
		return persistentClass;

	}

	@Override
	public E merge(E entity) {
		return getJpaTemplate().merge(entity);
	}

	@Override
	public void persist(E entity) {
		getJpaTemplate().persist(entity);
	}

	@Override
	public void remove(E entity) {
		getJpaTemplate().remove(entity);
	}

	@Override
	public E findById(K id) {
		return getJpaTemplate().find(getEntityClass(), id);
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<E> executeNamedQuery(String queryName,
			Map<String, Object> parameterMap) {
		Query query = getJpaTemplate().getEntityManager().createNamedQuery(
				queryName);
		if (parameterMap != null) {
			for (String param : parameterMap.keySet()) {
				query.setParameter(param, parameterMap.get(param));
			}
		}
		return query.getResultList();
	}

	@Override
	public List<E> executeNamedQuery(String queryName) {
		return executeNamedQuery(queryName, null);
	}

	@SuppressWarnings("unchecked")
	@Override
	public int getCount(String countField, Expression expr) {
		ReportQuery query = new ReportQuery(getEntityClass(), null);
		query.setSelectionCriteria(expr);
		query.addCount("count", query.getExpressionBuilder().get(countField)
				.distinct());

		List<ReportQueryResult> result = (List<ReportQueryResult>) getSession()
				.executeQuery(query);
		ReportQueryResult reportQueryResult = result.get(0);
		BigDecimal count = (BigDecimal) reportQueryResult.getResults().get(0);
		return count.intValueExact();

	}

	protected Session getSession() {
			if (entityManager == null) {
			entityManager = getJpaTemplate().getEntityManagerFactory()
					.createEntityManager();
		}
		return ((JpaEntityManager) entityManager.getDelegate())
				.getActiveSession();
	}

	@Override
	public List<E> executeReadAllQuery(ReadAllQuery readAllQuery, int first,
			int rows) {
		readAllQuery.setFirstResult(first);
		readAllQuery.setMaxRows(first + rows);

		return executeDatabaseQuery(readAllQuery);
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<E> executeDatabaseQuery(DatabaseQuery q) {
		List<E> resultList = (List<E>) getSession().executeQuery(q);
		return resultList;
	}

}
package com.biancama.spring3.dao.eclipselink;

import com.biancama.spring3.model.eclipselink.Employees;

public interface EmployeesDao extends EclipseLinkCrudAccess<Integer, Employees> {

}

package com.biancama.spring3.dao.eclipselink;

import javax.persistence.Query;

import com.biancama.spring3.model.eclipselink.Employees;

public class EmployeesDaoJpaDaoSupportImpl extends
		EclipseLinkCrudAccessAbstractJPASupport<Integer, Employees> implements
		EmployeesDao {

	@Override
	public int deleteById(Integer id) {

		Query q = getJpaTemplate().getEntityManager().createQuery(
				"delete from Employees where employeeId = :id");
		q.setParameter("id", id);
		return q.executeUpdate();
	}

	@Override
	public Integer getKey(Employees entity) {
		return entity.getEmployeeId();
	}

}

I created META-INF/persistence.xml

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0"
	xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
 <persistence-unit name="hr" >
     	<class>com.biancama.spring3.model.eclipselink.Countries</class>
        <class>com.biancama.spring3.model.eclipselink.Departments</class>
        <class>com.biancama.spring3.model.eclipselink.EmpDetailsView</class>
        <class>com.biancama.spring3.model.eclipselink.Employees</class>
        <class>com.biancama.spring3.model.eclipselink.JobHistory</class>
        <class>com.biancama.spring3.model.eclipselink.Jobs</class>
        <class>com.biancama.spring3.model.eclipselink.Locations</class>
        <class>com.biancama.spring3.model.eclipselink.Regions</class>  
<exclude-unlisted-classes>true</exclude-unlisted-classes>
 </persistence-unit>
<properties>
 	 	<property name="eclipselink.weaving" value="false"/>	
 	</properties>
 
</persistence>

And finally I injected all the classes with

<?xml version="1.0" encoding="UTF-8"?>

<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">
 
   <!-- Tells Spring how to convert JPA-specific exceptions
       to Spring data exceptions for classes that are annotated
       with @Repository. -->
  <bean class=
      "org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>

  <!-- Tells Spring to inject the entity manager into
       DAO classes with a @PersistenceContext annotation
       placed on a setEntityManager() method. -->
  <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
  
  <bean id="jpaTemplate"
      class="org.springframework.orm.jpa.JpaTemplate">
    <property name="entityManagerFactory" ref="entityManagerFactory" />
  </bean>
       
	
	<bean id="entityManagerFactory" 
      class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">

	    <property name="dataSource" ref="dataSource" />
	   <!--   
	    <property name="loadTimeWeaver">
	      <bean class="org.springframework.instrument.classloading.SimpleLoadTimeWeaver" /> 
	    </property>
	-->
	    <property name="jpaVendorAdapter">
	    	<bean class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter">
		        <property name="databasePlatform" value="org.eclipse.persistence.platform.database.OraclePlatform" />
        		<property name="generateDdl" value="false" />
        		<property name="showSql" value="true" />
    		</bean>
	    </property>
	    <property name="persistenceUnitName" value="hr" />
        <property name="persistenceProviderClass" value="org.eclipse.persistence.jpa.PersistenceProvider" />
    </bean>
	<bean id="transactionManager" 
      class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory"
        ref="entityManagerFactory" />
  </bean>

  <!-- 
    DAO Beans
   -->  
  <bean id="employeeDao" class="com.biancama.spring3.dao.eclipselink.EmployeesDaoImpl">
   	<property name="jpaTemplate" ref="jpaTemplate" />
  </bean>

</beans>

a test unit class could be

package com.biancama.spring3.dao.eclipselink;

import static org.junit.Assert.assertTrue;

import java.util.List;

import javax.annotation.Resource;

import org.eclipse.persistence.expressions.ExpressionBuilder;
import org.eclipse.persistence.queries.ReadAllQuery;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.biancama.spring3.model.eclipselink.Employees;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:spring3-data-local.xml",
		"classpath:spring-data-eclipseLinkJPADaoSupport.xml" })
public class EmployeesDaoTestUsingJpaSupport extends
		AbstractTransactionalJUnit4SpringContextTests {

	@Resource
	protected EmployeesDao employeesDao;

	@Test
	public void findAll() {
		ExpressionBuilder builder = new ExpressionBuilder();
		ReadAllQuery databaseQuery = new ReadAllQuery(Employees.class, builder);

		List<Employees> employees = employeesDao
				.executeDatabaseQuery(databaseQuery);
		assertTrue(employees != null);
		assertTrue(employees.size() == 107);
	}

}


Actions

Information

Leave a comment