I am trying to develop a simple Spring web application using Jersey (JAX-RS), deployed in a Tomcat container. The entities are managed using JPA with EclipseLink provider and stored in a MySQL database. I don't use EJB.
I'm trying to inject the EntityManager via Spring, however when I want to get (or persist) an entity from the DB, I get a NullPointerException showing that EntityManager is null.
I have spent lots of hours trying to find the solution and tried every code I've found in tutorials and threads, but got the same result.
I have included all the required dependecies in the project. If I manually create an EntityManagerFactory and then an EntityManager in getPerson, it works, but I don't think that should be the proper way.
Also, when I start the service, I can see in the console output logs that Spring root WebApplicationContext is initialized, bean definitions are loaded and JPA container EntityManagerFactory for persistence unit 'defaultPU' is built.
I am clearly missing something, could you please help me how can I make this work?
Why is EntityManager null and how should I inject it in order to be able to use it in the PersonController?
Person.java:
package TestSpringApp;
import javax.persistence.Entity;
import javax.persistence.Id;
#Entity
public class Person {
#Id
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
PersonController.java:
package TestSpringApp;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
#Component
#Path("/person")
public class PersonController {
#PersistenceContext
EntityManager entityManager;
#GET
#Transactional
public String getPerson() {
Person p = entityManager.find(Person.class, 0);
return p.getName();
}
public void setEntityManager(EntityManager em) {
this.entityManager = em;
}
public EntityManager getEntityManager() {
return this.entityManager;
}
}
beans.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation=
"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
<context:component-scan base-package="TestSpringApp"/>
<tx:annotation-driven />
<context:annotation-config/>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="jpaVendorAdapter" ref="jpaAdapter" />
<property name="persistenceUnitName" value="defaultPU"/>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean id="jpaAdapter" class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter">
<property name="database" value="MYSQL" />
<property name="showSql" value="true" />
</bean>
</beans>
persistence.xml:
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
version="1.0">
<persistence-unit name="defaultPU" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<class>TestSpringApp.Person</class>
<properties>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/test"/>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="javax.persistence.jdbc.user" value="root"/>
<property name="javax.persistence.jdbc.password" value="root"/>
<property name="eclipselink.ddl-generation" value="create-tables" />
<property name="eclipselink.ddl-generation.output-mode" value="database" />
<property name="eclipselink.weaving" value="false"/>
</properties>
</persistence-unit>
</persistence>
web.xml:
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
id="WebApp_ID" version="3.0">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:beans.xml</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<display-name>testspring</display-name>
<servlet>
<servlet-name>/</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>TestSpringApp</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>/</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
</web-app>
EDIT:
Until now, I have thought that context:component-scan or context:annotation-config in beans.xml was taking care of making Spring aware of PersonController, however now I checked it and I found out that setEntityManager is only called if I place #PersistenceContext on setEntityManager instead of on EntityManager itself and annotate the PersonController class with #Component. This way I can see that setEntityManager is called on Spring bean initialization, and its value is "Shared EntityManager proxy for target factory [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean#15bd577]".
My problem still occurs, because when I do a http://localhost:8080/rest/person request, entityManager is still null in line entityManager.find(Person.class, 0).
After reading through Jersey docs, I have found this chapter on Spring DI support in Jersey.
Adding jersey-spring3 and spring-bridge dependecies to the project solved the problem.
Related
I am trying to read a property file in Spring mvc 4.1.6 version and I am having some issues.
Dispatcher-servlet.xml
<context:property-placeholder location="classpath:login.properties"/>
My class
#Component
public class UserCheck {
#Value("${server_ip}") String server_ip;
public String isUserPresent(String userName){
System.out.println("server_ip: " + server_ip);
return "";
}
}
I am getting the server_ip as null when I print the value. My login.properties is in src/main/resources folder.
I also tried #Value("${login.server_ip}"), but then I got a different error when deploying the application. I got
org.springframework.beans.factory.BeanCreationException: Error creating bean with name : Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field
Is there anything else that I need to do?
Thanks.
EDIT:
My properties file looks like below:
server_ip=192.168.1.1
My complete dispatcher servlet:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:component-scan base-package="com.company"></context:component-scan>
**<context:annotation-config/>**
<mvc:annotation-driven />
<mvc:resources mapping="/**" location="/" />
<context:property-placeholder location="classpath:login.properties"/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name = "prefix" value="/WEB-INF/jsp/" />
<property name = "suffix" value=".jsp" />
</bean>
<bean class="org.springframework.context.support.ResourceBundleMessageSource"
id="messageSource">
<property name="basename" value="messages" />
</bean>
This was added for testing**********************
<bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
<property name="ignoreUnresolvablePlaceholders" value="true"/>
<property name="locations">
<list>
<value>classpath:application.properties</value>
</list>
</property>
</bean>
</beans>
EDIT 2:
My web.xml
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>test</display-name>
<servlet>
<servlet-name>spring-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring-dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
EDIT 3: My controller class with the #PostConstruct method
#Controller
#SessionAttributes("userData")
public class UserController {
#Autowired
#Value("${server_ip}")
String server_ip;
#Value("${username}")
String username;
public #ResponseBody
#RequestMapping(value = "/validateuser")
String validateUser(#RequestParam("user") String user){
//UserCheck userCheck = new UserCheck();
//String test = userCheck.isUserPresent(user);
return "";
}//validateUser
#PostConstruct
public void init(){
System.out.println("server_ip in inti: " + server_ip);
System.out.println("username: " + username);
}
}
First of all, you would need the #Configuration annotation on the class. Not sure it would work with just #Component
Secondly, I don't know your project type and setup but if your .properties file ends up in WEB-INF/classes directory, then Spring should be able to pick it up.
EDIT:
You need to add this to your configuration file <context:annotation-config/>
I am trying to Integrate Spring with Hibernate. However, I am not able to get Hibernate's SessionFactory Object through Spring's LocalSessionFactoryBean.
I tried the following approaches:
1) Use either of org.springframework.orm.hibernate3 and org.springframework.orm.hibernate4 LocalSessionFactoryBean class
2) Use AbstractSessionFactoryBean class
3) Try with SessionFactory=LocalSessionFactoryBean.getObject() as well as SessionFactory=LocalSessionFactoryBean
Here's the Project Structure:
Not allowed to post images till I reach 10 credits, sad..
Here 's the BookService
package com.zzz.service;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.hibernate3.AbstractSessionFactoryBean;
import org.springframework.orm.hibernate4.LocalSessionFactoryBean;
import com.zzz.forms.BookForm;
public class BookService {
#Autowired
LocalSessionFactoryBean hibernateSessionFactory;
SessionFactory sessionFactory;
public LocalSessionFactoryBean getHibernateSessionFactory() {
return hibernateSessionFactory;
}
public void setHibernateSessionFactory(LocalSessionFactoryBean hibernateSessionFactory) {
this.hibernateSessionFactory = hibernateSessionFactory;
}
public SessionFactory getSessionFactory() {
return sessionFactory;
}
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public void storeBookDetails(BookForm bookForm){
System.out.println("Hibernae");
setSessionFactory((SessionFactory)hibernateSessionFactory.getObject());
Session session=sessionFactory.openSession();
session.beginTransaction();
session.save(bookForm);
session.getTransaction().commit();
session.close();
System.out.println("Hibernae");
}
}
Here's The Controller that leads to this service
package com.zzz.controllers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import com.zzz.forms.BookForm;
import com.zzz.service.BookService;
#Controller
public class FirstPageController {
BookService bookService;
public BookService getBookService() {
return new BookService();
}
public void setBookService(BookService bookService) {
this.bookService = bookService;
}
#RequestMapping(value="/firstPage")
public ModelAndView showFirstPage()
{
return new ModelAndView("books/Book","BookForm",new BookForm());
}
#RequestMapping(value="/enterBookDetails")
public ModelAndView enterBookDetails(#ModelAttribute("BookForm") BookForm bookForm)
{
getBookService().storeBookDetails(bookForm);
System.out.println("BOOK DETAILS ARE AS FOLLOWWS");
System.out.println(bookForm.getBookId());
System.out.println(bookForm.getBookName());
return new ModelAndView("books/BookSubmitted","BookForm",bookForm);
}
}
Application Context:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:hz="http://www.hazelcast.com/schema/spring"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.hazelcast.com/schema/spring
http://www.hazelcast.com/schema/spring/hazelcast-spring-3.2.xsd">
<context:annotation-config/>
<context:component-scan base-package="com.zzz.controllers"></context:component-scan>
<mvc:annotation-driven/>
<bean id="myDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost/zz" />
<property name="username" value="root" />
<property name="password" value="root" />
</bean>
<bean id="hibernateSessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean" >
<property name="dataSource" ref="myDataSource" />
<property name="packagesToScan" value="com.zzz.forms"/>
<property name="hibernateProperties">
<value>
hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
</value>
</property>
</bean>
</beans>
And The web XML
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<display-name>ZZZ</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>*.htm</url-pattern>
</servlet-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:ApplicationContext.xml</param-value>
</context-param>
</web-app>
The NullPointer Looks like this
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.NullPointerException
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:894)
org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:789)
javax.servlet.http.HttpServlet.service(HttpServlet.java:641)
javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
root cause
java.lang.NullPointerException
com.zzz.service.BookService.storeBookDetails(BookService.java:38)
com.zzz.controllers.FirstPageController.enterBookDetails(FirstPageController.java:39)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
It seems that LocalSessionFactoryBean is not getting injected, but I cannot figure out the reason.
Any kind of help would be appreciated.
The NPE has nothing to do with your hibernate set-up. In your controller you create a new book service using new BookService() in your getBookService() method. This is incorrect. You need to define a bean for the book service in your spring configuration, inject that bean into your controller (either directly or using an annotation) and use that bean in your controller. You already defined a BookService property, so you are almost there.
I've been spending two days in trying to resolve a weird problem. I'm working in a MVC Spring App and when I run the following test....
#ContextConfiguration(locations = "/persistence-beans.xml")
public class UserDaoTest extends AbstractJUnit4SpringContextTests{
#Autowired
private UserDao userDao;
#Test
public void testAdd() {
int size = userDao.list().size();
User user = new User();
user.setName("omar");
userDao.add(user);
List<User> users = userDao.list();
System.out.println("users size: " + users.size());
// list should have one more employee now
assertTrue (size < users.size());
}
}
I see the result in the data base and all it's ok. But, when I call a controller and use the same Dao (userDao) to create an user, the app does not persist the user and do not throw any error. The only thing that comes to my mind is that there is a problem with the transaction annotation from Spring in the part of the servlet-context.xml. I can believe that in the test case work but not in app flow!
Please, I need to get out from this problem!!!!
------ Interface Dao --------
public interface GenericDao<E, K> {
void add(E entity);
void update(E entity);
void remove(E entity);
E find(K key);
List<E> list();
}
public interface UserDao extends GenericDao<User, Long>{
}
package com.tutorial.dao.impl;
import java.io.Serializable;
import java.util.List;
import com.tutorial.dao.GenericDao;
import java.lang.reflect.ParameterizedType;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
#Transactional(propagation = Propagation.REQUIRED, readOnly = false)
public class GenericDaoJPAImpl<E, K extends Serializable> implements GenericDao<E, K>{
#PersistenceContext
private EntityManager entityManager;
protected Class<E> daoType;
#SuppressWarnings("unchecked")
public GenericDaoJPAImpl() {
daoType = (Class<E>) ((ParameterizedType) getClass().getGenericSuperclass())
.getActualTypeArguments()[0];
}
public void add(E entity) {
em().persist(entity);
}
public EntityManager em() {
return entityManager;
}
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
#Override
public void update(E entity) {
em().merge(entity);
}
#Override
public void remove(E entity) {
em().remove(em().merge(entity));
}
#Override
public E find(K key) {
return (E) em().find(daoType, key);
}
#Override
public List<E> list() {
List<E> list = null;
TypedQuery<E> query = em().createQuery("select o from "
+ daoType.getSimpleName() + " o",
daoType);
list = query.getResultList();
return list;
}
}
#Repository("UserDao")
public class UserDaoImpl extends GenericDaoJPAImpl<User, Long> implements UserDao{
}
-------- Service Layer -----------
#Service("calculatorService")
#Transactional(propagation= Propagation.REQUIRED, readOnly=false)
public class CalculatorServiceImpl implements CalculatorService{
#Autowired
private UserDao userDao;
#Override
public void createUser(User user) {
userDao.add(user);
}
}
---------- Controller --------------
#Controller
#RequestMapping("/calculate")
public class CalculatorController {
#Autowired
private CalculatorService calculatorService;
#RequestMapping(method = RequestMethod.POST)
public String addUser(User user){
calculatorService.createUser(user);
return "session";
}
}
------- Persistence Beans ---------------------------------
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="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-3.1.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd">
<!-- we can use annotations -->
<context:annotation-config />
<!-- we will manage transactions with annotations -->
<tx:annotation-driven />
<context:component-scan base-package="com.tutorial.dao.impl" />
<context:property-placeholder location="classpath*:properties/database.properties"/>
<!-- data source for our database -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${database.driverClassName}"/>
<property name="url" value="${database.url}"/>
<property name="username" value="${database.username}"/>
<property name="password" value="${database.password}"/>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<!-- EntityManagerFactoryBean -->
<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory">
<property name="persistenceUnitName" value="persistenceUnit"/>
<property name="dataSource" ref="dataSource"/>
</bean>
</beans>
---------------------- Servlet Context -----------------------------
<?xml version="1.0" encoding="UTF-8"?>
<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">
<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->
<!-- Enables the Spring MVC #Controller programming model -->
<annotation-driven />
<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
<resources mapping="/resources/**" location="/resources/" />
<!-- Resolves views selected for rendering by #Controllers to .jsp resources in the /WEB-INF/views directory -->
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="prefix" value="/WEB-INF/views/" />
<beans:property name="suffix" value=".jsp" />
</beans:bean>
<!--All beans are scanned here, except the Repository because they are scanned in persistence-beans.xml-->
<context:component-scan base-package="com.tutorial.*" >
<context:exclude-filter expression="org.springframework.stereotype.Repository" type="annotation"/>
</context:component-scan>
</beans:beans>
----------------------- WEB XML --------------------------------
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring/root-context.xml
classpath:persistence-beans.xml
</param-value>
</context-param>
<!-- Creates the Spring Container shared by all Servlets and Filters -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Processes application requests -->
<servlet>
<servlet-name>calculator</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>calculator</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
The link of this project is the next: https://github.com/igiagante/calculator
Feel free to download to prove what's going on :) Thanks you!!!
It seems that you missed for your CalculatorServiceImpl. While your dispatcher-servlet.xml does.
Have a try that adding
<context:component-scan base-package="where your service is"/>
in your root application context and remove unnecessary component-scan in your dispatcher-servlet.
When I am running test at that time #Autowired is working but when I run the web app and try to fetch data at that time its throwing null pointer exception.
this is my controller
In this BuyerRepo is always null
import com.retail.exception.InvalidIdException;
import com.retail.model.Buyer;
import com.retail.repository.BuyerRepo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
#Path("/buyer")
#Component
public class BuyerController {
#Autowired
private BuyerRepo buyerRepo;
#GET
#Produces("application/json")
public Buyer searchFields() throws InvalidIdException {
String buyerId = "51";
Buyer buyer;
try {
buyer = buyerRepo.getBuyer(Long.parseLong(buyerId));
} catch (NumberFormatException e) {
buyer = buyerRepo.getBuyer(buyerId);
}
return buyer;
}
}
In repository entity manager is always null
this is buyerRepository
import com.retail.exception.InvalidIdException;
import com.retail.model.Buyer;
import org.springframework.stereotype.Repository;
import javax.persistence.NoResultException;
#Repository
public class BuyerRepo extends AbstractRepository {
public Buyer getBuyer(String buyerName) throws InvalidIdException {
javax.persistence.Query buyerId = entityManager.createNativeQuery("select b.buyer_id from buyer b where b.name = :name").setParameter("name", buyerName);
Integer id;
try {
id = (Integer) buyerId.getSingleResult();
} catch (NoResultException e) {
return null;
}
return getBuyer(id);
}
public Buyer getBuyer(long buyerId) throws InvalidIdException {
Buyer buyer = entityManager.find(Buyer.class, buyerId);
if (buyer == null) throw new InvalidIdException("Invalid Article ID");
return buyer;
}
}
this is applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
<context:annotation-config/>
<context:component-scan base-package="com.retail"/>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.postgresql.Driver"/>
<property name="url" value="jdbc:postgresql://localhost/retail"/>
<property name="username" value="retail_user"/>
<property name="password" value="password"/>
</bean>
<bean id="entityManagerOne" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="packagesToScan" value="com.retail"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true"/>
<property name="databasePlatform" value="org.hibernate.dialect.PostgreSQLDialect"/>
</bean>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerOne"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
this is servlet-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<mvc:annotation-driven />
<context:annotation-config />
<context:component-scan base-package="com.retail" />
</beans>
this is web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_5.xsd">
<servlet>
<servlet-name>retail</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>com.retail.web</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>retail</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:applicationContext.xml
/WEB-INF/servlet-context.xml
</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
<welcome-file-list>
<welcome-file>/WEB-INF/views/index.jsp</welcome-file>
</welcome-file-list>
</web-app>
You have to wire a interface instead of class. so there are two ways:
To let BuyerRepo to implement one interface
Useing #Inject or #Resource instead of #Autowired
I Have encountered this situation,
you need to add some jar file
gradle project:
compile group: 'org.glassfish.jersey.ext', name: 'jersey-spring3', version: '2.22.2'
maven project:
<dependency>
<groupId>org.glassfish.jersey.ext</groupId>
<artifactId>jersey-spring3</artifactId>
<version>2.22.2</version>
</dependency>
another solution is web.xml file:
<servlet>
<servlet-name>jersey-serlvet</servlet-name>
<servlet-class>com.sun.jersey.spi.spring.container.servlet.SpringServlet</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>cn.ice</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>jersey-serlvet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
You can try using the SpringServlet instead of the jersey provided servlet container to achieve Jersey-Spring integration.
<servlet-class>com.sun.jersey.spi.spring.container.servlet.SpringServlet</servlet-class>
The documentation for this class states :
A servlet or filter for deploying root resource classes with Spring integration.
This class extends ServletContainer and initiates the WebApplication with a Spring-based
IoCComponentProviderFactory, SpringComponentProviderFactory, such that instances of resource and provider
classes declared and managed by Spring can be obtained.
Classes of Spring beans declared using XML-based configuration or auto-wire-based confguration will be
automatically registered if such classes are root resource classes or provider classes. It is not necessary to provide
initialization parameters for declaring classes in the web.xml unless a mixture of Spring-managed and Jersey-
managed classes is required.
The servlet supports configuration of child applicationContexts, see CONTEXT_CONFIG_LOCATION.
Looks like your buyerRepo has no public setter. It's also not possible to set it through the constructor. How about write a setter for it and put the #Autowired annotation on the setter instead. Like this:
#Repository
public class BuyerRepo extends AbstractRepository {
private BuyerRepo buyerRepo;
#Autowired
public void setBuyerRepo(BuyerRepo buyerRepo)
{
this.buyerRepo = buyerRepo;
}
//...Other code is omitted.
}
I am trying to add open-session-in-view behavior to an existing pure JPA application. Using Spring in the service-tier is not an option. I would like to wrap the view in Spring's OpenEntityManagerInViewFilter, and not have to modify the EJB layer.
I am not having any luck getting OpenEntityManagerInViewFilter (Spring 3.2.2) to work in JBoss 6.1. The filter is definitely being invoked, but I am still getting a LazyInitializationException in the view.
The filter and the session-bean are using a different instance (and class) of the EntityManager. The filter is getting a org.hibernate.ejb.EntityManagerImpl, while the session-bean is getting a org.jboss.jpa.tx.TransactionScopedEntityManager. I am not sure what Spring configuration is responsible for this.
Here is the relevant code/config:
war/WEB-INF/classes/test.web.servlet.TestServlet
public class TestServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
#EJB
private ServiceLocal service;
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
long parentId = Long.parseLong(req.getParameter("parentId"));
Parent parent = service.retrieveParent(parentId);
// this call throws a LazyInitializationException
// because parent.children.session is NULL
parent.getChildren().iterator().next().getName();
req.setAttribute("parent", parent);
RequestDispatcher requestDispatcher = this.getServletContext().getRequestDispatcher("/WEB-INF/jsp/view.jsp");
requestDispatcher.forward(req, resp);
}
}
ejb/test.ejb.session.ServiceBean
#Stateless
#TransactionAttribute(TransactionAttributeType.REQUIRED)
public class ServiceBean implements ServiceLocal, Service {
#PersistenceContext(name="test")
private EntityManager entityManager;
#Override
public Parent retrieveParent(Long parentId) {
return entityManager.find(Parent.class, parentId);
}
}
war/WEB-INF/web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
id="WebApp_ID" version="3.0">
<display-name>test-war</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring.xml</param-value>
</context-param>
<filter>
<filter-name>osiv-filter</filter-name>
<filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
<init-param>
<param-name>flushMode</param-name>
<param-value>AUTO</param-value>
</init-param>
</filter>
<servlet>
<servlet-name>test-servlet</servlet-name>
<servlet-class>test.web.servlet.TestServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>test-servlet</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<filter-mapping>
<filter-name>osiv-filter</filter-name>
<servlet-name>test-servlet</servlet-name>
</filter-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
</web-app>
war/WEB-INF/spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN"
"http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="persistenceUnitName" value="test" />
<property name="jpaProperties">
<props>
<prop key="hibernate.transaction.manager_lookup_class">
org.hibernate.transaction.JBossTransactionManagerLookup
</prop>
</props>
</property>
</bean>
</beans>
ejb/META-INF/persistence.xml
<persistence
xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version="1.0">
<persistence-unit name="test" transaction-type="JTA">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>java:/MSSQLDS</jta-data-source>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.SQLServerDialect"/>
<property name="hibernate.show_sql" value="false" />
<property name="hibernate.format_sql" value="true" />
<property name="hibernate.use_sql_comments" value="true" />
<property name="jboss.entity.manager.factory.jndi.name" value="java:/testEntityManagerFactory" />
<property name="jboss.entity.manager.jndi.name" value="java:/testEntityManager" />
</properties>
</persistence-unit>
</persistence>
I don't think it's necessary to use a custom EntityManagerFactory to lookup the EntityManagerFactory via JDNI, the element should take care of that.
I have given your setup a little bit more thought and i don't think that the spring OpenEntityManagerInViewFilter will work for you. It binds an entity manager to the current thread so that spring's transaction management code can reuse it. The problem is that spring doesn't handle the transaction management of your service bean as this is handled by the the application server. The application server doesn't detect the entity manager bound to the thread by spring and creates another one; resulting in 2 different instances.
To make it work you should either define your service bean(s) in spring so that spring handles the transaction management or use jboss seam (JBoss Seam: How to Open jpa/hibernate session in view)
If you are sure that the open session in view filter is working then you might want to take a look at the transaction demarcation for service.retrieveParent(parentId);. The LazyInitializationException would make sense if the service/dao uses a different persistence context to load the parent entity.
I am not familiar with the spring/jboss setup and therefore missed some things.
I assume that your service bean is managed by the JBoss server and not by spring. By defining the LocalContainerEntityManagerFactoryBean you are actually configuring an EntityManagerFactory in Spring (very similar to the one managed by the application server). The open session in view filter is injected with the an EntityManager that's managed by Spring while it should have been injected by an entity manager managed by the application server.
I think that the following spring configuration will fix your problem (don't forget to adjust the jndi-name attribute):
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
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.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd">
<context:annotation-config/>
<jee:jndi-lookup id="entityManagerFactory" jndi-name="persistence-units/test"/>
<tx:jta-transaction-manager/>
LazyInitializationException means that hibernate tried to get the data of a lazy collection/object but the session was already closed.
If this line parent.getChildren().iterator().next().getName(); is throwing the error, it means that childrens is a lazy collection with actually no useful data, and by calling iterator().next() hibernate tried to load the entire collection.