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?
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:
Create a singleton services for all your needs
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.
Related
I have trouble with initializing bean and injecting JPA repository into one particular bean. No idea why it doesn't work...
There is a interface defining key service:
public interface KeyService {
Store getKeyStore();
Store getTrustStore();
}
and abstract class that implements this interface:
public abstract class DefaultKeyService implements KeyService {
abstract KeyRecord loadKeyStore();
abstract KeyRecord loadTrustStore();
/* rest omitted... */
}
and base class that extends abstract class:
#Service
public class DatabaseKeyService extends DefaultKeyService {
#Autowired
private KeyRecordRepository keyRecordRepository;
#Override
protected KeyRecord loadKeyStore() {
return extract(keyRecordRepository.findKeyStore());
}
#Override
protected KeyRecord loadTrustStore() {
return extract(keyRecordRepository.findTrustStore());
}
/* rest omitted... */
}
And bean initialization:
#Bean
public KeyService keyService() {
return new DatabaseKeyService();
}
This is a KeyRecordRepository repository:
public interface KeyRecordRepository extends Repository<KeyRecord, Long> {
KeyRecord save(KeyRecord keyRecord);
#Query("SELECT t FROM KeyRecord t WHERE key_type = 'KEY_STORE' AND is_active = TRUE")
Iterable<KeyRecord> findKeyStore();
#Query("SELECT t FROM KeyRecord t WHERE key_type = 'TRUST_STORE' AND is_active = TRUE")
Iterable<KeyRecord> findTrustStore();
KeyRecord findById(long id);
}
Question: is there some reason why keyRecordRepository in DatabaseKeyService class is still null? Really I have no idea why only this this field is not injected. Other beans and repositories works perfectly fine.
Couldn't be a problem because parent class is an abstract class?
DatabaseKeyService must be annotated with #Component to be a Spring managed bean.
Your problem is related with having 2 beans for class DatabaseKeyService. One from configuration class - #Bean annotation and second from #Service annotation.
Probably when you remove
#Bean
public KeyService keyService() {
return new DatabaseKeyService();
}
injecting with #Service will be work.
If you want use #Bean you must add KeyRecordRepository. I prefer using constructor injection so firstly create it in DatabaseKeyService
public DatabaseKeyService(KeyRecordRepository keyRecordRepository) {
this.keyRecordRepository = keyRecordRepository;
}
Then in your configuration file
//other
#Autowired
private KeyRecordRepository keyRecordRepository;
#Bean
public KeyService keyService() {
return new DatabaseKeyService(keyRecordRepository);
}
I created a spring application where i decided to add a BaseDAO to eliminate redundant create,
update,delete,findByid,and findAll methods for every dao. So i created a baseDao and every dao should extend this BaseDAO.
BaseDaoImpl
public class BaseDAOImpl implements BaseDAO{
SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory sf){
this.sessionFactory = sf;
}
#Override
public void create(ModelBase modelBase) {
Session session = this.sessionFactory.getCurrentSession();
session.persist(modelBase);
}
#Override
public void update(ModelBase modelBase) {
Session session = this.sessionFactory.getCurrentSession();
session.update(modelBase);
}
#Override
public Collection findAll(Class aClass) {
Session session = this.sessionFactory.getCurrentSession();
Collection modelCols = session.createQuery("from "+aClass.getSimpleName()).list();
return modelCols;
}
#Override
public ModelBase findById(Class aClass, Integer id) {
Session session = this.sessionFactory.getCurrentSession();
ModelBase modelBase = (ModelBase) session.load(aClass, new Integer(id));
return modelBase;
}
}
Then i extends this Dao to each DAO
EmployeeDAOImp
public class EmployeeDAOImpl extends BaseDAOImpl implements EmployeeDAO{
private SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory sf){
this.sessionFactory = sf;
}
}
I created a BaseService like this. But when i try to access BaseDAO methods from EmployeeDAO it returns null pointer exception.
Why this happen. I dont want to use genericDAO from google. Because we should create DAOs
for each model. I want to eliminate this. So I follow this method.
Have you though about Spring Data project & Spring Data JPA in particular?
This would save you lots of time, since you would no longer need to write your DAO / Repositories from scratch, all you need to do is enable Spring Data JPA, and add needed interfaces. It should save you tons of time.
http://projects.spring.io/spring-data-jpa/
http://spring.io/guides/gs/accessing-data-jpa/ - Sample project
Your are overriding setSessionFactory from base class for no reason, its already available with extending class EmployeeDAOImpl , either remove it or try below:
public class EmployeeDAOImpl extends BaseDAOImpl implements EmployeeDAO{
//this reference should be from base class,
// the extending class ref is hiding base ref.
// private SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory sf){
super.setSessionFactory(sf);
}
}
Something like the following should work (note the use of constructor rather than setter injection). In the BaseDAO:
public class BaseDAOImpl implements BaseDAO {
private final SessionFactory sessionFactory;
public BaseDAOImpl(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
}
Then in the Employee DAO:
public class EmployeeDAOImpl extends BaseDAOImpl implements EmployeeDAO {
#Inject
public EmployeeDAOImpl (SessionFactory sessionFactory) {
super(sessionFactory);
}
}
You can create generic dao.
#Repository("genericDao")
public class GenericDaoImpl<T,PK extends Serializable> implements GenericDao<T, PK> {
protected Class<T> entityClass;
public T create(T t) {
this.entityManager.persist(t);
return t;
}
public T read(PK id,Class<T> c) {
return (T)this.entityManager.find(c, id);
}
public T update(T t) {
return this.entityManager.merge(t);
}
public void delete(T t) {
t = this.entityManager.merge(t);
this.entityManager.remove(t);
}
public List<T> getAll(Class<T> c){
return this.entityManager.createQuery("SELECT o FROM "+ c.getName() +" o").getResultList();
}
}
UPDATED
You can use as following, TimeRange is a pojo class in the following example. If you do not want a service layer. You can use timeRangeDao in controller.
#Service("timeRangeService")
public class TimeRangeServiceImpl implements TimeRangeService{
#Autowired
GenericDao<TimeRange,Long> timeRangeDao;
public List<TimeRange> getAllTimeRanges(){
return timeRangeDao.getAll(TimeRange.class);
}
#Transactional
public void createTimeRange(TimeRange c) {
timeRangeDao.create(c);
}
#Transactional
public void update(TimeRange p) {
timeRangeDao.update(p);
}
#Transactional
public TimeRange getTimeRange(long id) {
return timeRangeDao.read(id, TimeRange.class);
}
#Transactional
public void delete(long id) {
TimeRange timeRange = new TimeRange();
timeRange.setId(id);
timeRangeDao.delete(timeRange);
}
}
I have a method defined in an implementing #Repository class that is an extension of an abstract base class and implements an interface. However, a method defined in the #Repository class is not visible in the #Service class, and I am not sure why.
I have a #Service class defined as
#Service
#Transactional
public class CategoryService {
#Autowired
private IJpaRepository categoryRepository;
public CategoryService(){ }
/* service methods */
public List<Category> findTopLevelCategories(){
//findTopLevelCategories is not visible here
return categoryRepository.findTopLevelCategories();
}
}
where IJpaRepository is an interface defined by
public interface IJpaRepository<T> {
T findOne(int id);
List<T> findAll();
T create(T entity);
T update(T entity);
void delete(T entity);
void deleteById(int id);
}
and the #Repository is defined as an extension of an abstract class implementing the interface above:
#Repository
public class CategoryRepository extends AbstractJpaRepository<Category> implements IJpaRepository<Category> {
public List<Category> findTopLevelCategories(){
Query queryCategoryTopLevel = getEntityManager().createNamedQuery("findTopLevelCategories");
return queryCategoryTopLevel.getResultList();
}
/* Other overriding methods */
}
My best guess is that it is due to the #Autowired binding to the IJpaRepository, rather than the actual implementing CategoryRepository class. Without making any changes to IJpaRepository interface, how can I make the new method defined in CategoryRepository visible to the #Service class?
I'm building a small application using Spring and Spring Data JPA and I need to use the CrudRepository methods in the service layer, so I made 2 classes: GenericService and GenericServiceImpl. But I don't know if this is the right or even the best approach.
Here is an example:
POJO:
#Entity
public class User {
#Id
private Long id;
private String username;
}
DAO:
public interface UserDAO extends CrudRepository<User, Long> {
User findOneByUsername(String username);
}
Generic service
public interface GenericService<T, ID extends Serializable> {
<S extends T> S save(S entity);
}
Service
public interface UserService extends GenericService<User, Long> {
User findOneByUsername(String username);
}
Generic service impl.
public class GenericServiceImpl<T, ID extends Serializable> implements GenericService<T, ID> {
#Autowired
private CrudRepository<T, ID> repository;
#Override
public <S extends T> S save(S entity) {
return repository.save(entity);
}
}
Service Impl.
#Service
#Transactional
public class UserServiceImpl extends GenericServiceImpl<User, Long> implements UserService {
#Autowired
private UserDAO userDAO;
#Override
public User findOneByUsername(String username) {
userDAO.findOneByUsername(username);
}
}
Yes, you're providing your own impl that's may do custom things while still reusing the Derived queries from Spring JPA's CrudRepository. I've seen that a lot. :) We need to do that if we want to do our own computation before calling the Derived methods. After all, that computation may very well be part of a repository, so it doesn't make sense to put that logic in the service. But in your scenario, if there are no such custom computations, then this indirection isn't needed. As a commenter mentioned, you should directly use the UserDao interface. :)
I have developed a GenericDAO interface with two generic types, the entity and the type of the primary key:
public interface GenericDAO<E, PK extends Serializable> {
PK save(E newInstance);
void update(E transientObject);
//typical dao methods
}
Then I have provided an implementation for them in hibernate 4:
#Transactional
#Component
#Repository
public abstract class GenericDAOHibernate4<E, PK extends Serializable> implements GenericDAO<E, PK> {
public PK save(E newInstance) {
return (PK) factory.getCurrentSession().save(newInstance);
}
public E findById(PK id) {
return (E) factory.getCurrentSession().get(getEntityClass(), id);
}
//method implementations
}
Then I just have to create concrete classes extending this abstract class:
#Component
#Transactional
#Repository
#Qualifier("userDAO")
public class UserDAO extends GenericDAOHibernate4<User, Long> {
#Autowired
public UserDAO(SessionFactory factory) {
super(factory);
}
#Override
protected Class<User> getEntityClass() {
return User.class;
}
}
Then I inject the concrete DAOs when needed this way:
public class UserService extends GenericService<User> {
#Autowired
public UserService(#Qualifier("userDAO") GenericDAO<User, Long> dao) {
super(dao);
}
But, if I need to add another method to the concrete dao, and therefore inject the concrete class, spring cannot find the dependency. This fails at startup:
public class UserService extends GenericService<User> {
#Autowired
public UserService(#Qualifier("userDAO") UserDAO dao) {
super(dao);
}
With this error:
Could not instantiate bean class [ddol.rtdb.services.UserService]: No default constructor found; nested exception is java.lang.NoSuchMethodException: ddol.rtdb.services.UserService.()
How should I inject it?
If a class implements an interface, a bean of that class can only be autowired using the interface type and not the concrete class type. Since UserDao implements the GenericDAO<User, Long> interface, it is being autowired correctly when you autowire using the interface. Spring is not able to find the dependency when you try to autowire using the concrete class, then it looks for a no-arg constructor for UserService and fails giving the particular error on not finding any.
In general, it not a good idea to inject dependencies using concrete classes because it tightly couples your modules. Right way to do this is to have an interface for each of your DAO classes and have their implementation extending the GenericDAOHibernate4.
public interface GenericDAO<E, PK extends Serializable> {
PK save(E newInstance);
void update(E transientObject);
//typical dao methods
}
public interface UserDAO extends GenericDAO<User, Long> {
List<User> findUsersByFirstname(String firstName);
}
#Component
#Transactional
#Repository
#Qualifier("userDAO")
public class UserDAOImpl extends GenericDAOHibernate4<User, Long>
implements UserDAO {
#Autowired
public UserDAO(SessionFactory factory) {
super(factory);
}
#Override
protected Class<User> getEntityClass() {
return User.class;
}
List<User> findUsersByFirstname(String firstName) {
//provide implementation here
}
}
public class UserService extends GenericService<User> {
#Autowired
public UserService(#Qualifier("userDAO") UserDAO dao) {
super(dao);
}
}
#Autowired = wire by Type
#Resource = wire by bean name