Problem

Majority of enterprise applications use database as a persistence layer. JPA framework allows developers to manage relational data in their J2SE and J2EE applications. While knowledge about JPA domain modeling techniques is widespread and available, there is little known about persistence layer testing. In this post I will describe the process of setting up an environment for an application integration testing using JUnit, Spring Framework and Maven.

The standard Maven 2 directory layout

The standard Maven 2 directory structure can be seen below.

Maven Directory Layout


In the project home directory goes the pom.xml and two subdirectories – src for source code and target for compilation output. The src directory has two subdirectories, main – all files related to the application being developed go here and test – all test related files go here.

Naturally, this layout might be different, most likely having more elements – this depends on the archetype used during project inception, but, nevertheless, the layout above is an absolute minimum. The test directory have two subdirectories – java – with all unit tests and resources – with resources, which are used for testing, but are not deployed.
Having two separate directories for application and test allows us to have two, completely separated configuration files, so that testing environment was completely independent from development environment. It is possible, to develop using one database instance and test on the other, or even use MySQL for development and HSQLDB for testing, if required.

Configuration files

persistence.xml

The persistence.xml file defines a persistence-unit, and according to specification, has to be included an the META-INF directory of a JAR file that contains entities. However, Spring gives a little bit more room here and my approach is to put it in a config subdirectory of test/resources. The minimum persistence.xml:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<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="persistenceUnit" transaction-type="RESOURCE_LOCAL"/>

</persistence>

defines only the persistence-unit name, everything else is configured in Spring Framework configuration file – applicationContext.xml, which goes also to a config directory.

applicationContext.xml

Spring Framework configuration file – applicationContext.xml

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:context="http://www.springframework.org/schema/context"
  xmlns:tx="http://www.springframework.org/schema/tx"
  xmlns:aop="http://www.springframework.org/schema/aop"
  xmlns:p="http://www.springframework.org/schema/p"
  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-3.0.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
  ">

  <!-- Enable processing of PersistenceUnit and PersistenceContext annotations  -->
  <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>

  <!-- Persistence exception translation for Repositories -->
  <bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />

  <!-- Enable annotation-driven configuration and auto-detection -->
  <context:annotation-config/>

  <!-- Enable component scan -->
  <context:component-scan base-package="com.bewareofthebear"/>

  <!-- Configure property placeholders for environment-specific properties customization -->
  <context:property-placeholder location="classpath:/properties/*.properties" />

  <!-- Datasource to be used by Hibernate/JPA  -->
  <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"
    p:driverClassName="${db.driverClassName}"
    p:url="${db.url}"
    p:username="${db.username}"
    p:password="${db.password}"
  />

  <!-- EntityManagerFactory using defined datasource and JPA provider - Hibernate  -->
  <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
    p:persistenceXmlLocation="classpath:/config/persistence.xml"
    p:dataSource-ref="dataSource"
  	p:persistenceUnitName="persistenceUnit"
    >
    <property name="jpaVendorAdapter">
      <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
    </property>
    <property name="jpaProperties">
      <props>
        <prop key="hibernate.ejb.naming_strategy">org.hibernate.cfg.ImprovedNamingStrategy</prop>
        <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
        <prop key="hibernate.hbm2ddl.auto">create</prop>
        <prop key="hibernate.format_sql">false</prop>
        <prop key="hibernate.use_sql_comments">false</prop>
      </props>
    </property>
  </bean>

  <!--  Transaction manager -->
  <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"
    p:entityManagerFactory-ref="entityManagerFactory"
    p:dataSource-ref="dataSource"
  />

  <!-- Use @Transactional annotation on methods -->
  <tx:annotation-driven transaction-manager="transactionManager"/>

</beans>

As seen, using persistenceXmlLocation property of EntityManagerFactory I was able to point to my test version of a persistence.xml file. This approach has however one drawback which comes from limitations of JPA’s entities scan. It scans only paths within a persistent unit root url, which is a parent folder of persistence.xml location. Since maven copies content of the resource folder to the target/test-classes folder, than this folder becomes the root url and is scanned during application start-up. As a result of this, all application entities defined under main/java/… will not be scanned and, if test database is different than development database, than tests will fail. There are few ways to solve this problem.

First, it is possible to use an application version of persistence.xml instead of test version, however, this approach has the same drawback, just in opposite direction – all application entities are scanned, but, if there are any entities defined in a test directory than these will not be scanned.

Second solution is to explicitly list required entities in a persistence.xml file:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<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="persistenceUnit" transaction-type="RESOURCE_LOCAL">
    <class>com.bewareofthebear.domain.model.customer.Customer</class>
    <class>com.bewareofthebear.domain.model.customer.Category</class>
  </persistence-unit>

</persistence>

Which works, but could be time consuming and error prone.

Third solution is to use PersistenceUnitPostProcessors, which will scan all entities and add them to persistence unit.

package com.bewareofthebear.application;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;

import org.scannotation.AnnotationDB;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.orm.jpa.persistenceunit.MutablePersistenceUnitInfo;
import org.springframework.orm.jpa.persistenceunit.PersistenceUnitPostProcessor;

public class TestPersistenceUnitPostProcessor implements  PersistenceUnitPostProcessor  {
  private final Logger log = LoggerFactory.getLogger( TestPersistenceUnitPostProcessor.class );

  public void postProcessPersistenceUnitInfo(MutablePersistenceUnitInfo pui) {
    URL persistenceUnitRootUrl = pui.getPersistenceUnitRootUrl();

    String protocol = persistenceUnitRootUrl.getProtocol();
    String host =  persistenceUnitRootUrl.getHost();
    int port = persistenceUnitRootUrl.getPort();
    String file = persistenceUnitRootUrl.getFile();
    String newFile = file.substring(0, file.lastIndexOf("test-classes")) + "classes/";

    URL url = null;
    try {
      url = new URL(protocol, host, port, newFile);
    } catch (MalformedURLException e) {
      log.warn( "Malformed url: " + url, e );
      return;
    }

    AnnotationDB annotationDB = new AnnotationDB();
    try {
      annotationDB.scanArchives(url);
    } catch (IOException e) {
      log.warn( "Unexpected IOException", e );
      return;
    }

    if (annotationDB.getAnnotationIndex().containsKey("javax.persistence.Entity")) {
      for (String entity : annotationDB.getAnnotationIndex().get("javax.persistence.Entity")) {
        pui.addManagedClassName(entity);
        log.debug( "Adding: {}", entity );
      }
    }
  }

}

PersistenceUnitPostProcessors has to be wired to LocalContainerEntityManagerFactoryBean:

  <property name="persistenceUnitPostProcessors">
    <list><bean class="com.bewareofthebear.application.TestPersistenceUnitPostProcessor"/></list>
  </property>

Now, the configuration is completed, so it is time to move on and create some tests.

Test classes

The basic template for creating test classes:

package com.bewareofthebear.test;

import static org.junit.Assert.*;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.transaction.AfterTransaction;
import org.springframework.test.context.transaction.BeforeTransaction;
import org.springframework.test.context.transaction.TransactionConfiguration;
import org.springframework.transaction.annotation.Transactional;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"classpath:/config/applicationContext.xml"})
@TransactionConfiguration(transactionManager="transactionManager", defaultRollback=false)
@Transactional
public class JPATestTemplate {

  @BeforeTransaction
  public void verifyInitialDatabaseState() {
  // logic to verify the initial state before a transaction is started
  }

  @Before
  public void setUpTestDataWithinTransaction() {
  // set up test data within the transaction
  }

  @Test
  @Rollback(true)
  public void modifyDatabaseWithinTransaction() {
  // logic which uses the test data and modifies database state
  }

  @After
  public void tearDownWithinTransaction() {
  //  execute "tear down" logic within the transaction
  }

  @AfterTransaction
  public void verifyFinalDatabaseState() {
  // logic to verify the final state after transaction has rolled back
  }

}
  • @RunWith(SpringJUnit4ClassRunner.class) – tells JUnit to use Spring’s own built-in Test Runner that is aware of Spring-specific annotations
  • @ContextConfiguration(locations={“classpath:/config/applicationContext.xml”}) – creates a Spring context for this test from the specified context file.
  • @Transactional – before the method is executed a transaction is opened, upon exit the transaction is commited unless an exception occurs in which case it is rolled back.
  • @TransactionConfiguration(transactionManager=”transactionManager”, defaultRollback=false) – defines class-level metadata for configuring transactional tests
  • @Rollback(true) – forces the database to rollback this transaction when the test terminates regardless of whether the test fails, an exception is thrown or not.

Sample usage:

package com.bewareofthebear.test;

import static org.junit.Assert.assertEquals;

import java.util.List;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.transaction.TransactionConfiguration;
import org.springframework.transaction.annotation.Transactional;

import com.bewareofthebear.domain.model.customer.Customer;
import com.bewareofthebear.infrastructure.persistence.CustomerDao;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"classpath:/config/applicationContext.xml"})
@TransactionConfiguration(transactionManager="transactionManager", defaultRollback=false)
@Transactional
public class JPATestCustomer {

  @Autowired
  CustomerDao customerDao;

  @Before
  public void setUpTestDataWithinTransaction() {
    Customer customer = null;

    customer = new Customer ();
    customer.setFirstName("John"); customer.setFirstName("Doe");
    customerDao.persist(customer);

    customer = new Customer ();
    customer.setFirstName("Jack"); customer.setFirstName("Rabbit");
    customerDao.persist(customer);

    customer = new Customer ();
    customer.setFirstName("Richard "); customer.setFirstName("Roe");
    customerDao.persist(customer);
  }

  @Test
  @Rollback(true)
  public void countTest() {
    Long count = customerDao.countAll();
    assertEquals(count, new Long(3));
  }

  @Test
  @Rollback(true)
  public void findAllTest() {
    List<Customer> all = customerDao.findAll();
    assertEquals(all.size(), 3);
  }

}

Complete project

complete sources used during writing.

December 25th, 2009Ext JS Integration with Spring

Problem

Create Ext JS grid able to read data in XML format. Provide XML data from Spring controller. Bind it all together.

To demonstrate an integration between Ext JS and Spring frameworks I am going to use one of Ext JS grid samples – Progress Bar Pager. This grid displays Dow Jones components using Ext.data.ArrayReader which is one of the three, built in Ext.data.DataReader implementation. Since data will be served from a server, an ArrayReader has to be replaced with a XMLReader. Ext JS provides a helper class, XMLStore, which is automatically configured with an XMLReader, so I am going to use it.

DJIA Grid

Ext.onReady(function() {

  // example of custom renderer function
  function change(val) {
    if (val > 0) {
      return '<span style="color:green;">' + val + '</span>';
    } else if (val < 0) {
      return '<span style="color:red;">' + val + '</span>';
    }
      return val;
  }

  // example of custom renderer function
  function pctChange(val) {
    if (val > 0) {
      return '<span style="color:green;">' + val + '%</span>';
    } else if (val < 0) {
      return '<span style="color:red;">' + val + '%</span>';
    }
    return val;
  }

  // create the data store
  var xmlStockStore = new Ext.data.XmlStore({
    autoDestroy : true,
    url : '/zone/rest/djia',
    record : 'component',
    idPath : 'symbol',
    totalProperty : 'totalRecords',
    fields : [
      {name : 'name'},
      {name : 'price', type : 'float'},
      {name : 'valChange', type : 'float'},
      {name : 'pctChange', type : 'float'},
      {name : 'lastUpdate', type : 'date', dateFormat : 'Y-m-d H:i:s.u T'}
    ]
  });

  // create the Grid
  var grid = new Ext.grid.GridPanel({
    store : xmlStockStore,
    columns : [
      {id : 'company', header : "Company", width : 160, sortable : true, dataIndex : 'name'},
      {header : "Price", width : 75, sortable : true, renderer : 'usMoney', dataIndex : 'price'},
      {header : "Change", width : 75, sortable : true, renderer : change, dataIndex : 'valChange'},
      {header : "% Change", width : 75, sortable : true, renderer : pctChange, dataIndex : 'pctChange'},
      {header : "Last Updated", width : 95, sortable : true, renderer : Ext.util.Format.dateRenderer('d-m-Y H:i'), dataIndex : 'lastUpdate'}
    ],
    stripeRows : true,
    autoExpandColumn : 'company',
    height : 320,
    width : 545,
    frame : true,
    title : 'DJIA',

    bbar : new Ext.PagingToolbar({
      pageSize : 10,
      store : xmlStockStore,
      displayInfo : true,
      displayMsg : 'Displaying item {0} - {1} of {2}',
      emptyMsg : "No item to display",

      plugins: new Ext.ux.ProgressBarPager()
    })
  });

  grid.render('grid-example');

  xmlStockStore.load({params : {start : 0, limit : 10}});
});

The grid above is configured to consume an xml of the form:

<?xml version="1.0" encoding="UTF-8"?>
<djia>
  <totalRecords>30</totalRecords>
  <components>
    <component>
      <symbol>MMM</symbol>
      <name>3M Co </name>
      <price>60.46</price>
      <valChange>0.12</valChange>
      <pctChange>0.2</pctChange>
      <lastUpdate>2009-12-24 15:00:00.0 CET</lastUpdate>
    </component>
  </components>
</djia>

So the last thing to do is to configure Spring to deliver an XML in a required form.

Thanks to Spring 3.0 REST support and ContentNegotiatingViewResolver providing an XML content is an extremally easy task. First, Spring configuration:

web.xml

	<servlet>
		<servlet-name>SpringDispatcher</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value/>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>SpringDispatcher</servlet-name>
		<url-pattern>/rest/*</url-pattern>
	</servlet-mapping>

applicationContext.xml

  <bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver" p:order="1">
    <property name="mediaTypes">
      <map>
        <entry key="xml" value="application/xml"/>
      </map>
    </property>
    <property name="defaultViews">
      <bean class="org.springframework.web.servlet.view.xml.MarshallingView">
        <property name="marshaller">
          <bean class="org.springframework.oxm.xstream.XStreamMarshaller"
            p:autodetectAnnotations="true"
          />
        </property>
      </bean>
    </property>
  </bean>

As seen above, I am going to use an XStream library to serialize objects to XML. XStream is easy configurable with annotations, so the single DJIA component:

Component

import java.util.Date;

import com.thoughtworks.xstream.annotations.XStreamAlias;

@XStreamAlias("component")
public class Component {

  private String symbol;
  private String name;
  private Double price;
  @XStreamAlias("valChange")
  private Double valueChange;
  @XStreamAlias("pctChange")
  private Double percentChange;
  private Date lastUpdate;

  public Component () {
    super ();
  }

  public Component(String symbol, String name, Double price, Double valueChange, Double percentChange, Date lastUpdate) {
    super();
    this.symbol = symbol;
    this.name = name;
    this.price = price;
    this.valueChange = valueChange;
    this.percentChange = percentChange;
    this.lastUpdate = lastUpdate;
  }

  public String getSymbol() {
    return symbol;
  }
  public String getName() {
    return name;
  }
  public Double getPrice() {
    return price;
  }
  public Double getValueChange() {
    return valueChange;
  }
  public Double getPercentChange() {
    return percentChange;
  }
  public Date getLastUpdate() {
    return lastUpdate;
  }

  public void setSymbol(String symbol) {
    this.symbol = symbol;
  }
  public void setName(String name) {
    this.name = name;
  }
  public void setPrice(Double price) {
    this.price = price;
  }
  public void setValueChange(Double valueChange) {
    this.valueChange = valueChange;
  }
  public void setPercentChange(Double percentChange) {
    this.percentChange = percentChange;
  }
  public void setLastUpdate(Date lastUpdate) {
    this.lastUpdate = lastUpdate;
  }
}

and all of the components:

IndexDTO

import java.util.LinkedList;

import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.zone.domain.model.Component;

@XStreamAlias("djia")
public class IndexDTO {

  private int totalRecords;
  private LinkedList <Component> components;

  public void setTotalRecords(int totalRecords) {
    this.totalRecords = totalRecords;
  }
  public void setComponents(LinkedList <Component> components) {
    this.components = components;
  }

  public int getTotalRecords() {
    return totalRecords;
  }
  public LinkedList <Component> getComponents() {
    return components;
  }

}

IndexDTO is a helper class, which will be eventually marshalled and sent to browser, totalRecords variable is optional, but grid PagingToolbar will not work without it.

Finally, the controller:

IndexController

import java.util.LinkedList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import com.zone.domain.model.Component;
import com.zone.infrastructure.repository.DJIARepository;
import com.zone.web.grid.IndexDTO;

@Controller
public class IndexController {

  @Autowired
  DJIARepository djiaRepository;

  @RequestMapping(value = "/djia")
  public void getComponents(@RequestParam("start") int start, @RequestParam("limit") int limit, Model model) {

    List <Component> components= (List<Component>) djiaRepository.findAll();
    IndexDTO indexDTO = new IndexDTO ();

    indexDTO.setTotalRecords(components.size());
    indexDTO.setComponents(new LinkedList<Component> (components.subList(start, start+limit > components.size() ? components.size() : start+limit)));

    model.addAttribute("indexDTO", indexDTO);
  }

}

DJIARepository is a class holding all DJIA components.

Conclusion

It is actuall all, what is necessary, to have an Ext JS grid populated with data coming from Java based back end. Of course, all hard work is done by Spring and Xstream with some configuration and programming left to the application developer.

Problem

Most likely, each DAO class implements basic CRUD operations. Since these are the same for all possible entities, it makes perfect sense to have one generic DAO class which implements common CRUDs and extend it when necessary adding anything which is required by a specific entity instance.

Simple generic DAO should implement the following interface:

SimpleDao.java

package com.application.sample;

import java.io.Serializable;

public interface SimpleDao <PK extends Serializable, E extends AbstractEntity <PK>> {
  public E create(E entity);
  public E read(PK id);
  public E update(E entity);
  public void delete(PK id);
}

When implementing generic DAO using Hibernate as JPA provider we are facing the problem. Hibernate load and get operations require information about object being retrieved. Either object class, class name or the object instance has to be provided before actual read operation can be executed. None of these information is accessible before generic DAO is extended and instantiated. I can think of two possible solutions, an obvious one – asking implementation to deliver required information, and nice one – using java.lang.reflection.ParameterizedType.

Lets assume, I have an abstract entity, which defines fields common to all entities in my application:

AbstractEntity .java

package com.application.sample;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.MappedSuperclass;
import javax.persistence.Transient;
import javax.persistence.Version;

@MappedSuperclass
public abstract class AbstractEntity <PK extends Serializable> implements Serializable {
  private static final long serialVersionUID = -6991226731574845156L;

  public AbstractEntity () {
  }

  private PK primaryKey;
  private Integer version;

  @Transient
  public PK getPrimaryKey () {
    return primaryKey;
  }

  @Version
  @Column(name="version", nullable=false)
  public Integer getVersion() {
    return version;
  }

  public void setPrimaryKey (PK primaryKey) {
    this.primaryKey = primaryKey;
  }

  public void setVersion(Integer version) {
    this.version = version;
  }

}

And Employee entity:

Employee.java

package com.application.sample;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

import org.hibernate.annotations.Index;

@Entity
@Table(name = "EMPLOYEES")
@org.hibernate.annotations.Table(
  indexes = {@Index(name="lastNameIdx", columnNames={"last_name"} )},
  appliesTo = "EMPLOYEES"
)
public class Employee extends AbstractEntity <Integer> {
  private static final long serialVersionUID = -1693502528557287614L;

  private String firstName = null;
  private String lastName = null;

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  @Column(name="employee_id")
  public Integer getEmployeeId() {
    return getPrimaryKey();
  }

  @Column(name = "first_name")
  public String getFirstName() {
    return firstName;
  }

  @Column(name = "last_name")
  public String getLastName() {
    return lastName;
  }

  public void setEmployeeId(Integer employeeId) {
    setPrimaryKey(employeeId);
  }

  public void setFirstName(String firstName) {
    this.firstName = firstName;
  }

  public void setLastName(String lastName) {
    this.lastName = lastName;
  }

}

For an Employee entity I want to have a possibility to find employees by their last name, so I add the required method the specification:

EmployeeDao.java

package com.application.sample;

import java.util.List;

public interface EmployeeDao extends SimpleDao<Integer, Employee> {

  public List<Employee> readEmployeeByLastName(String lastName);

}


Solution one – pass the buck.

Generic DAO implementation:

AbstractPassTheBuckDao.java

package com.application.sample;

import java.io.Serializable;

import org.hibernate.SessionFactory;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

public abstract class AbstractPassTheBuckDao<PK extends Serializable, E extends AbstractEntity <PK>>
       extends HibernateDaoSupport implements SimpleDao <PK, E>   {

  public AbstractPassTheBuckDao() {
  }

  protected AbstractPassTheBuckDao(SessionFactory sessionFactory) {
    this();
    this.setSessionFactory(sessionFactory);
  }

  // Ask the implementation for entity class
  abstract protected Class<E> getPersistentClass ();

  public E create(E entity) {
    this.getHibernateTemplate().save(entity);
    return entity;
  }

  @SuppressWarnings("unchecked")
  public E read(PK id) {
    E entity = (E) this.getHibernateTemplate().get(getPersistentClass(), id);
    return entity;
  }

  public E update(E entity) {
    this.getHibernateTemplate().merge(entity);
    return entity;
  } 

  public void delete(PK id) {
    this.getHibernateTemplate().delete(read(id));
  }

}

Employee DAO implementation:

EmployeePassTheBuckDao.java

package com.application.sample;

import java.util.List;

public class EmployeePassTheBuckDao
       extends AbstractPassTheBuckDao <Integer, Employee> implements EmployeeDao {

  // Deliver entity class
  protected Class<Employee> getPersistentClass() {
    return Employee.class;
  }

  @SuppressWarnings("unchecked")
  public List<Employee> readEmployeeByLastName(String lastName) {
    String queryString = "from Employee where lastName = :lastName";
    String paramName = "lastName";
    return (List<Employee>) this.getHibernateTemplate().findByNamedParam(queryString, paramName, lastName);
  }

}


Solution two – do it yourself.

Generic DAO implementation:

AbstractDoItYourselfDao.java

package com.application.sample;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;

import org.hibernate.SessionFactory;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

public abstract class AbstractDoItYourselfDao<PK extends Serializable, E extends AbstractEntity <PK>>
       extends HibernateDaoSupport implements SimpleDao <PK, E>   {

  private Class<E> persistentClass;

  @SuppressWarnings("unchecked")
  public AbstractDoItYourselfDao() {
    // retrieve entity class
    ParameterizedType paramType = null;
    Type type = getClass().getGenericSuperclass();
    if (type instanceof ParameterizedType) {
      paramType = (ParameterizedType) type;
    } else {
      paramType = (ParameterizedType) getClass().getSuperclass().getGenericSuperclass();
    }

    if (paramType.getActualTypeArguments().length == 2) {
      if (paramType.getActualTypeArguments()[1] instanceof TypeVariable) {
        throw new IllegalArgumentException("Could not persistent entity class using reflection");
      } else {
        persistentClass = (Class<E>) paramType.getActualTypeArguments()[1];
      }
    } else {
      persistentClass = (Class<E>) paramType.getActualTypeArguments()[0];
    }

  }

  protected AbstractDoItYourselfDao(SessionFactory sessionFactory) {
    this();
    this.setSessionFactory(sessionFactory);
  }

  // deliver entity class
  protected Class<E> getPersistentClass () {
    return persistentClass;
  }

  public E create(E entity) {
    this.getHibernateTemplate().save(entity);
    return entity;
  }

  @SuppressWarnings("unchecked")
  public E read(PK id) {
    E entity = (E) this.getHibernateTemplate().get(getPersistentClass(), id);
    return entity;
  }

  public E update(E entity) {
    this.getHibernateTemplate().merge(entity);
    return entity;
  } 

  public void delete(PK id) {
    this.getHibernateTemplate().delete(read(id));
  }

}

Employee DAO implementation:

EmployeeDoItYourselfDao .java

package com.application.sample;

import java.util.List;

public class EmployeeDoItYourselfDao
       extends AbstractDoItYourselfDao <Integer, Employee> implements EmployeeDao {

  @SuppressWarnings("unchecked")
  public List<Employee> readEmployeeByLastName(String lastName) {
    String queryString = "from Employee where lastName = :lastName";
    String paramName = "lastName";
    return (List<Employee>) this.getHibernateTemplate().findByNamedParam(queryString, paramName, lastName);
  }

}

As seen above, the EmployeeDao implementation implements only Employee related operations and there is no need to deliver Employee class to generic DAO superclass.


© 2007 Toss a coin | iKon Wordpress Theme by Windows Vista Administration | Powered by Wordpress