Mock spring's LocalContainerEntityManagerFactoryBean method using Mockito? - java

I am trying to write unit testcases for the below code and am trying to mock the EntityManager implementation. I am unable to do so and I get null entity manager bean in my test class.
public List<Object[]> getForecastResults(String query, String siteId, long startTime, long endTimestamp)
{
List<Object[]> result = null;
EntityManager em = null;
try {
query = String.format(query, startTime, endTimestamp, siteId);
logger.debug(" Query : " + query);
em = localContainerEntityManagerFactoryBean.nativeEntityManagerFactory.createEntityManager();
EntityTransaction et = em.getTransaction();
et.begin();
result = (List<Object[]>) em.createNativeQuery(query).getResultList();
//logger.debug("Results from the query : " + query + " are :" + Utility.toJsonString(result, true));
} catch (Exception ex) {
ex.printStackTrace();
logger.error("Error Occurred while fetching the data for the query : " + query);
}
return result;
}
The test code I have written to mock it is below:
#InjectMocks
private LocalContainerEntityManagerFactoryBean emMock = new LocalContainerEntityManagerFactoryBean();
...
Mockito.when(localContainerEntityManagerFactoryBean.nativeEntityManagerFactory.createEntityManager()).thenReturn();
I should return a list when this is called as output So i need the whole method to be mocked. Please help !

First off all instead of #InjectMocks you should be using #Mock and put the #InjectMocks on the class you are trying to unit test.
However the fact that you are even considering mocking the LocalContainterEntityManagerFactoryBean is a sign that your code is flawed. You shouldn't be using the LCEMFB in code. It is only for configuration. It is a FactoryBean that creates an EntityManagerFactory so actually you should be injecting an EntityManagerFactory into your code which you should be mocking.
Instead of wiring the LCEMFB use the plain EMF and get an instance by annotating the field with #PersistenceUnit.
#PersistenceUnit
private EntityManagerFactory emf;
Then your method is also a bit cleaner
public List<Object[]> getForecastResults(String query, String siteId, long startTime, long endTimestamp)
{
List<Object[]> result = null;
EntityManager em = null;
try {
query = String.format(query, startTime, endTimestamp, siteId);
logger.debug(" Query : " + query);
em = emf.createEntityManager();
EntityTransaction et = em.getTransaction();
et.begin();
result = (List<Object[]>) em.createNativeQuery(query).getResultList();
//logger.debug("Results from the query : " + query + " are :" + Utility.toJsonString(result, true));
} catch (Exception ex) {
ex.printStackTrace();
logger.error("Error Occurred while fetching the data for the query : " + query);
}
return result;
}
However what you actually should be doing is injecting an EntityManager and don't try to create one yourself (your code is still flawed as you aren't closing the transaction nor the created EntityManager which in turn will eventually lead you to being unable to connect to your database as the underlying Connection remains open as well.
So instead of injecting either the LCEMFB or a EMF use a plain EntityManager instead and let spring manage it for you. To have spring manage the transaction make sure there is an #EnableTransactionManagement or <tx:annotation-driven /> in your configuration else it won't work.
#PersistenceContext
private EntityManager em;
Now your method is really focussed on what it should do, get data from the database.
#Transactional(readOnly=true)
public List<Object[]> getForecastResults(String query, String siteId, long startTime, long endTimestamp) {
query = String.format(query, startTime, endTimestamp, siteId);
return em.createNativeQuery(query).getResultList();
}
Now in your test you should only need to mock the EntityManager.
All of this is also explained in the ORM chapter of the Spring Reference guide.
Another thing that worries me is that you are using a String and parsing that to be used as a query. This is potentially dangerous and a cause for SQL injection attacks. Instead of doing the formatting yourself you should let it be handled by Hibernate or JDBC.
#Transactional(readOnly=true)
public List<Object[]> getForecastResults(String query, String siteId, long startTime, long endTimestamp) {
query = String.format(query, startTime, endTimestamp, siteId);
Query q = em.createNativeQuery(query);
q.setParameter("siteId", siteId)
.setParameter("startTime", startTime)
.setParameter("endTime", endTimestamp);
return q.getResultList();
}
The code above assumes a query in the form of SELECT * FROM YOURTABLE WHERE siteId=:siteId and startTime >= :startTime and endTime <= :endTime (or whatever your SQL looks like).

Related

call procedure with out parameters in hibernate3

I work with hibernate3 and didn't use JPA
I have a procedure in oracle which return 2 out parameter
For test I execute this procedure in oracle with this query.
declare
req_type number;
req_seq number;
begin
insert_req(1111,req_type,req_seq);
dbms_output.put_line('req_type='||req_type);
dbms_output.put_line('req_seq='||req_seq);
end;
Now I want to call this procedure using hibernate
I try with native query without success using this code :
public void insertReq(String numEmp) {
int req_type ;
int req_seq;
String sql = " insert_req(1111,:in1,:in2) ";
SQLQuery query = session.createSQLQuery(sql);
query.setParameter("in1", req_type);
query.setParameter("in2", req_seq);
List results = query.list();
System.out.println(req_type);
System.out.println(req_seq);
}
when I have a function I can run it using hibernate using this code as an example :
public void insertOrder(String numEmp) {
String query = "call insert_order(" + numEmp + ",50)";
SQLQuery sqlQuery = this.getSession().createSQLQuery(query);
sqlQuery.executeUpdate();
}
but the problem is how to call procedure with 2 out parameter using hibernate.
you have to use CallableStatement and registerOutParameter.
you can get a connection from your hibernate session and create the callablestatement.
hibernate does not provide a mecanism to deal with this (at least as i know).
i hope that helps.
Try this and let me know.
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
Session session = em.unwrap(Session.class);
session.doWork(new Work() {
#Override
public void execute(Connection con) throws SQLException {
// do something useful
try (CallableStatement stmt = con.prepareCall("{call my_sp()}")) {
stmt.execute();
}
}
});
em.close();
Best regards.

How to delete an entity by two attributes in Hibernate?

i've come across a problem in these days, which would be simple for other languages, like php, but the project I'm doing is in Spring MVC.
The question is: In Spring MVC, how can i delete an entity with two attributes ids coming from this entity?
Example: "Delete from Entity Where id1 =: id1 and id2 =: id2" (This is the query that i want)
Thanks for the attention.
What i was trying ...
public boolean remover(int idUsuario, int idCategoria) {
EntityManagerFactory factory = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT);
EntityManager manager = factory.createEntityManager();
String hqlStr = "delete from UsuarioEscolheCategoria where idUsuario = :idUsuario and idCategoria = :idCategoria";
Query query = null;
try {
query = manager.createQuery(hqlStr);
query.setParameter("idUsuario", idUsuario);
query.setParameter("idCategoria", idCategoria);
query.executeUpdate();
manager.close();
factory.close();
return true;
}catch(Exception e) {
return false;
}
}
If i take the exception, it gives me:
String hqlStr = "delete from UsuarioEscolheCategoria where usuario.idUsuario = :idUsuario and categoria.idCategoria = :idCategoria";
The important part is usuario.idUsuario and categoria.idCategoria. That way you're making a reference to the attribute type Usuario, which is on your model class.
you prblem is the session factory, check how you have created it, here a simple usefull example:
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
#Autowired
private SessionFactory sessionFactory;
protected Session getSession() {
return sessionFactory.getCurrentSession();
}
public void deleteById(Integer id) {
Query query = getSession().createSQLQuery("delete from TABLE where id = :t_id");
query.setInteger("t_id", id);
query.executeUpdate();
}

modifying existing code to adapt nolock in jpa

What I want to achieve is, I would like to do a no lock query execution in select statement. But according to this answer it is impossible to achieve this with direct JPA implementation. I also understood from searches that nolock and READ_UNCOMMITTED are same. Is there any way to achieve this(no lock, READ_UNCOMMITTED) by modifying my below code. Or should I use the native query with specifying WITH(NOLOCK)
I had tried
entityManager.createQuery(query).setLockMode(LockModeType.NONE).getResultList();
but it also not solving my issue.
My references this, this , this, this
I am using the following code to get data from table. this code works fine without nolock.
String query = "FROM Employee WHERE empId=:empId AND empStatus='failed'";
to fetch data from db
public Object getListFromQuery(String query) throws Exception {
Object resultObject = null;
List<Object> queryResultList = null;
EntityManager entityManager = null;
try {
entityManager = entityManagerFactory.createEntityManager();
queryResultList = entityManager.createQuery(query).getResultList();
resultObject = (Object) queryResultList;
} catch (Exception ex) {
LOGGER.error("Exception : DatabaseManager :executeQueryGetList ",ex);
throw ex;
} finally {
entityManager.close();
}
return resultObject;
}
Database configuration
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory()
throws NamingException {
LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
factoryBean.setDataSource(dataSource());
factoryBean
.setPackagesToScan(new String[] { "com.test.middleware.entity" });
factoryBean.setJpaVendorAdapter(jpaVendorAdapter());
factoryBean.setJpaProperties(jpaProperties());
factoryBean.setPersistenceUnitName("test_unit");
return factoryBean;
}

Hibernate Neo4j retrieve result in a key-value form

I would like to retrieve entity properties in a format like this: property_name: value.
I am trying to get the result this way:
public void retrievePerson(){
EntityManagerFactory emf = Persistence.createEntityManagerFactory("persistence");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
try{
String query = "MATCH (p:Person {id:3}) RETURN p.firstname, p.lastname";
List<Object[]> person = (List<Object[]>) em.createNativeQuery(query).getResultList();
em.flush();
tx.commit();
em.clear();
em.close();
emf.close();
}
catch (HibernateException e) {
if (tx!=null) tx.rollback();
e.printStackTrace();
}
}
I read somewhere the the object returned by the query is a managed entity.
I would like the result to be like this: {"firstname":"Jon", "lastname":"Smith"}
I have found this setResultTransformer(AliasToEntityMapResultTransformer.INSTANCE which might be something that I am looking for but I am unable to get it to work.
Is there a way to achieve this?
Try changing your query to:
MATCH (p:Person {id:3})
RETURN { firstname: p.firstname, lastname: p.lastname }
If you are looking for the returned value to be an entity, this will work:
String query = "MATCH (p:Person {id:3}) RETURN p";
List<Person> person = (List<Person>) em.createNativeQuery(query, Person.class).getResultList();
Actually, in this case this would make more sense:
Person poem = (Person) em.createNativeQuer(query, Person.class).getSingleResult();

How to convert hql to sql and apply filters on it?

I call this method to convert hql query to sql:
public String toSql(String hqlQueryText) {
if (hqlQueryText != null && hqlQueryText.trim().length() > 0) {
QueryTranslatorFactory translatorFactory = new ASTQueryTranslatorFactory();
SessionFactoryImplementor factory = (SessionFactoryImplementor) sessionFactory;
QueryTranslator translator = translatorFactory.createQueryTranslator(hqlQueryText, hqlQueryText, Collections.EMPTY_MAP, factory, null);
translator.compile(Collections.EMPTY_MAP, false);
return translator.getSQLString();
}
return null;
}
and I have this filter in .hbm.xml file of domain class:
<filter name="userAuthorize" condition="some sql query here" />
but I don't know how I should tell hibernate to apply this filter when converting from hql to sql.
Assume that I call above method like this:
public Session getSession() {
try {
return sessionFactory.getCurrentSession();
}
catch (Exception e) {
}
return sessionFactory.openSession();
}
public List<DomainClass> getAll() {
String hql = " some hql query ";
Session session = getSession();
String sql = toSql(hql);
return session.createSQLQuery(sql).list();
}
Not a great Idea. But maybe It helps.
HQL and SQL have some differences, for instance with join , 'on' is used in SQL and 'with' is used in HQL.
So maybe you can use list of words that are unique to HQL and check for them in your String using
hql.contains("with") or hql.indexOf("with").
It is not the responsibility of the QueryTranslator to apply filters. Also, filters don't get applied to native SQL.
It looks like you just want to execute the HQL query? There is no need to have it translated to SQL first:
public List<DomainClass> getAll() {
String hql = " some hql query ";
return session.createQuery(hql).list();
}

Categories