Spring + Hibernate DAO as generic class - java

Some time ago I started to learn java EE. I swiftly moved to spring(mvc)+hibernate. As I was learning about databases and integration with spring+hibernate I came up with an idea.
As far as I noticed(and understand) there's a common approach to build an objects structure including configuration files, entities, dao interface and dao implementation(as we're talking just about dbs, not controllers and other applications' layers). I decided to write a generic java class and call it BasicDao. It's a template which takes entity as a type.
This is actually working and I think it's much better than interfaces and implementations, because you need only one class for all entities(if you wanted to write separated implementations for each entity you might end up with a big amount of files).
I also wrote some template functions there so the class is very flexible(no exceptions with types passed to the db). Here's the code
package local.bb.dao;
import java.util.List;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
#Repository(value = "basicDao")
#Transactional(propagation = Propagation.REQUIRED,readOnly = true)
public class BasicDao<ENTITY> {
private Class<ENTITY> data;
private SessionFactory sessionFactory;
public BasicDao() {
this.data = null;
}
#Transactional
public void addRecord(ENTITY t) {
this.sessionFactory.getCurrentSession().save(t);
}
#Transactional
public void removeRecord(ENTITY t) {
this.sessionFactory.getCurrentSession().delete(t);
}
#Transactional
public List<ENTITY> getAllRecords() {
return (List<ENTITY>)this.sessionFactory.getCurrentSession().createCriteria(this.data).list();
}
#Transactional
public <TYPE> ENTITY getRecordByParam(String param, TYPE value) {
return (ENTITY)this.sessionFactory.getCurrentSession().createCriteria(this.data).add(Restrictions.eq(param, value)).uniqueResult();
}
#Transactional
public <TYPE> List<ENTITY> getRecordsByParam(String param, TYPE value) {
return (List<ENTITY>)this.sessionFactory.getCurrentSession().createCriteria(this.data).add(Restrictions.like(param, value)).list();
}
// GETTERS / SETTERS
public SessionFactory getSessionFactory() {
return sessionFactory;
}
#Autowired
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public Class<ENTITY> getData() {
return data;
}
public void setData(Class<ENTITY> data) {
this.data = data;
}
}
The question, finally, is: is it a good approach actually? Because I've never seen such code anywhere(speaking about tutorials on the Internet and books).

Spring likes interfaces since a couple of important mechanism are based on it, e.g. AOP, interceptors. So, if you decide to go without them you have to accept certain limits to Spring functionality. What's more, it will be harder to write Test-Mocks for other classes that depend on your DAOs.
If you want to save code, I suggest you lose the implementation rather than the interface. With Spring JPA you can annotate a DAO interface with as set of annotations, i.e. #Query, #Procedure, #Modifying etc to define how the data is accessed. If you then enable JPA repositories in your application context, Spring will supply the DAO implementation for you.
More information can be found here.

Yes you can write generic DAO in hibernate and if it's useful and helps you to reduce substantial amount of code and makes your codebase clean then you should go for it. I have used generic DAO but only for simple CRUD operations. Here is a good read on generic persistence layer.

Related

testing HQL query on hbm2dll with Junit

How can I test HQL query with JUnit tests?
I have mapped Entity Class:
#Entity
#Table(name = "DOE")
public DomainObjectEntity {
//some attributes
}
which represents domain objects:
public class DomainObject {
//some attributes
}
I also have repository interface for my domain objects:
public interface DomainObjectRepository {
/**
* Gets entity by some attribute
*
*/
DomainObject getDomainObjectByObjectId(String objectId);
}
this interface is implemented in
#Repository
public class DomainObjectRepositoryImpl implements DomainObjectRepository {
#Inject
private DomainObjectEntityJPARepository entityRepository;
#Override
public DomainObjectgetDomainObjectById(String parcelId) {
//this converts my entity to domain object
return entityRepository.findByDomainObjectId(DomainObjectId.getStr()).getDomainObject();
}
}
my JPA Entity repository looks like this:
public interface DomainObjectEntityJPARepository extends JpaRepository<DomainObjectEntity, String> {
/**
* get DomainObject with requested id
*
* #param objectId - objects id
* #return DomainObject
*/
#Query("some query to be tested")
DomainObjectEntity findByDomainObjectId(#Param("objectId") String objectId);
}
and finally i want to write a simple JUnit test to check if query to findByDomainObjectId returns the correct object. I think my test should look like this:
create test object to put into DB
retrieve object from DB
compare objects
i have setted up a hbm2dll with import.sql to create and populate my DB but how can i access it from Junit test by calling method findByDomainObjectId?
Unit vs integration
First of all there is one thing you need to ask:
Do you want an Unit test or an Integration test
An unit test is fast (ie, milliseconds) to run and is, well, unitary - meaning it doesn't touch the database.
An integration test is heavier and, in case of a database test, will touch the db.
While it is usually preferable to create unit tests, in your case it seems you want an integration test - you actually want to test the call to the database and check if the query does what you think it does.
When to load data
I would suggest that in your integration test you don't preload data with import.sql (or at least think very carefully if this is what you want). The reason for this is that, as your test suite grows, you'll need the database in one state for test A, another state for test B, and so on, and you'll quickly end up in a situation where you'll have incompatible states.
You'll also end up with slower tests if you load too much data via SQL.
My advise would be: try to create/manipulate the data in your test.
How to test
How to test it depends on how you load your hibernate in production. Judging by the code you've shown, I believe you might be using a Dependency injection mechanism to start up hibernate's EntityManager (or SessionFactory), like Spring.
If this is the case, you can use spring to configure you integration test.
The main suggestions here would be:
Use rollback so that data is not stored between tests (guarantees test independence)
As your test suite grows, create an abstract class that holds the configuration and, e.g, exposes the EntityManager/sessionFactory. All your integration tests just need to extend this class, have the repository injected (in your example, inject DomainObjectRepositoryImpl into the test) and run the method you need to test.
Below is a very simple abstract test I have (in my case I'm using a SessionFactory):
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.transaction.TransactionConfiguration;
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations={
"/spring-SF-tests.xml",
"/spring-transaction.xml"
})
#TransactionConfiguration(transactionManager="txManager", defaultRollback=true)
public abstract class HibernateAbstractTest extends AbstractTransactionalJUnit4SpringContextTests {
#Autowired
protected SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory sessionFactory){
this.sessionFactory = sessionFactory;
}
public Session getSession(){
return sessionFactory.getCurrentSession();
}
public void save(Object object){
getSession().save(object);
}
public void update(Object object){
getSession().update(object);
}
}
Since I wanted to test only query, proper solution was to #autowire JPArepository and then in setup, populate it with data, this way tests were bound only with DB structure and not the data inside
public class EntityObjectJPARepositoryTest {
#Autowired
DomainObjectEntityJPARepository domainObjectRepo;
DomainObjectEntity entity;
#Before
public void Setup(){
entity = new DomainObjectEntity ()
//setup entity
domainObjectRepo.save(entity);
}
#Test
public void testfindByDomainObjectId(){
DomainObjectEntity res = domainObjectRepo.findByDomainObjectId(objectid);
Assert.assertEquals(entity.getId(), res.getId());
}
//everything else
}

Mockito : Basic Code doubts

I am learning Mockito , i have trouble understanding few things. Suppose i want to test a Doa method which gets List of objects and saves it in DB by iterating ove the list . How do test it using Mockito. Below is the code example.
import java.util.Iterator;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.springframework.stereotype.Repository;
#Repository
public class AuditDaoImpl {
#PersistenceContext(unitName = "somepersistance")
EntityManager entityManager;
public <T> boolean saveAuditData(List<T> dataList) {
Iterator<Data> itr = (Iterator<Data>) dataList.iterator();
while (itr.hasNext()) {
Data Data = (Data) itr.next();
Audit audit = new Audit();
audit.setUserName(Data.getUserName());
entityManager.persist(audit);
}
return true;
}
}
Assuming that your test class is annotated and running with spring (by using #RunWith(SpringJUnit4ClassRunner.class) and #ContextConfiguration("classpath:applicationContext.xml")) annotation and you have this working. And if your main concern is to verify that entityManager.persist(audit); is invoked for each element, something like this should work
#Autowired //Autowired to get mockito to inject into the spring-handled dao
#InjectMocks
AuditDaoImpl auditDao;
#Mock
EntityManager entityManager;
#Test
public void saveAllAudit_entityManagerShouldPersistAll() {
List<Data> dataList = new ArrayList<>();
dataList.add(new Data("username"));
//add more to list
auditDao.saveAuditData(dataList);
verify(entityManager, times(1)).persist(anyObject());
}
If you actually need to test that it is persisted correctly, an in-memory database would be the way to go.
Mockito is poor for testing cases that deal with the persistence layer. You should use an embedded container to test the persistance layer. An embedded container is an in memory database that simulates your Database and is fast to create, making it ideal for unit tests.
Look at this SO question and read the SECOND answer :
Testing an EJB with JUnit

Usage of a different kind of functions in one Java Class

I am following this tutorial to create my first Spring Hibernate JSF app, and in this tutorial http://marco-ng.blogspot.com/2014/02/primefaces-jsf2-spring-security-spring.html?showComment=1440293840519#c5483896447188701172 the developer used a UserDAO and CustomerDAO which are one for getting login name and the other to manager customers. For my sample, I'm using one class User merging the two used functions (User will login, and then he will manager totality of Users).
My Question is, can I simply merge those two DAO in one UserDAO :
User DAO :
package spring.dao;
import spring.model.User;
public interface UserDAO {
public User getUser(String login);
}
Custommer DAO :
package spring.dao;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import spring.dao.CustomerDAO.ComponentScan;
import spring.model.Customer;
import java.util.List;
#Repository
public class CustomerDAO {
public #interface ComponentScan {
}
#Autowired
private SessionFactory sessionFactory;
public SessionFactory getSessionFactory() {
return sessionFactory;
}
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public void addCustomer(Customer customer) {
getSessionFactory().getCurrentSession().save(customer);
}
public void deleteCustomer(Customer customer) {
getSessionFactory().getCurrentSession().delete(customer);
}
public void updateCustomer(Customer customer) {
getSessionFactory().getCurrentSession().update(customer);
}
public Customer getCustomerById(int id) {
List list = getSessionFactory().getCurrentSession().createQuery("from Customer where id=?").setParameter(0, id).list();
return (Customer)list.get(0);
}
public List<Customer> getCustomers() {
List list = getSessionFactory().getCurrentSession().createQuery("from Customer").list();
return list;
}
}
The goal of all this is about using Management functions as long as Login from same class. And as I'm following a tuto to learn, I can't know the exceptions or things that are impossible to do before asking about them.
Thank you
NO both DAO should remain sepparated.
You can (and should for what you explain) create a single service for all the management, in this service ManagementBS for example you must inject DAO's with #Autowired annotation.
What you can do is a BasicDAO using reflection for basic operation like save, getById, delete... shared between all classes.
The DAO can't be merged because login needs an interface which is has no superclass but an interface. This means both DAO remains but both inherit data from model UserDAO.

Mocking CGLIB enhanced objects

Is it true that mockito can't mock objects that were already enhanced by CGLIB?
public class Article {
#Autowired
private dbRequestHandler
#Autowired
private filesystemRequestHandler
#Transactional
public ArticleDTO getArticleContents() {
//extractText() and then save the data in DTO
//extractImages() and then save the data in DTO
// some other calls to other databases to save data in dto
return articleDTO;
}
public void extractText() {
//call to DB
}
public void extractImages() {
// call to file system
}
}
public class IntegrationTest {
#Autowired
private Article article;
//setup method {
articleMock = Mockito.spy(article);
doNothing().when(articleMock).extractImages();
}
}
In the above example when it comes to doNothing().when(articleMock).extractImages(); it actually calls the real function. On a closer look articleMock gets enhanced two times. One cause of autowiring and second time cause of spying.
If I can't spy on enhaced objects, then how can I test the getArticle() method in my Integration test, so that I can verify a proper DTO is returned.
Note : I actually don't want to test the method which does filesystem calls. just the DB ones. thats why I need to test the getArticle method.
If I understand correctly your class is wired by Spring. Spring uses CGLIB to ensure transactional behaviour only if there is no interface, which is implemented by your object. If there is an interface, it uses simple JDK Dynamic Proxies. (see http://docs.spring.io/spring/docs/3.0.0.M3/reference/html/ch08s06.html)
Maybe you could try to extract an interface, and let Spring to use dynamic proxies. Maybe then Mockito could perform better.
If you run as a true unit test and not as an integration test, you need not run in a container having Spring autowire for you. In one of your comments, I think you alluded to trying this, and you noted that there was an endless set of chained object references which you would have to provide as well. But there is a way around that. Mockito provides some predefined Answer classes that you can initialize your mock with. You may want to look at RETURNS_DEEP_STUBS, which will possibly get you around this problem.
Will you please update your question with ready-to-go compilable code. Here's some code review suggestions:
Issues with this question code:
Article.java missing import: org.springframework.beans.factory.annotation.Autowired
Article.java missing import: org.springframework.transaction.annotation.Transactional
Article.java attribute syntax issue: dbRequestHandler
Article.java attribute syntax issue: filesystemRequestHandler
Article.java method has no initialized return statement: articleDTO
Here's what you maybe should use as you questionCode with the above issues fixed:
Article.java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
public class Article {
#Autowired
private Object dbRequestHandler;
#Autowired
private Object filesystemRequestHandler;
#Transactional
public ArticleDTO getArticleContents() {
// extractText() and then save the data in DTO
// extractImages() and then save the data in DTO
// some other calls to other databases to save data in dto
ArticleDTO articleDTO = null;
return articleDTO;
}
public void extractText() {
// call to DB
}
public void extractImages() {
// call to file system
}
}
IntegrationTest.java is a poor name for a testClass because it's to generic. I would suggest ArticleTest for a java unit test.
ArticleTest.java
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.springframework.beans.factory.annotation.Autowired;
#RunWith(PowerMockRunner.class)
#PrepareForTest(ClassWithPrivate.class)
public class ArticleTest {
#InjectMocks
private Article cut;
#Mock
private Object dbRequestHandler;
#Mock
private Object filesystemRequestHandler;
#Test
public void testeExtractImages() {
/* Initialization */
Article articleMock = Mockito.spy(cut);
/* Mock Setup */
Mockito.doNothing().when(articleMock).extractImages();
/* Test Method */
ArticleDTO result = cut.getArticleContents();
/* Asserts */
Assert.assertNull(result);
}
}
You can utilize AdditionalAnswers.delegatesTo method. In following example, the secondProxyDoingMocking declaration creates something like a spy (compare with implementation of spy() method) except it uses "lightweight" method delegation.
import org.mockito.AdditionalAnswers;
public class ArticleTest {
#Autowired
private Article firstProxyDoingAutowiring;
#Test
public void testExtractImages() {
Article secondProxyDoingMocking = Mockito.mock(Article.class,
Mockito.withSettings().defaultAnswer(
AdditionalAnswers.delegatesTo(firstProxyDoingAutowiring)
)
);
Mockito.doNothing().when(secondProxyDoingMocking).extractImages();
...
}
}
I didn't test this example, however I assembled it from my working code. My use case was similar: return constant value for given method, call real method for all remaining methods of Spring #Transactional-annotated bean.

On Services, Daos and in between - a beginner's dilemma

I'm pretty new to layered architecture, + spring + hibernate
after reading some guides on how the class hierarchy is supposed to be -
i came up with this structure:
public interface GenericDAO {
public <T> T getItemById(long id, Class<T> c);
public <T> int save(T... objectsToSave);
public <T> int saveOrUpdate(T... objectsToSave);
public <T> int delete(T... objectsToDelete);
.
.
}
now all my other daos impls are using this generic dao as a private field in order to use its basic methods:
i.e:
#Repository
public class UserDAOImpl implements UserDao {
#Autowired
private GenericDAO dao;
#Override
public int deleteUser(User u) {
return dao.delete(u);
}
.
.
.
}
My services are like this :
#Service
public class UserServiceImpl implements UserService {
#Autowired
private UserDao userDao;
#Transactional(readOnly = false)
public int deleteUser(User u) {
return userDao.deleteUser(u);
}
.
.
.
}
I don't get why i need a UserDaoImpl , CarDaoImpl, XDaoImpl in my project? it seems really redundant since all the XDaoImpls looks the same:
#Repository
public class UserDAOImpl implements UserDao {
#Autowired
private GenericDAO dao;
#Override
public int deleteUser(User u) {
return dao.delete(u);
}
.
.
.
}
#Repository
public class CarDAOImpl implements CarDao {
#Autowired
private GenericDAO dao;
#Override
public int deleteCar(Car c) {
return dao.delete(c);
}
.
.
.
}
#Repository
public class XDAOImpl implements XDao {
#Autowired
private GenericDAO dao;
#Override
public int deleteX(X c) {
return dao.delete(c);
}
.
.
.
}
I could just not create any XDaoImpl and just use the GenericDaoImpl instead and save alot of classes creation, no?
If ill need any complex actions like deleteUserCar(User u) i can just implement the logic in the service:
UserService {
public void deleteUserCar(User u) {
Car c = u.getCar();
CarService cs.deleteCar(c);
}
}
Am i missing something?
can anyone please offer an example that using only GenericDaoImpl instead of XDaoImpl will make me regret it?
thanks
Your service will later on invoke businesslogic instead of just passing methods to the DAO. It may validate values (e.g. does it exist and is it supposed to be unique), run calculations (e.g. int getStock() { return bought - sold; } and so on.
A generic DAO is great, though consider a abstract class instead of an interface. This way you don't need to create multiple create()s, just extend the abstract DAO (e.g. CarDAO extends AbstractDAO<Car>).
Your extended DAO will pass the class it handles to the generic abstract DAO (as seen in previous example).
Your extended DAO will later on implement extra methods that only apply on that particular object, e.g.: List<Car> getCarsWithColor(Color color).
Your Service -> DAO relationship is not always one-on-one. Consider these DAOs: TruckDAO, CarDAO, VanDAO with objects Truck extends Vehicle, Car extends Vehicle, Van extends Vehicle. Do you need three services, or will a VehicleService cover it (will you run logic for all Vehicles perhaps)?
Reconsider the use of interfaces, this question applies to C# but the concept is the same.
My advice is: Just keep it simple! Please don't create too much abstraction that leads to too much complexity, remember that if you create create so much code that you don't need, that code you will be forced to mantain: tons of trash that you don't even know what was its purpose, tons of code that obscure the real objectives of your application.
So in this particular case I advice to :
Forget about creating DAO interfaces: They are intended to abstract the DAO implementations in order to switch 'easily' from databases (eg. MySQL to SQLServer) but think!: that is a really rare thing: it is more common to switch systems than to switch databases
Put that GenericDao in the trash (The world is not about CRUDs, go to your stakeholders and ask what they really need)
Use a simple DAO Layer and Service Layer, you can implement that with Spring: I imagine
that you can use a SimpleJDBCTemplate in DAO Layer and call that DAO methods in Service layer
Why use Spring after all? Have you asked yourself what's its purpose?, Currently I work with MyBatis in this way: I create Mappers (something analogous to DAOs) that are called by POJO services. Simple, useful and straightforward, no Spring, plain old Java, works like champ.

Categories