3

I am trying to learn creating ReST API end points using spring mvc and Hibernate without using springboot. When I am running my end point , I am getting internal server error saying that ,

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

My spring-servlet.xml file under src/main/webapp/web-1nf is like the following,

<beans:beans xmlns="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context" 
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/mvc 
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context 
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx 
http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">

<annotation-driven />

<resources mapping="/resources/**" location="/resources/" />

<beans:bean id="dataSource"
    class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <beans:property name="driverClassName" value="org.postgresql.Driver" />
    <beans:property name="url" value="jdbc:postgresql://localhost:5432/company" />
    <beans:property name="username" value="postgres" />
    <beans:property name="password" value="postgresql" />
    <!--<property name="socketTimeout" value="10"/>-->

    <beans:property name="connectionProperties">
        <beans:props>
            <beans:prop key="socketTimeout">10</beans:prop>
        </beans:props>
    </beans:property>
 </beans:bean>


<beans:bean id="hibernate4AnnotatedSessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
 <beans:property name="dataSource" ref="dataSource" />
 <beans:property name="annotatedClasses">
 <beans:list>
 <beans:value>com.springmvc.Employee</beans:value>
</beans:list>
</beans:property>

<beans:property name="hibernateProperties">
 <beans:props>
   <beans:prop 
     key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect
   </beans:prop>
  <beans:prop key="hibernate.show_sql">true</beans:prop>
 </beans:props>
</beans:property>
</beans:bean>

<context:component-scan base-package="com.springmvc" />


<tx:annotation-driven transaction-manager="transactionMgr"/>

 <beans:bean id="transactionMgr" 
  class="org.springframework.orm.jpa.JpaTransactionManager">
   <beans:property name="entityManagerFactory" ref="mgrFactory"/>
 </beans:bean>

   <beans:bean id="mgrFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
   <beans:property name="dataSource" ref="dataSource"/>
   <beans:property name="packagesToScan" value="com.springmvc"/>
    <beans:property name="jpaVendorAdapter">
      <beans:bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
   </beans:property>
   <beans:property name="jpaProperties">
      <beans:props>
        <beans:prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</beans:prop>
        <beans:prop key="hibernate.dialect">${hibernate.dialect}</beans:prop>
        <beans:prop key="hibernate.cache.use_second_level_cache">${hibernate.cache.use_second_level_cache}</beans:prop>
        <beans:prop key="hibernate.cache.use_query_cache">${hibernate.cache.use_query_cache}</beans:prop>
        <beans:prop key="hibernate.show_sql">${hibernate.show_sql}</beans:prop>
        <beans:prop key="hibernate.format_sql">${hibernate.format_sql}</beans:prop>
    </beans:props>
   </beans:property>
 </beans:bean>

</beans:beans>

My controller is ,

@RestController
@RequestMapping("/mvchibernate")
public class CompanyController {

@Autowired
EmployeeService employeeService;

 @GetMapping(value = "/getAllEmployees")
    public List<Employee> getEmployeesList() {
     
     @SuppressWarnings("unchecked")
    List<Employee> listOfEmployees = employeeService.getAllEmployees();
        return listOfEmployees;
    }
}

And my service class like the following,

@Service
public class EmployeeService {

@Autowired
EmployeeDAO employeeDaoObj;

public List getAllEmployees() { 
    return employeeDaoObj.getAllEmployees();
  }
}

And DAO implementation ,

@Repository
public class EmployeeDAO {

@PersistenceContext private EntityManager entityManager;

public List<Employee> getAllEmployees() {
    
    String jpql = "SELECT e FROM Employee e";
    TypedQuery<Employee> query = entityManager.createQuery(jpql, Employee.class);
    
       return query.getResultList();
    
        }
}

Here in my DAO class I autowired the entitymanager.And while running I am getting Cannot invoke javax.persistence.EntityManager and last showing that because "this.entityManager" is null.

So can anyone guide me to resolve this issue or kindly refer any documentation to follow please?

Mr.DevEng
  • 2,651
  • 14
  • 57
  • 115

3 Answers3

2

Edit from my previous answer, After reviewing your code below is what you are currently doing:

  1. You created PersistenceConfig.java with Configuration annotation. This class is empty & it looks you have commented it after creating & defining beans.

  2. Spring is actually checking PersistenceConfig.java for finding configurations instead of going to your xml.

  3. Move your xml config to src/main/resources & for supporting best practice rename it to persistence.xml.

  4. Now, you have to tell spring to read your configs from persistence.xml instead of looking anywhere else. Comment out Configuration annotation from PersistenceConfig.java & use below annotation in your main class :

:

@SpringBootApplication
@ImportResource({ "classpath:persistence.xml" })
public class SpringMvcHibernateRestApiApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringMvcHibernateRestApiApplication.class, args);
    }
}
  1. Also, I suggest to use org.springframework.orm.hibernate5.LocalSessionFactoryBean instead of org.springframework.orm.hibernate4.LocalSessionFactoryBean as it will be inline with your latest spring & jpa versions. Once you used this, you will be able to see entitymanager got created properly.

Edit : As per OP's comment, point number 5 is not required on their machine.

Ashish Patil
  • 4,428
  • 1
  • 15
  • 36
  • Thank you for your response. It listing rest of all. But entitymanager bean is not getting listing in console. – Mr.DevEng Jul 25 '22 at 13:44
  • @Mr.DevEng, can you share what versions of spring, jpa you are using in project? – Ashish Patil Jul 25 '22 at 13:52
  • spring 5.3 and data jpa 2.7 – Mr.DevEng Jul 25 '22 at 14:43
  • ok, your `component` scan has `com.springmvc` & your `packagesToScan` in `MgrFactory` is `com.restDemo` . can you please confirm if package struct is correct? I was thinking if your `packagesToScan` would be `com.springmvc.restDemo` ? – Ashish Patil Jul 25 '22 at 14:46
  • No its com.springmvc only. That mistake already corrected in xml early and I forgot to update here. – Mr.DevEng Jul 25 '22 at 14:51
  • ok, is it possible for you to mock your project & upload it somewhere like in git? as this error seems too specific to me. If its not possible, that is fine, no problem on that. – Ashish Patil Jul 25 '22 at 14:54
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/246743/discussion-between-mr-deveng-and-ashish-patil). – Mr.DevEng Jul 25 '22 at 15:03
  • hi, I waited for some time in chat room, but need to go now, please can you share any further observations offline if you can so that I can check on that. thanks – Ashish Patil Jul 25 '22 at 15:12
  • i shared as a study project zip file. Please look on when you gets time. link - https://github.com/princevarghesev/springhibernatestudy – Mr.DevEng Jul 25 '22 at 15:15
  • @Mr.DevEng , I have just updated my answer, this is working fine on my local machine. Please verify now – Ashish Patil Jul 25 '22 at 16:12
  • @Mr.DevEng, I just updated comment about point 5 as per your confirmation. Strangely I never got duplicate beans error about mgrFactory otherwise would have suggested that as well. – Ashish Patil Jul 26 '22 at 07:47
0

You are referencing the transactionManager bean here:

<tx:annotation-driven transaction-manager="transactionManager"/>

But the bean is actually named transactionMgr:

 <beans:bean id="transactionMgr" 
  class="org.springframework.orm.jpa.JpaTransactionManager">
   <beans:property name="entityManagerFactory" ref="MgrFactory"/>
 </beans:bean>

You should reference the correct name:

<tx:annotation-driven transaction-manager="transactionMgr"/>
Olivier
  • 13,283
  • 1
  • 8
  • 24
  • Thank you for your response. I modified the naming mismatch and updated in my question. But still getting the same error. – Mr.DevEng Jul 25 '22 at 12:09
0

I do believe there are two options:

  1. define PersistenceAnnotationBeanPostProcessor bean - it is responsible for injecting @PersistenceContext fields (though documentation says it should be registered automatically, m.b. it is worth to debug it to understand the reason):
 <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>
  1. define EntityManager factory bean and use @Autowired instead of @PersistenceContext:
<bean id="emf" class="org.springframework.orm.jpa.support.SharedEntityManagerBean">
  <property name="entityManagerFactory" ref="mgrFactory"/>
</bean>
Andrey B. Panfilov
  • 4,324
  • 2
  • 12
  • 18