change entitymanager datasource in same session - java

in my session i need to call 2 diffrent procedures which are on db1 and db2. it works fine when i call them separetely but it fails when i call them in same session. it fetches first data correctly but it fails on second call since it looks for the second procedure on db1 although entitiymanager's datasource changed correctly.
what am i missing?
here is code snippet
#Repository
#Transactional
public class DB1Dao {
#PersistenceContext()
private EntityManager entityManager;
#SuppressWarnings("unchecked")
public Model1 getData(String param1) {
.....
}
}
#Repository
#Transactional
public class DB2Dao {
#PersistenceContext()
private EntityManager entityManager;
#SuppressWarnings("unchecked")
public Model2 getData(String param2) {
.....
}
}
#Autowired
private DB1Dao dao1;
#Autowired
private DB2Dao dao2;
#RequestMapping(value = "/inquiry", method = RequestMethod.POST)
public ResponseEntity<Object> inquiryService(#RequestBody InquiryRequest inquiryRequest){
....
Model1 model1 = dao1.getData(param2); // success
....
Model2 model 2 = dao2.getData(param2); // fails since it looks for second procedure on db1
}

You didn't show any persistence-related configuration info, but I'd guess you should differentiate your repositories by properly naming them:
#PersistenceContext(unitName = "db1PersitenceUnitName")
private EntityManager entityManager;

Related

Cannot invoke "jakarta.persistence.EntityManager.createQuery(String, java.lang.Class)" because "this.entityManager" is null

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

#Inject gives a NullPointer Exception in java EE

I'm trying to create a webservice that gives some results taken through hibernate from the database.
#Path("/book")
public class BookService {
#Inject
private dbController db;
#GET
#Produces(MediaType.TEXT_PLAIN)
public String getBookTitle() {
return "H2G2";
}
#GET
#Path("/users")
#Produces(MediaType.APPLICATION_JSON)
public Response getUsers(){
List<UserEntity> users = db.getUsers();
return Response.ok(users,MediaType.APPLICATION_JSON).build();
}
}
the db variable whenever I call http://localhost/book/users is always null.
The dbController is:
public class dbController {
#Inject
private HibernateUtil util;
public List<UserEntity> getUsers(){
List<UserEntity> result = null;
try{
result = (List<UserEntity>) this.util.createQuery("select e from UserEntity e");
}catch (Exception e){
System.out.println(e.getMessage());
}
return result;
}
}
and the HibernateUtil is:
public class HibernateUtil {
private static final EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("NewPersistenceUnit");
private EntityManager entityManager = null;
private void createEntityManager(){
if (this.entityManager==null){
this.entityManager = entityManagerFactory.createEntityManager(); // here is your persistence unit name
}
}
private void closeConnection(){
this.entityManager.close();
this.entityManager = null;
}
public List createQuery(String query) throws Exception{
this.createEntityManager();
List result;
try{
result = this.entityManager.createQuery(query).getResultList();
}catch (Exception e){
throw new Exception(e.getMessage());
}
return result;
}
}
I'm using intellij and I added a break point at the db.getUsers() and set the variable db by adding new dbController(). However, the Intellij gives me the error "Class not loaded : controller.dbController".
The hibernate works for sure...so the problem is not there. It's the first time I'm trying to use Dependency Injection, but I'm not sure what I'm doing wrong.
Thanks
You cannot inject POJO it has to be a Bean. So making it a bean requires the annotations, for example:
#Stateful
#LocalBean
public class dbController {..} // Should be DbController, start with CAPS
and
#Stateful // or maybe #Stateless ?
#LocalBean
public class HibernateUtil {..}
Then when you have a Bean it is not allowed to use static final so change like this is needed:
private EntityManagerFactory entityManagerFactory =
Persistence.createEntityManagerFactory("NewPersistenceUnit");
But actually the easiest way to get EntityManager is just to inject it also. Like:
#PersistenceContext// maybe also with unit name (unitName = "whatever_the_unit_name_is")
private EntityManager em;

How to persist/commit entity to database immediately in Activiti Service Task

I have a need to persist(insert) a entity to database immediately when the save (or saveAndFlush) code is called.
However although the entity is created in the context it is not persisted in the database immediately.
We are using Spring Boot.
public interface MessageRepository extends JpaRepository<MessageEntity, Long> {
}
In the Service class
#Service
public class TestService {
#Autowired
private MessageRepository messageRepository;
#Transactional
public MessageEntity saveMessage(MessageEntity entity) throws Exception {
entity = messageRepository.saveAndFlush(entity);
return entity;
}
}
Though the entity is created it is not persisted/committed to the database immediately.
We are facing this issue within the Activiti Tasks only.
Any feedback will be appreciated.
This worked.
#Component
public class MessageRepositoryCustomImpl implements MessageRepositoryCustom {
#PersistenceContext
EntityManager entityManager;
#Override
#Transactional(propagation = Propagation.REQUIRES_NEW)
public MessageEntity saveImmediate(MessageEntity entity) {
entityManager.persist(entity);
return entity;
}
}
One way of overcoming this situation is by taking advantage of the REQUIRES_NEW transaction attribute.
In your situation you would have to create a new repository:
public interface MessageRepositoryCustom{
void saveAndFLush(MessageEntity ent);
}
public MessageRepositoryCustomImpl implements MessageRepositoryCustom{
#Autowired
private SessionFactory sessionFactory;
#Transactional(propagation = Propagation.REQUIRES_NEW)
void saveAndFLush(MessageEntity ent){
Session session = sessionFactory.getCurrentSession();
session.persist(ent);
}
}
Then in your service you would use that repository:
#Transactional
public MessageEntity saveMessage(MessageEntity entity) throws Exception {
entity = messageRepositoryCutom.saveAndFlush(entity);
// other processing
return entity;
}
}
Now after the messageRepositoryCutom.saveAndFlush method has finished processing the entity will be physically persisted in the database as it was created in a separate transaction which has been commited.

Mocking Entitymanager while testing of EJB class

I am using: Netbeans, Glassfish, Mockito
While working with Java EE for the first time I have come across the issue of trying to test methods that interact with the database using an entitymanager.
In the below code snippets I have tried to mock out the entity manager so i know that the db interaction will not be tested exactly and for this testing thats ok. But I am striggling on instansiating the UsersController because it has an injected EntityManager which is always null. I would like the EntityManager to be mocked out so I can test the rest of the method.
Below is a class that interacts with the db. NOTE this is an example methods, it is not for use in production.
#Stateless
public class UsersController {
#PersistenceContext()
EntityManager em;
public User getOne() {
em.getEntityManagerFactory().getCache().evictAll();
User theUser = null;
try {
Query q = em.createNamedQuery("User.findAll");
Collection<User> entities = q.getResultList();
theUser = Iterables.get(entities, 1);
}
catch(NoResultException e){}
em.flush();
return theUser;
};
}
The test file that will test this method.
#RunWith(MockitoJUnitRunner.class)
public class UsersControllerTest {
#Mock
private UsersController usersController;
#Mock
private EntityManager entityManagerMock;
private Collection<User> mockUsersDbCollection = //...
#BeforeClass
public void setUpClass() {
when(entityManagerMock.createNamedQuery("User.findAll")).thenReturn(mockUsersDbCollection);
}
#Test
public void findOneTest(){
User mockUserDbEntry = new User("1", "pa$$word", "salt", "user1", "user1#email.com", false);
User returnedUser = null;
returnedUser = usersController.getOne();
assertEquals(returnedUser.getId(), "1");
}
}
Whenever the UsersController mock is created the entityManager is always null causing issues, how can I inject the EntityManagerMock so it will work?
You have a few issues here:
you are testing your UsersController, therefore it should not be mocked; rather you should use the #InjectMocks annotation on it because you want Mockito to inject your mock entity manager
the #BeforeClass annotation only works when applied to a static method, which in turn can only access static instance variables; in this instance I think you just need the #Before annotation
your entityManagerMock.createNamedQuery needs to return a mock Query object, the code you pasted should not even compile
In the end, your test should look something like:
#RunWith(MockitoJUnitRunner.class)
public class UsersControllerTest {
#InjectMocks
private UsersController usersController;
#Mock
private EntityManager entityManagerMock;
#Mock
private EntityManagerFactory entityManagerFactory;
#Mock
private Cache emfCache;
#Mock
private Query findAllQuery;
private List<User> mockUsersDbCollection = //...
#Before
public void setUp() {
when(entityManagerFactory.getCache())
.thenReturn(emfCache);
when(entityManagerMock.getEntityManagerFactory())
.thenReturn(entityManagerFactory);
when(entityManagerMock.createNamedQuery("User.findAll"))
.thenReturn(findAllQuery);
when(findAllQuery.getResultList())
.thenReturn(mockUsersDbCollection);
}
#Test
public void findOneTest(){
mockUsersDbCollection.add(new User("1", "pa$$word", "salt", "user1", "user1#email.com", false));
User returnedUser = usersController.getOne();
assertEquals(returnedUser.getId(), "1");
}
}

Spring Boot and multiple databases

I've setup a basic spring project with a single database connection.
In the application.properties file I have the database settings:
spring.datasource.url = jdbc:mysql://192.168.1.19/ticket
spring.datasource.username = dbusername
spring.datasource.password = dbpassword
I've created a base DAO class which other DAOs extend:
#Transactional
public class Dao<E> {
#PersistenceContext
private EntityManager entityManager;
private Class<E> entityClass;
public Dao(Class<E> entityClass) {
this.entityClass = entityClass;
}
public void create(E object) {
entityManager.persist(object);
return;
}
public void delete(E object) {
if (entityManager.contains(object)) {
entityManager.remove(object);
} else {
entityManager.remove(entityManager.merge(object));
}
return;
}
#SuppressWarnings("unchecked")
public List<E> getAll() {
return entityManager.createQuery("from " + entityClass.getName()).getResultList();
}
public E get(long id) {
return entityManager.find(entityClass, id);
}
public void update(E object) {
entityManager.merge(object);
return;
}
}
Here's a sample entity that extends the base DAO:
#Repository
public class PersonDao extends Dao<Person> {
public PersonDao() {
super(Person.class);
}
}
Currently this uses a single database, but I need to be able to add a second database, and somehow define in each DAO which datasource to use. Each DAO will only use a single database, so there's no requirement for a DAO to be able to connect to multiple databases.
I've done some research, and that seems to suggest I need to use JdbcTemplate? but I can't seem to find a tutorial that matches my need. Also, at the minute the entityManager is injected into the DAO, but the JdbcTemplate examples I've looked at don't seem to use the entityManager, which is slightly confusing.
database.password1=<password1>
database.url1=jdbc\:mysql\://localhost\:3306/twodbone
database.username1=<username1>
database.password2=<password1>
database.url2=jdbc\:mysql\://localhost\:3306/twodbtwo
database.username2=<username2>
database.driverClassName=com.mysql.jdbc.Driver
In this way you can add the multiple databases and configure both hibernate.cfg.xml file and applicationContext.xml file also..
#Repository
public class FooRepository
{
#PersistenceContext
private EntityManager entityManager;
#Autowired(required = true)
private JdbcTemplate jdbcTemplate;
public void saveFoo(Foo foo)
{
this.entityManager.persist(foo);
}
public List<SomeReportPojo> getSomeReport()
{
return this.entityManager.queryForList("SELECT .. ",SomeProjectPojo.class);
}
}
this.jdbcTemplate should be kept rather than this.entityManager for jdbc templetes
this is simple example

Categories

Resources