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.

Java generics are checked for type correctness at compile time, when a generic type is instantiated, the compiler removes generic type information by a type erasure technique. A generic class is translated to a raw type – generic type without any type arguments. Consequently, when a type is not known during both compile time and runtime, it is not possible to instantiate a generic type parameter using a constructor call. The following code:

  private I i= new I ();

will not compile.

In this post I’ll describe two possible solutions, both using java.lang.Reflection package.

Let’s assume we have a generic Envelope class, which is used to pair a content object – Content – with additional information related to it – ContentInfo.

Envelope.java

package com.application.generics;

import java.io.Serializable;

public class Envelope <I extends ContentInfo, C extends Serializable> implements Serializable {
  private static final long serialVersionUID = -6433250240547869806L;

  private I contentInfo;
  private C content;

  public Envelope () {
  }

  public Envelope (I contentInfo) {
    this.contentInfo = contentInfo;
  }

  public Envelope (I contentInfo, C content) {
    this.contentInfo = contentInfo;
    this.content = content;
  }

  public I getContentInfo() {
    return contentInfo;
  }

  public C getContent() {
    return content;
  }

  public void setContent(C content) {
    this.content = content;
  }

  public void setContentInfo(I contentInfo) {
    this.contentInfo = contentInfo;
  }

}

ContentInfo is an interface:

ContentInfo.java

package com.application.generics;

public interface ContentInfo {

  public boolean isContentValid();

}

And its three possible implementations:

ContentAlwaysValid.java

package com.application.client;

import java.io.Serializable;

import com.application.generics.ContentInfo;

public class ContentAlwaysValid implements ContentInfo, Serializable {
  private static final long serialVersionUID = 8019707740072299936L;

  public boolean isContentValid() {
    return true;
  }

}

ContentNeverValid .java

package com.application.client;

import java.io.Serializable;

import com.application.generics.ContentInfo;

public class ContentNeverValid implements ContentInfo, Serializable {
  private static final long serialVersionUID = -861952203103353570L;

  public boolean isContentValid() {
    return false;
  }

}

ContentSometimesValid.java

package com.application.client;

import java.io.Serializable;

import com.application.generics.ContentInfo;

public class ContentSometimesValid implements ContentInfo, Serializable {
  private static final long serialVersionUID = 2731488051426426010L;

  private boolean contentValid;

  public ContentSometimesValid (boolean contentValid) {
    this.contentValid = contentValid;
  }

    public boolean isContentValid() {
      return contentValid;
    }

}

Additionally, let’s say, there is requirement, that the contentInfo is initialized to its default value whenever an object of the Envelope class is instantiated. The common solution is a factory class, which provides a method which instantiates an object of a given class using Reflection API. In our case, a simple factory class – ContentWrapper – might look like this:

ContentWrapper.java

package com.application.generics;

import java.io.Serializable;

public class ContentWrapper <I extends ContentInfo, C extends Serializable> {

  @SuppressWarnings("unchecked")
  public Envelope <I, C> wrapContent (Class<?> cls, C content) {
    I contentInfo = null;
    try {
      contentInfo = (I) cls.newInstance();
    } catch (Exception exception) {
      throw new RuntimeException(exception);
    }
    return new Envelope <I, C> (contentInfo, content);
  }

}

ContentWrapper does the job. The following code:

ContentWrapperTest.java

public class GenericsTest {

  private void ContentWrapperTest () {

    ContentWrapper <ContentInfo, String> contentWrapper = new  ContentWrapper <ContentInfo, String> ();
    Envelope <ContentInfo, String> envelope = null;

    envelope = contentWrapper.wrapContent(ContentAlwaysValid.class, new String("I am a message"));
    System.out.println("Content is " + (envelope.getContentInfo().isContentValid() ? "valid" : "invalid") + ".");    

    envelope = contentWrapper.wrapContent(ContentNeverValid.class, new String("I am a message"));
    System.out.println("Content is " + (envelope.getContentInfo().isContentValid() ? "valid" : "invalid") + ".");    

  }

}

compiles and runs fine. However, this test:

    envelope = contentWrapper.wrapContent(ContentSometimesValid.class, new String("I am a message"));
    System.out.println("Content is " + (envelope.getContentInfo().isContentValid() ? "valid" : "invalid") + ".");

compiles, but during the runtime a java.lang.InstantiationException is thrown.

In some cases, instantiating an object without any meaningful content makes no sense, and developers are protecting themselves against such cases by not providing default, public constructor. Now we have a conflict of interests. Implementation deliberately does not provide a default constructor, which is necessary to instantiate an object in a reflective way. What if a constructor were provided, but with non public access modifier?

ContentSometimesValid.java

package com.application.client;

import java.io.Serializable;

import com.application.generics.ContentInfo;

public class ContentSometimesValid implements ContentInfo, Serializable {
  private static final long serialVersionUID = 2731488051426426010L;

  private boolean contentValid;

  protected ContentSometimesValid () {
    contentValid = true;
  }

  public ContentSometimesValid (boolean contentValid) {
    this.contentValid = contentValid;
  }

  public boolean isContentValid() {
    return contentValid;
  }

}

Protected constructor alone does not solve the problem – java.lang.IllegalAccessException is thrown during the runtime with a following message: Class com.application.generics.ContentWrapper can not access a member of class com.application.client.ContentSometimesValid with modifiers “protected”. Fortunately, reflection API allows code to perform actions, which would be illegal in standard code, such as invoking non public methods. In order to use this feature, we need to change our ContentWrapper class to make constructor accessible:

ContentWrapper .java

package com.application.generics;

import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;

public class ContentWrapper <I extends ContentInfo, C extends Serializable> {

  @SuppressWarnings("unchecked")
  public Envelope <I, C> wrapContent (Class<?> cls, C content) {

    Constructor<?> ctor = null;
    try {
      ctor = cls.getDeclaredConstructor((Class<?>[]) null);
    } catch (Exception exception) {
      throw new RuntimeException(exception);
    } 

    // make constructor accessible, if it is not already public
    if (!Modifier.isPublic(ctor.getModifiers()) || !Modifier.isPublic(ctor.getDeclaringClass().getModifiers())) {
      ctor.setAccessible(true);
    }        

    I contentInfo = null;
    try {
      contentInfo = (I) ctor.newInstance();
    } catch (Exception exception) {
      throw new RuntimeException(exception);
    }

    return new  Envelope <I, C> (contentInfo, content);
  }

}

Modified ContentWrapper class is sufficient to do what is required, however, it is not type-safe. Since the singature of a wrapContent method:

  public Envelope <I, C> wrapContent (Class<?> cls, C content);

requires a parameter of type Class, then the following code:

  envelope = contentWrapper.wrapContent(String.class, new String("I am a message"));

compiles and obviously failes during the runtime with a java.lang.ClassCastException.

Solution to this problem comes with a java.lang.reflect.ParameterizedType interface. Using this interface is a little bit tricky since a class, within it is used, must be derived from another generic class. We can achieve it by making our ContentWrapper abstract and then instantiating it with unnamed implementations. Then, instead of passing a ContentInfo class as a parameter, we can retrieve it from ParameterizedType.

ContentWrapper .java

package com.application.generics;

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

public abstract class ContentWrapper <I extends ContentInfo, C extends Serializable> {

  @SuppressWarnings("unchecked")
  public Envelope <I, C> wrapContent (C content) {

    // get a class
    Class<I> cls  = (Class<I>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];

    Constructor<I> ctor = null;
    try {
      ctor = cls.getDeclaredConstructor((Class<?>[]) null);
    } catch (Exception exception) {
      throw new RuntimeException(exception);
    } 

    if (!Modifier.isPublic(ctor.getModifiers()) || !Modifier.isPublic(ctor.getDeclaringClass().getModifiers())) {
      ctor.setAccessible(true);
    }        

    I contentInfo = null;
    try {
      contentInfo = ctor.newInstance();
    } catch (Exception exception) {
      throw new RuntimeException(exception);
    }

    return new  Envelope <I, C> (contentInfo, content);
  }

}

And on the client side:

  private void ContentWrapperTest () {

    // an abstract class is implemented
    ContentWrapper <ContentSometimesValid, String> contentWrapper = new  ContentWrapper <ContentSometimesValid, String> () {};
    Envelope <ContentSometimesValid, String> envelope = null;

    envelope = contentWrapper.wrapContent(new String("I am a message"));    

    System.out.println("Content is " + (envelope.getContentInfo().isContentValid() ? "valid" : "invalid") + ".");    

  }

Enforcing type correctness makes ContentWrapper and Envelope classes less generic, since it is not possible now to have one Envelope and one ContentWrapper instance for any ContentInfo implementation. the following code:


    Envelope <ContentInfo, String> envelope = contentWrapper.wrapContent(new String("I am a message"));

does not compile.

As seen, there is a certain trade off between both approaches and it is difficult to say which implementation is more correct. My guess is, it depends.


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