When I execute from DAO layer(ProjectDAOImpl), I'am able to see the results from database.
However when I execute from results from Service layer, I'am getting null pointer exceptions.
java.lang.NullPointerException
ProjectServiceImpl.fetchProjects(ProjectServiceImpl.java:25)
ProjectServiceImpl.main(ProjectServiceImpl.java:36)
How can I resolve this issue?
DAO Layer Interface and Class
#Remote
public interface ProjectDAO {
List<Project> fetchProjectDetail();
}
#Stateless
public class ProjectDAOImpl implements ProjectDAO {
private EntityManagerFactory entityManagerFactory =
Persistence.createEntityManagerFactory("projects");
public ProjectDAOImpl() {
}
public List<Project> fetchProjectDetail() {
List<Project> listProject = new ArrayList<Project>();
listProject =
getEntityManager().createNamedQuery("Project.findProjects").getResultList();
return listProject;
}
private EntityManager getEntityManager() {
return entityManagerFactory.createEntityManager();
}
}
Service Layer Interface and Class
#Remote
public interface ProjectService {
List<Project> fetchProjectDetail();
}
#Stateless
public class ProjectServiceImpl implements ProjectService {
private ProjectDAO projectDAO;
public ProjectServiceImpl() {
}
#EJB
public void setProjectDAO(ProjectDAO projectDAO) {
this.projectDAO = projectDAO;
}
#GET
#Path("/projects")
#Produces(MediaType.APPLICATION_JSON)
public List<Project> fetchProjects() {
return getProjectDAO().fetchProjectDetail();
}
public ProjectDAO getProjectDAO() {
return projectDAO;
}
public static void main(String [] args) {
ProjectServiceImpl projectServiceImpl = new ProjectServiceImpl();
projectServiceImpl.fetchProjects();
}
}
Related
Good afternoon, I am trying to get the data from my database. My application is with abse in microservices which has the following
This is my class for the database configuration.
#ApplicationScoped
public class DbConfig {
#Inject
#ConfigProperty(name = "db.connection.username")
private String dbUser;
#Inject
#ConfigProperty(name = "db.connection.password")
private String dbPassword;
#Inject
#ConfigProperty(name = "db.connection.url")
private String dbUrl;
#Produces
#ApplicationScoped
public EntityManager entityManager() {
Map<String, String> properties = new HashMap<>();
properties.put("javax.persistence.jdbc.url", dbUrl);
properties.put("javax.persistence.jdbc.user", dbUser);
properties.put("javax.persistence.jdbc.password", dbPassword);
EntityManagerFactory emf = Persistence.createEntityManagerFactory("persistence-books", properties);
return emf.createEntityManager();
}
}
This is my RepositoryImpl class book
#ApplicationScoped
public class BookRepositoryImpl implements BookRepository {
#PersistenceContext
EntityManager entityManager;
#Override
public List<Book> findAll() {
try {
TypedQuery<Book> query = entityManager.createQuery("SELECT b FROM Book b ORDER BY b.id ASC", Book.class);
return query.getResultList();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
..// another CRUD methods
This is my rest class
#ApplicationScoped
#Path("/books")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public class BookRest {
#GET
public List<Book> findAll() {
System.out.println("Buscando todos");
return bookService.findAll();
}
..// another CRUD Methods
}
The problem arises when I start the application through the server class, it starts correctly at localhost:7001, but in order to verify that it is working correctly I need to list the data in the database through localhost:7001/books, which gives me this error Cannot invoke "jakarta.persistence.EntityManager.createQuery(String, java.lang.Class)" because "this.entityManager" is null
how can i inject EntityManager(jpa) with Mockito?
I wanna bind Mockito.spy(UserService.class) to guice injector.
but UserService.class has EntityManager for query execution.
When installing 'JunitServiceModule' in guice injector, EntityManager is not found.
See below for error details
com.google.inject.CreationException: Unable to create injector, see the following errors:
1) Error in custom provider, java.lang.NullPointerException
while locating com.google.inject.persist.jpa.JpaPersistService
while locating javax.persistence.EntityManager
My code is below.
(The test code just made the error situation similar.)
(actually 'EntityManager' is located in UserRepository... It's just example!)
(#Transactional is belong to guice)
public class UserServiceTest {
#Inject
private UserService userService;
#Before
public void setUp() {
Injector injector = new TestBuilder().init();
injector.initMembers(this);
Mockito.doReturn(10).when(userService).getEntityCount(UserEntity.class);
}
#Test
public void test() {
assertEquals(10, userService.getEntityCount(UserEntity.class));
}
}
public class TestBuilder {
public TestBuilder() {
}
public Injector init() {
Injector injector = Guice.createInjector(
new TestDBInjectModule("test"),
new JunitServiceModule()
);
}
}
public class TestDBInjectModule extends AbstractModule {
private String unitName;
public TestDBInjectModule(String unitName) {
this.unitName = unitName;
}
#Override
protected void configure() {
install(new JpaPersistModule(unitName));
bind(JpaInitializer.class).asEagerSingleton();
}
#Singleton
private static class JpaInitializer {
#Inject
public JpaInitializer(final PersistService persistService) {
persistService.start();
}
}
}
public class JunitServiceModule extends AbstractModule {
#Override
protected void configure() {
bind(UserService.class).toInstance(Mockito.spy(UserService.class));
}
}
public class UserService {
#Inject
private EntityManager entityManager;
public UserService {} // <-- throw NullPointerException!!! since EntityManager
#Transactional
public void addUser(User user) {
return entityManager.persist(user);
}
public Number getCount() {
return entityManager.createQuery("select count(*) from user", Number.class).getSingleResult();
}
}
I have generic abstract class AbstractBaseEntityGenericDao which contains #Autowired field. It worked perfectly until I had to write a unit test for it, to not duplicate the same code inside all tests for classes which extends it. And now I'm thinking...Is it possible to write a unit/integration test for such class?
#Repository
#Transactional
public abstract class AbstractBaseEntityGenericDao<T extends BaseEntity> {
private Class<T> classInstance;
private SessionFactory sessionFactory;
#Autowired
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public final void setClassInstance(Class<T> clasInstance) {
this.classInstance = clasInstance;
}
public void create(#NonNull T entity) {
Session session = sessionFactory.getCurrentSession();
session.save(entity);
}
public Optional<T> find(long id) {
Session session = sessionFactory.getCurrentSession();
return Optional.ofNullable(session.get(classInstance, id));
}
public void update(#NonNull T entity) {
Session session = sessionFactory.getCurrentSession();
session.saveOrUpdate(entity);
}
public void remove(#NonNull Long id) throws EntityNotFoundException {
Session session = sessionFactory.getCurrentSession();
session.remove(session.load(classInstance, id));
}
public void remove(#NonNull T entity) {
Session session = sessionFactory.getCurrentSession();
session.remove(entity);
}
}
The reason this is difficult is because generally you should not be doing this. The abstract class should have no knowledge of how its child creates SessionFactory. so instead it should look something like:
#Repository
#Transactional
public abstract class AbstractBaseEntityGenericDao<T extends BaseEntity> {
...
protected SessionFactory sessionFactory;
...
}
Now you CANNOT directly unit test a abstract class as it can not be instantiated. you can however stub it out in a unit test, and test that stub. The stub in turn will have a constructor for the protected field which we can mock out in the unit test. In the end it would look like:
public class AbstractBaseEntityGenericDaoTest {
private class AbstractClassStub extends AbstractBaseEntityGenericDao {
public AbstractClassStub(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
#Override
public void create(BaseEntity entity) {
super.create(entity);
}
#Override
public Optional find(long id) {
return super.find(id);
}
#Override
public void update(BaseEntity entity) {
super.update(entity);
}
#Override
public void remove(#NonNull Long id) throws EntityNotFoundException {
super.remove(id);
}
#Override
public void remove(BaseEntity entity) {
super.remove(entity);
}
}
#Mock
SessionFactory sessionFactory;
private AbstractClassStub abstractClassStub;
#Before
public void before() {
sessionFactory = mock(SessionFactory.class);
abstractClassStub = new AbstractClassStub(sessionFactory);
}
#Test
public void testWhatever() {
abstractClassStub.find(1); //or whatever
}
}
I want to call all the request mapping method(which has #Resource injection) before the server starts. How I can do this?
#Controller
public class ServiceController {
#Resource(name="userService")
private IUserService userService;
#RequestMapping("/getAllCountry")
public String getAllCountry() {
return userService.getAllCountry();
}
#RequestMapping("/getAllStates")
public String getAllStates() {
return userService.getStates();
}
#PostConstruct
public void cacheData(){
cache.put("ALL_COUNTRY_DATA", getAllCountry());
cache.put("ALL_STATE_DATA", getAllStates());
}
}
The above code fails and give me IllegalStateException. What is the best way to call the request mapping methods before the server is up and populate the cache.
Try using ApplicationListener in conjunction with ContextRefreshedEvent:
#Controller
public class ServiceController implements ApplicationListener<ContextRefreshedEvent> {
private static final Map<String, String> cache = new HashMap<>();
#Resource(name = "userService")
private IUserService userService;
#RequestMapping("/getAllCountry")
public String getAllCountry() {
return userService.getAllCountry();
}
#RequestMapping("/getAllStates")
public String getAllStates() {
return userService.getStates();
}
public void cacheData() {
cache.put("ALL_COUNTRY_DATA", getAllCountry());
cache.put("ALL_STATE_DATA", getAllStates());
}
#Override
public void onApplicationEvent(ContextRefreshedEvent event) {
cacheData();
}
}
So I have such classes
BaseDao
public interface BaseDao<T> {
T save(T entity);
}
UserDao
public interface UserDao extends BaseDao<User> {
User getUserByUserName(String name);
}
GenericDao
public abstract class GenericDao implements BaseDao {
#Autowired
protected SessionFactory sessionFactory;
private Class<?> getEntityClass() {
return ((Class) ((ParameterizedType) getClass().getGenericSuperclass())
.getActualTypeArguments()[0]);
}
public T save(T entity) {
Integer id = (Integer) sessionFactory.getCurrentSession().save(entity);
return (T) sessionFactory.getCurrentSession().get(getEntityClass(), id);
}
}
UserDaoImpl
#Repository
public class PgUserDaoImpl extends GenericDao<User> implements UserDao {
public User getUserByUserName(String name) {
Criteria criteria = sessionFactory.getCurrentSession().createCriteria(
User.class);
criteria.add(Restrictions.eq("name", name));
return (User) criteria.uniqueResult();
}
}
GenericService
public class GenericService<T extends GenericDao<E>, E> {
protected T dao;
public GenericService(T dao) {
setDao(dao);
}
#Transactional
public E save(E entity) {
return dao.save(entity);
}
}
UserServiceImpl
#Service("userServiceImpl")
public class UserServiceImpl extends GenericService<PgUserDaoImpl, User>
implements UserService {
#Autowired
public UserServiceImpl(PgUserDaoImpl dao) {
super(dao);
}
#Autowired
private UserAssebmler assebmler;
#Transactional
#Override
public UserDetails loadUserByUsername(String name)
throws UsernameNotFoundException {
.....
}
}
So I write test contoller to save user, but I always get Exception
org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here
The contoller
#
Controller
#RequestMapping(value = "/test")
public class TestController {
#Autowired
private UserServiceImpl userService;
#RequestMapping(value = "save", method = RequestMethod.GET)
public String test() {
User user = new User();
user.setName("admin");
user.setPassword("21232f297a57a5a743894a0e4a801fc3");
user.setRole(UserRole.ADMIN);
userService.save(user);
return "home";
}
}
Anybody know hot to fix that? Thanks :)
I've solved my question by extending GenericDao class from HibernateDaoSupport class.