A Handy and Highly Reusable JPA 2.0 Data Access Object
Hi ! In this post I’ll show you a highly reusable Data Access Object for Java web applications which will reduce the development time of your DAOs.
Consider the following DAO and it’s implementation.
public interface UserDao {
User storeUser(User user);
void removeUser(User user);
List<User> findAllUsers();
User findUserById(long id);
}
public class JpaUserDao implements UserDao {
@PersistentContext
private EntityManager em;
@Override
public User storeUser(User user) {
User merged = em.merge(user);
em.persist(merged);
return merged;
}
@Override
public void removeUser(User user) {
em.remove(user);
}
@Override
public List<User> findAllUsers() {
return (List <User>) em.createQuery("from User").getResultList();
}
@Override
public User findUserById(Long id) {
return em.find(User.class, id);
}
}
It looks pretty cool ! We just coded a JPA 2.0 Data Access Object. This means we used standard Java libraries (javax.persistence package).
The problem with the above code is that you are going to repeat it for each entity in your application. Having those 40 lines of CRUD (Create-Remove-Update-Delete) code doesn’t only lead you to more development effort but only to a poorly maintainable application. A code generator like Spring Roo can do the work but we can avoid any code generation tools by applying some Java inheritance and spicy code like using Java Generics and Reflection. You’ll see how to use those forty lines for infinite entities DAOs.
First of all let’s create a generic DAO:
public interface BaseDao<T> {
T store(T t);
void remove(T t);
List<T> findAll();
T findById(long id);
}
The above interface will be extended by all your DAO interfaces.
We should now create a generic implementation of the above interface which will be extended by all the DAO implementations of your application.
@SuppressWarnings("unchecked")
@Repository
public abstract class JpaBaseDao<T extends Serializable> implements BaseDao<T> {
private Class<T> clazz;
@PersistenceContext
protected EntityManager em;
protected JpaBaseDao() {
Class<T> getClass = (Class<T>) getClass();
ParameterizedType genericSuperclass = (ParameterizedType) getClass.getGenericSuperclass();
clazz = (Class<T>) genericSuperclass.getActualTypeArguments()[0];
}
@Override
public T store(T t) {
T merged = em.merge(t);
em.persist(merged);
return merged;
}
@Override
public void remove(T t) {
em.remove(t);
}
@Override
public List<T> findAll() {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<T> query = cb.createQuery(clazz);
query.from(clazz);
return em.createQuery(query).getResultList();
}
@Override
public T findById(long id) {
return em.find(clazz, id);
}
}
The @Repository annotation is a Spring annotation which Indicates that an annotated class is a “Repository” (or “DAO”). A class thus annotated is eligible for Spring DataAccessException translation. The annotated class is also clarified as to its role in the overall application architecture for the purpose of tools, aspects, etc. Note that you don’t need it if you are not using Spring.
The @PersistenContext is a javax.persistence annotation which expresses a dependency on an EntityManager persistence context.
The final code:
public interface UserDao extends BaseDao<User> {
// Custom access methods (which are not CRUD's) go here
}
public class JpaUserDao extends JpaBaseDao<User> implements UserDao {
// Custom access methods implementations go here
}
Then in a service layer, let’s say a Spring service, you can access the BaseDao CRUD methods from any DAO which inherits it.
@Service
public class UserService {
@Autowired
private UserDao userDao;
@Transactional
public User saveUser(User user) {
return userDao.store(user);
}
}
Well, that’s all ! I hope you find it useful.
If you enjoyed this post follow me on twitter or leave a feedback !
What I would add to this generic dao is the query method or methods (query, single result query, count query)
Nice post.
Hi ! Thanks for the feedback ! It would be nice to have methods like
findManyBy(Criterion… criterions)
(the three points mean multiple parameters)
Unluckily, Criterion and Session belong to the Hibernate framework.
Then it would be easy to add custom dao methods like
public List
userDao.findManyBy(Restrictions.eq(“name”, name), Restrictions.ge(“age”, age)).
}
The findManyBy(Criterion… criterions) implementation in the JpaBaseDao would be something like:
public List
Criteria criteria = session.createCriteriaQuery(clazz);
for (Criterion criterion : criterions) {
criteria.add(criterion);
}
return criteria.list();
}
Keep around !
Hi,
if you’re allowed to use Spring (as I suppose you are, as you’re using Spring annotations such as @Repository) you can use Hades (http://hades.synyx.org/) to do (almost) all the work for you.
@abel
The link doesn’t work
Based on yourself to increase the risk for judgements can definitely always be distressing along with frustrating. Many of us produce this particular capability throughout our own existence. Honestly it will take more than just taking place to happen.