GenericDao, Class<T> is null - java

I'm implementing GenericDao. I have problem with 2 methods - getAll() and getById(Long id), entity class has null value. It looks like the class is not setted. How Can I solve this problem ?
#Repository
public class GenericDaoImpl<T> implements GenericDao<T> {
private Class<T> clazz;
#Autowired
SessionFactory sessionFactory;
public void setClazz(final Class<T> clazzToSet) {
this.clazz = clazzToSet;
}
public T getById(final Long id) {
return (T) this.getCurrentSession().get(this.clazz, id);
}
public List<T> getAll() {
Criteria criteria = sessionFactory.getCurrentSession().createCriteria(
this.clazz);
return criteria.list();
}
protected final Session getCurrentSession() {
return this.sessionFactory.getCurrentSession();
}
}
PersonDao
public interface PersonDao extends GenericDao<Person> { }
PersonDaoImpl
#Repository("PersonDAO")
public class PersonDaoImpl extends GenericDaoImpl<Person> implements PersonDao {}
Service:
#Service
public class PersonServiceImpl implements PersonService {
#Autowired
private PersonDao personDao;
#Transactional
public List<Person> getAll() {
return personDao.getAll();
}
#Transactional
public Person getById(Long id) {
return personDao.getById(id);
}
}

You must set the clazz property of PersonDao. This can be done by declaring a post initialization callback with the #PostConstruct annotation.
#Repository("PersonDAO")
public class PersonDaoImpl extends GenericDaoImpl<Person> implements PersonDao {
#PostConstruct
public void init(){
super.setClazz(Person.class);
}
}

Related

Why the entitymanager does not get autowired in spring boot?

I have an abstract repository class in which I used entitymanager and I want to initialize it with spring boot, but it gives an error that this object is null. What should I do? I used both #PersistenceContext on the entitymanager field and #EnableJpaRepositories on the main class, but the result is the same. What should I do?
#Getter
#NoArgsConstructor
#Transactional
#Repository
#Qualifier("personDAO")
public abstract class AbstractDAO<T> {
public EntityManager em;
#Transient
protected Class clazz;
public AbstractDAO(EntityManager em) {
this.em = em;
}
public void persist(T model) {
em.persist(model);
}
public void delete(T model) {
em.remove(model);
}
public boolean deleteById(int id) {
boolean result= em.createQuery("delete from "+clazz.getSimpleName()+ " o where o.id=" + id).executeUpdate() > 0;
return result;
}
public List<T> findAll() {
return em.createQuery("select o from "+clazz.getSimpleName()+" o").getResultList();}
public T findById(int id) {
return (T) em.find(clazz, id);
}
}
an example of its implementation:
public class SimpleDAOImpl extends SimpleDAO<Person> {
public SimpleDAOImpl(Class<?> clazz) {
this.clazz=Person.class;
}
}
exception:
Exception in thread "restartedMain" java.lang.reflect.InvocationTargetException
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:116)
at java.base/java.lang.reflect.Method.invoke(Method.java:578)
at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49)
Caused by: java.lang.NullPointerException: Cannot invoke "jakarta.persistence.EntityManager.persist(Object)" because "this.em" is null
at org.isoft.repo.AbstractDAO.persist(AbstractDAO.java:29)
at org.isoft.App.main(App.java:35)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
... 2 more
If you want to inject some bean in abstract class for its implementation classes, you need to use Autowired annotation on the initialization method instead of a constructor like
#Getter
#NoArgsConstructor
#Transactional
#Repository
#Qualifier("personDAO")
public abstract class AbstractDAO<T> {
public EntityManager em;
#Transient
protected Class clazz;
#Autowired
public init(EntityManager em) {
this.em = em;
}
public void persist(T model) {
em.persist(model);
}
public void delete(T model) {
em.remove(model);
}
public boolean deleteById(int id) {
boolean result= em.createQuery("delete from "+clazz.getSimpleName()+ " o where o.id=" + id).executeUpdate() > 0;
return result;
}
public List<T> findAll() {
return em.createQuery("select o from "+clazz.getSimpleName()+" o").getResultList();}
public T findById(int id) {
return (T) em.find(clazz, id);
}
}
Otherwise, Spring won't inject the bean and it will be null for implementations of this abstraction
Also you can inject this bean in every implementation of this class

How to add custom method all services spring data

I customizei a repository for all my repositories children have the same methods. The code is below the repository implementation.
This interface:
#NoRepositoryBean
public interface BaseMyRepository<T, ID extends Serializable> extends JpaRepository<T, ID>{
List<T> findCustomNativeQuery(String sqlQuery);
}
This implementation class:
public class BaseMyRepositoryImpl<T, ID extends Serializable> extends SimpleJpaRepository<T, ID> implements BaseMyRepository<T, ID>{
private final EntityManager entityManager;
public BaseMyRepositoryImpl(JpaEntityInformation entityInformation, EntityManager entityManager){
super(entityInformation, entityManager);
this.entityManager = entityManager;
}
#Transactional
#Override
public List<T> findCustomNativeQuery(String sqlQuery) {
List<T> lista = entityManager.createNativeQuery(sqlQuery, this.getDomainClass()).getResultList();
return lista;
}
}
This my repository:
public interface MyRepository extends BaseMyRepository<SmaempreEntity, Integer>{
}
Now I need to know if is possible do exemplify the code below:
#Service
#Transactional
public class MyBaseService<R extends BaseMyRepository, E> {
#Autowired
private R;
public List<E> findAll() {
return R.findAll();
}
public List<E> findCustomNativeQuery(String sqlQuery) {
return R.findCustomNativeQuery(sqlQuery);
}
}
public class MyService extends MyBaseService<MyRepository, MyEntity> {
}

Creating BaseDAO for Each Dao class

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);
}
}

Hibernate Transaction Manager - Java configuration

I've been beating my head against a wall for awhile now trying to get this to work. I have created the following data access object:
public interface GenericDAO<T, ID extends Serializable> {
T findById(ID id);
List<T> findAll();
T save(T entity);
void update(T entity);
void delete(T entity);
}
public class GenericHibernateDAO<T, ID extends Serializable> implements GenericDAO<T, ID> {
private final Class<T> persistentClass;
private final SessionFactory sessionFactory;
public GenericHibernateDAO(final SessionFactory sessionFactory) {
this.persistentClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
this.sessionFactory = sessionFactory;
}
protected Session getSession() {
return sessionFactory.getCurrentSession();
}
public Class<T> getPersistentClass() {
return persistentClass;
}
#Override
public T findById(final ID id) {
return (T) getSession().load(getPersistentClass(), id);
}
#Override #SuppressWarnings("unchecked")
public List<T> findAll() {
return findByCriteria();
}
protected List<T> findByCriteria(final Criterion... criterion) {
final Criteria crit = getSession().createCriteria(getPersistentClass());
for (final Criterion c : criterion) {
crit.add(c);
}
return crit.list();
}
#Override
public T save(final T entity) {
getSession().saveOrUpdate(entity);
return entity;
}
#Override
public void delete(final T entity) {
getSession().delete(entity);
}
#Override
public void update(final T entity) {
getSession().saveOrUpdate(entity);
}
}
#Repository
public class StockHibernateDAO extends GenericHibernateDAO<Stock, String> implements StockDAO {
#Inject
public StockHibernateDAO(final SessionFactory sessionFactory) {
super(sessionFactory);
}
}
I'm attempting to set this up with Java Configuration, so here is my configuration to setup my service layer:
#Configuration #Profile("hibernate")
#EnableCaching #EnableTransactionManagement
#ComponentScan("reference.dao.hibernate")
public class HibernateServiceConfig implements TransactionManagementConfigurer {
#Inject private StockDAO stockDao; //No extra methods, just the base stuff for now
#Bean(destroyMethod = "shutdown")
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.HSQL).addScript("classpath:schema.sql").build();
}
#Bean
public SessionFactory sessionFactory() {
return new LocalSessionFactoryBuilder(dataSource()).addAnnotatedClasses(Stock.class)
.setProperty("hibernate.show_sql", "true")
.setProperty("hibernate.cache.region.factory_class", "org.hibernate.cache.ehcache.EhCacheRegionFactory")
.setProperty("hibernate.cache.use_query_cache", "true")
.setProperty("hibernate.cache.use_second_level_cache", "true")
.setProperty("hibernate.dialect", "org.hibernate.dialect.HSQLDialect").buildSessionFactory();
}
#Override #Bean
public PlatformTransactionManager annotationDrivenTransactionManager() {
return new HibernateTransactionManager(sessionFactory());
}
}
Here is the TradingService:
#Service
public class TradingServiceImpl implements TradingService {
#Inject private StockDAO stockDAO;
#Override #Transactional
#CachePut(value = "stockCache", key = "#stock.name")
public Stock addNewStock(final Stock stock) {
stockDAO.save(stock);
return stock;
}
#Override #Cacheable(value = "stockCache")
public Stock getStock(final String stockName) {
return stockDAO.findById(stockName);
}
#Override #CacheEvict(value = "stockCache", key = "#stock.name")
public void removeStock(final Stock stock) {
stockDAO.delete(stock);
}
#Override #CacheEvict(value = "stockCache", key = "#stock.name")
public void updateStock(final Stock stock) {
stockDAO.update(stock);
}
#Override
public List<Stock> getAll() {
return stockDAO.findAll();
}
}
The saving of a stock only seems to be completed if I add a session.flush() to the save method. The way I understand things, having the TransactionManager and the #Transactional around the service layer method should in fact cause that call to be made for me. What is this configuration missing?
Because you are injecting a Session
#Bean
public Session session() {
return sessionFactory().openSession();
}
Spring cannot add it's transactional behavior around it. Let Spring open the session and do it's business.
Instead of injecting a Session, inject a SessionFactory. In your DAO, keep a attribute for SessionFactory and use sessionFactory.getCurrentSession() to acquire a session.
When Spring sees the #Transactional, it will get the SessionFactory, call openSession(), begin a transaction on it, then call your method. When your method returns successfully, it will close that transaction.
You should also probably #Autowired the dao in your service class.

Overriding the persistentce context unitName declared for the EntityManager in a parent class.

I have a generic DAO class that looks like this:
public class GenericDaoJpa <T extends DomainObject> implements GenericDao<T> {
private final Class<T> type;
#PersistenceContext(type=PersistenceContextType.TRANSACTION, unitName="myPersistenceUnit")
protected EntityManager entityManager;
public GenericDaoJpa(Class<T> type) {
super();
this.type = type;
}
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
public T get(Object id) {
return (T) entityManager.find(type, id);
}
}
The implementation DAO class looks like this:
#Repository("appDao")
public class ProductDaoJpa extends GenericDaoJpa<Product> implements ProductDao{
public ProductDaoJpa() {
super(Product.class);
}
public List<Product> getAllProducts() {
return getAll();
}
}
I have configured another persistentUnit called mySecondPersistenceUnit for a different database. I would like to create a new DAO class that will also extend the GenericDaoJpa class but use a different persistent unit. How can i extend the GenericDaoJpa class but use a different persisitent unit for each DAO?
I tried moving this declaration to each of the DAO classes but this causes the parent class not to compile because it has no reference to the entityManager.
#PersistenceContext(type=PersistenceContextType.TRANSACTION, unitName="myPersistenceUnit")
protected EntityManager entityManager;
Try to use method injection instead:
public class GenericDaoJpa <T extends DomainObject> implements GenericDao<T> {
#PersistenceContext(type=PersistenceContextType.TRANSACTION, unitName="myPersistenceUnit")
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
}
While child class that need use different PU:
#Repository("appDao")
public class ProductDaoJpa extends GenericDaoJpa<Product> implements ProductDao{
#Override
#PersistenceContext(type=PersistenceContextType.TRANSACTION, unitName="mySecondPersistenceUnit")
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
}

Categories