0
votes

I'm trying to follow code reusing best practices. I have generic DAO interface with some common methods:

    public interface DaoInterface<T> {
        T findById(int id);
        //...more methods...
    }

and its implementation class:

    public class GenericDao<T> implements DaoInterface<T> {

        @SuppressWarnings("unchecked")
        private final Class<T> persistentClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];

        @Autowired
        protected SessionFactory sessionFactory;

        @Override
        @SuppressWarnings("unchecked")
        public T findById(int id) {
            Session session = sessionFactory.getCurrentSession();
            return (T) session.get(persistentClass, id);
        }

        //...more methods...
    }

Then my every concrete implementation class extends GenericDao and implements its interface.

I also have Service layer in my application. Some Services' methods completely delegate their work to DAO classes. So in the each concrete Service implementation I autowire appropriate DAO class and call its methods. So now it looks:

public interface CustomerService {
    Customer findById(int id);
}

and implementation:

@Service
@Transactional(readOnly = true, rollbackFor = Exception.class)
public class CustomerServiceImpl implements CustomerService {

    @Autowired
    private CustomerDao customerDao;

    @Override
    public Customer findById(int id) {
        return customerDao.findById(id);
    }
}

My question is - how to generify Service classes in the same way as DAO? So that my concrete class will look:

public class CustomerServiceImpl extends GenericService<Customer> implements CustomerService {
.....
}

The problem is that I cannot autowire DAO class in Generic Service:

@Autowired
private GenericDao<T> dao;

so that I could call dao's methods. Should I do it in the constructor?

And one more question - where is the right place to annotate methods with @Transactional - in generic class or in every implementation class?

1
There are either too many possible answers, or good answers would be too long for this format. Please add details to narrow the answer set or to isolate an issue that can be answered in a few paragraphs.Roman C
The main question is how to autowire the GenericDao of type <T> in the GenericService<T> class?DimaSan

1 Answers

2
votes

You have to create an instance of a generic Dao and put in the service layer some decision:

 @Repository
 public class GenericDao implements DaoInterface<T> {
 //The type must be aquired at runtime,otherwise it may not be thread safe

    @Autowired
    protected SessionFactory sessionFactory;

    @Override
    @SuppressWarnings("unchecked")
    public T findById(int id,Class<?> persistenceClass) {
        Session session = sessionFactory.getCurrentSession();
        return (T) session.get(persistenceClass, id);
    }

    //...more methods...
}

Also if you need a good generic repository layer take a look for Spring Data Jpa

This will make one and only one instance of the GenericDao.

Next you have 2 choice:

  1. Create a singleton services for all your needs
  2. Create a class service for every entity

    abstract class GenericService<T> {
        @Autowired
        protected GenericDao dao;
        @SuppressWarnings("unchecked")
        protected final Class<T> persistentClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
    
        @Override
        public T  findById(int id) {
            return dao.findById(id,persistenceClass);
        }   
    }
    

    Now every one of your service must extends the GenericService with a supplied persistence type and the job is done.