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.
Related
I have a Spring MVC project going.
I have a WebController that has an #Autowired service.
When I run the web app on the server, the WebController is created but it doesn't autowire the service.
Been really banging my head against a wall trying to figure this out ... Any idea what's wrong?
Here's the error I get ...
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'webController':
Unsatisfied dependency expressed through field 'myAppService';
nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException:
No qualifying bean of type 'com.mycompany.myapp.controller.MyAppService'
available: expected at least 1 bean which qualifies as
autowire candidate. Dependency annotations:
{#org.springframework.beans.factory.annotation.Autowired(required=true)}
Here's my 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"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<display-name>Archetype Created Web Application</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>/</url-pattern>
</servlet-mapping>
</web-app>
Here's my dispatcher-servlet.xml ...
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context"
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/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.mycompany.myapp" />
<mvc:annotation-driven />
<bean id="viewResolver"
class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
</beans>
I have a WebController like so ...
package com.mycompany.myapp.controller;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import com.mycompany.myapp.model.TableRecord;
#Controller
public class WebController {
#Autowired
MyAppService myAppService;
#RequestMapping(value = "/showprojects", method = RequestMethod.GET)
public ModelAndView showProjects(Model model) {
ModelAndView mav = new ModelAndView();
try {
Set<TableRecord> recProjects = myAppService.getProjects();
model.addAttribute("projects", recProjects);
} catch (Exception x) {
x.printStackTrace();
}
mav.setViewName("projects");
return mav;
}
Here's my Service interface ...
package com.mycompany.myapp.controller;
import java.util.Set;
import org.springframework.stereotype.Component;
import com.mycompany.myapp.model.TableRecord;
#Component
public interface MyAppService {
public Set<TableRecord> getProjects() throws Exception;
}
And here's my Service implementation ...
package com.mycompany.myapp.controller;
import java.util.Set;
import org.springframework.stereotype.Component;
/* ... other import statements ... */
#Component
public class MyAppServiceImpl {
public MyAppServiceImpl() throws Exception {
/* ... some initialization of member variables
and db connection ... */
}
public Set<TableRecord> getProjects() throws Exception {
/* ... implementation that returns a Set... */
}
}
You didnt implement the interface in your service class- Change it as below-
public class MyAppServiceImpl implements MyAppService {
}
It should better to use #Service annoation for service class instead of #Component
Your MyAppServiceImpl class does not implement the MyAppService interface.
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.
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 new to spring security.
i try to use spring security in my application. the basic spring security functionality works fine.
but when i try to secure methods to allow only for specific role, it does not secured and that method can work for every role.
here i given my code snippet. may i know where i did mistake.
library that i used for this application are
01.aopalliance-1.0.jar
02.jcl-over-slf4j-1.6.1.jar
03.jstl-1.2.jar
04.logback-classic-0.9.29.jar
05.logback-core-0.9.29.jar
06.mysql-connector-java-5.1.12-bin.jar
07.org.springframework.jdbc-3.1.0.RC1.jar
08.org.springframework.transaction-3.1.0.RC1.jar
09.slf4j-api-1.6.1.jar
10.spring-aop-3.0.6.RELEASE.jar
11.spring-asm-3.0.6.RELEASE.jar
12.spring-beans-3.0.6.RELEASE.jar
13.spring-context-3.0.6.RELEASE.jar
14.spring-context-support-3.0.6.RELEASE.jar
15.spring-core-3.0.6.RELEASE.jar
16.spring-expression-3.0.6.RELEASE.jar
17.spring-security-config-3.1.0.RC3.jar
18.spring-security-core-3.1.0.RC3.jar
19.spring-security-crypto-3.1.0.RC3.jar
20.spring-security-taglibs-3.1.0.RC3.jar
21.spring-security-web-3.1.0.RC3.jar
22.spring-web-3.0.6.RELEASE.jar
23.spring-webmvc-3.0.6.RELEASE.jar
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">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/applicationContext.xml
/WEB-INF/security-app-context.xml
/WEB-INF/application-data-source.xml
</param-value>
</context-param>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!--
- Provides core MVC application controller. See bank-servlet.xml.
-->
<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>
<session-config>
<session-timeout>
30
</session-timeout>
</session-config>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
dispatcher-servlet.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:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.1.xsd"
xmlns:ns1="http://www.springframework.org/schema/security">
<ns1:global-method-security pre-post-annotations="enabled"/>
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:prefix="/pages/result/"
p:suffix=".jsp" >
<property name="viewClass">
<value>
org.springframework.web.servlet.view.JstlView
</value>
</property>
</bean>
<!--
The index controller.
-->
<bean name="indexController"
class="org.springframework.web.servlet.mvc.ParameterizableViewController"
p:viewName="index" />
<bean name="/action.htm" id="action" class="com.spt3.controller.ActionController">
<property name="methodNameResolver">
<ref bean="paramResolver"/>
</property>
</bean>
<bean id="paramResolver" class="org.springframework.web.servlet.mvc.multiaction.ParameterMethodNameResolver">
<property name="paramName">
<value>action</value>
</property>
</bean>
</beans>
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:security="http://www.springframework.org/schema/security"
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-3.0.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd">
</beans>
security-app-context.xml
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
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-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<global-method-security pre-post-annotations="enabled"/>
<http use-expressions="true" auto-config="true" access-denied-page="/pages/accessDenied.jsp">
<intercept-url pattern="/index.jsp" access="permitAll" />
<intercept-url pattern="/**.htm" access="isAuthenticated()"/>
<intercept-url pattern="/pages/*" access="permitAll" />
<intercept-url pattern="/user/*" access="isAuthenticated()"/>
<intercept-url pattern="/md/*" access="hasRole('MD')"/>
<intercept-url pattern="/admin/*" access="hasAnyRole('Administrator','MD')"/>
<intercept-url pattern="/manager/*" access="hasAnyRole('Manager','MD')"/>
<form-login login-page="/pages/login.jsp" authentication-failure-url="/pages/loginfailed.jsp"/>
<logout logout-success-url="/index.jsp"/>
</http>
<beans:bean id="encoder" class="com.spt3.encoder.MyPasswordEncoder"/>
<authentication-manager>
<authentication-provider>
<password-encoder ref="encoder"/>
<jdbc-user-service data-source-ref="dataSource"
users-by-username-query="
select username,password, enabled
from users where username=?"
authorities-by-username-query="
select u.username, ur.authority from users u, user_roles ur where u.user_id = ur.user_id and u.username =? "
/>
</authentication-provider>
</authentication-manager>
</beans:beans>
application-data-source.xml
<beans xmlns="http://www.springframework.org/schema/beans"
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-3.0.xsd">
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/app" />
<property name="username" value="uname" />
<property name="password" value="pword" />
</bean>
</beans>
ActionController.java
package com.spt3.controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.multiaction.MultiActionController;
import com.spt3.infc.ActionInterface;
import org.springframework.security.access.prepost.PreAuthorize;
public class ActionController extends MultiActionController implements ActionInterface {
public ActionController(){
}
public ModelAndView getResult(HttpServletRequest request,HttpServletResponse response)throws Exception{
System.out.println(" - - - - - getResult() - - - - - ");
try{
this.getPersonalInformation("MD");
}catch(Exception e){
System.out.println(" Exception : "+e);
}
return new ModelAndView("result");
}
public void getPersonalInformation(String role){
System.out.println(" "+role+"'s-Personal Information.");
}
}
ActionInterface.java
package com.spt3.infc;
import org.springframework.security.access.prepost.PreAuthorize;
public interface ActionInterface {
#PreAuthorize("hasRole('MD')") // Secured method only for role MD
public void getPersonalInformation(String role);
}
When accessing getResult() method from url (
http://127.0.0.1:8080/myapp/action.htm?action=getResult) secured method can be invoked.
My Expected Result should be
getPersonalInformation() method can access only for user role MD
Now Actual Result is
getPersonalInformation() method is invoking every user roles.
After using beans - Edited (1) Here
Same problem has been occurred when using bean injection.
Here i changed the files with the code snippet.
ActionController.java is like
package com.spt3.controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.multiaction.MultiActionController;
import com.spt3.infc.ActionInterface;
public class ActionController extends MultiActionController {
private ActionInterface actionInterface;
public ActionController(){
}
public ActionController(ActionInterface actionInterface){
this.actionInterface=actionInterface;
}
public ModelAndView getResult(HttpServletRequest request,HttpServletResponse response)throws Exception{
System.out.println(" - - - - - getResult() - - - - - ");
try{
actionInterface.getPersonalInformation("MD");
}catch(Exception e){
System.out.println(" Exception : "+e);
}
return new ModelAndView("result");
}
}
ActionInterface.java
package com.spt3.infc;
public interface ActionInterface {
public void getPersonalInformation(String role);
}
bean class called ActionBean.java
package com.spt3.bean;
import com.spt3.infc.ActionInterface;
import org.springframework.security.access.annotation.Secured;
public class ActionBean implements ActionInterface{
#Secured("MD")
public void getPersonalInformation(String role){
System.out.println(" "+role+"'s-Personal Information.");
}
}
i used constructor injection to inject the object.
<bean id="actionBean" class="com.spt3.bean.ActionBean"/> <!-- Bean class -->
<bean name="/action.htm" id="action" class="com.spt3.controller.ActionController">
<property name="methodNameResolver">
<ref bean="paramResolver"/>
</property>
<constructor-arg index="0" ref="actionBean"/> <!-- Injecting object to controller -->
</bean>
Where i did mistake. please give me the solution.
The problem is solved.
These are the steps i followed.
Configure bean in appropriate xml file
I used bean injection.
i used #PreAuthorize annotation.
Finally the classes are looks like the following snippet when the program is successfully ran.
ActionBean is a separate class i created and i implemented ActionInterface.java class and implemented the method getPersonalInformation() method.
ActionInterface.java looks like this
package com.spt3.infc;
public interface ActionInterface {
public void getPersonalInformation(String role);
}
and ActionBean.java looks like this
package com.spt3.bean;
import com.spt3.infc.ActionInterface;
import org.springframework.security.access.prepost.PreAuthorize;
public class ActionBean implements ActionInterface{
#PreAuthorize("hasRole('MD')")
public void getPersonalInformation(String role){
System.out.println(" "+role+"'s-Personal Information.");
}
}
ActionController.java is look like this
package com.spt3.controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.multiaction.MultiActionController;
import com.spt3.infc.ActionInterface;
public class ActionController extends MultiActionController {
private ActionInterface actionInterface;
public ActionController(){
}
public ActionController(ActionInterface actionInterface){
this.actionInterface=actionInterface;
}
public ModelAndView getResult(HttpServletRequest request,HttpServletResponse response)throws Exception{
System.out.println(" - - - - - getResult() - - - - - ");
try{
actionInterface.getPersonalInformation("MD");
}catch(Exception e){
System.out.println(" Exception : "+e);
}
return new ModelAndView("result");
}
}
Good luck...
Thanks a lot.
Spring security works by using proxies around the spring beans, which intercept the calls to methods of the beans, and throw an exception if the user doesn't have the appropriate role. But your controller doesn't call any spring bean method. It does call an instance method : this.getPersonalInformation().
When doing this, you're not calling another Spring bean method, so Spring can't intercept the call, and thus can't verify that the user has the appropriate roles.
Put the getPersonalInformation method in another Spring bean, inject this bean in your controller, and all should be fine.
Side note : why not simply using the #Secured("MD") annotation for such a case? And why not put the annotation on the getResult method directly?