Spring MVC cannot autowire - spring

I keep getting the below error when my bean is being created, however I am unsure why it is not seeing the bean when I have it declared. Is there something wrong with the file structure or is there a deeper issue? I know this will be TLDR for a lot of people but I wanted to include the full flow.
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'productsController' defined in file [C:\Users\ChappleZ\Desktop\CRCart001\CRCartSpring001\out\artifacts\CRCartSpring001_war_exploded\WEB-INF\classes\cr\controllers\ProductsController.class]: Unsatisfied dependency expressed through constructor argument with index 0 of type [cr.managers.ProductsManager]: : No matching bean of type [cr.managers.ProductsManager] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [cr.managers.ProductsManager] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
Below is folder structure and related files.
src
- Java
|_ Cr
|_ Controllers
|_ ProductsController
|_ Dao
|_ Impl
|_ ProductsDaoImpl
|_ ProductsDao
|_ Entity
|_ Products
|_ Managers
|_ ProductsManager
|_ Impl
|_ ProductsManagerImpl
- Resources
|_ Beans
|_ Daos.xml
|_ Services.xml
|_ Config
|_ BeanLocations.xml
|_ Database
|_ DataSource.xml
|_ Hibernate.xml
|_ Properties
|_ Database.properties
Web
- Resources
|_ Components
|_ Css
|_ Data
|_ Img
|_ Js
|_ Views
- WEB-INF
|_ applicationContext.xml
|_ dispatcher-servlet.xml
|_ logging.properties
|_ web.xml
- index.jsp
Products Controller
package cr.controllers;
import cr.Entity.Products;
import cr.managers.ProductsManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
#Controller
#RequestMapping("/Products")
public class ProductsController {
private ProductsManager productsManager;
#Autowired
public ProductsController(ProductsManager productsManager) {
this.productsManager = productsManager;
}
#RequestMapping(
value = "/products/{productId}",
method = RequestMethod.GET)
public
#ResponseBody
Products findByProductId(#PathVariable long productId) {
Products products = productsManager.findByProductId(productId);
return products;
}
}
ProductsDaoImpl
package cr.dao.impl;
import cr.Entity.Products;
import cr.dao.ProductsDao;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import java.util.List;
public class ProductsDaoImpl extends HibernateDaoSupport implements ProductsDao {
#Override
public void save(Products products) {
getHibernateTemplate().save(products);
}
#Override
public void update(Products products) {
getHibernateTemplate().update(products);
}
#Override
public void delete(Products products) {
getHibernateTemplate().delete(products);
}
#Override
public Products findByProductId(Long productId) {
List list = getHibernateTemplate().find("from Products where productId=?",productId);
return (Products)list.get(0);
}
}
ProductsDao
package cr.dao;
import cr.Entity.Products;
import org.codehaus.jackson.annotate.JsonAutoDetect;
import org.codehaus.jackson.annotate.JsonIgnoreProperties;
#JsonAutoDetect
#JsonIgnoreProperties(ignoreUnknown = true)
public interface ProductsDao {
void save(Products products);
void update(Products products);
void delete(Products products);
Products findByProductId(Long productId);
}
ProductsEntity
package cr.Entity;
import com.sun.istack.internal.NotNull;
import org.codehaus.jackson.annotate.JsonAutoDetect;
import org.codehaus.jackson.annotate.JsonIgnoreProperties;
import javax.persistence.*;
import java.sql.Timestamp;
#JsonAutoDetect
#JsonIgnoreProperties(ignoreUnknown = true)
#Entity
#Table(name= "Products")
public class Products {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name= "productsId")
private int productsId;
#Column(name = "ProductName")
#NotNull
private String productName;
#Column(name = "ProductDescription")
#NotNull
private String productDescription;
#Column(name = "MfgCost")
private double mfgCost;
#Column(name = "Price")
private double price;
#Column(name = "SalePrice")
private double salePrice;
#Column(name = "CreationDate")
private Timestamp creationDate;
#Column(name = "DeletedIndicator")
private Boolean deletedIndicator;
#Column(name = "ImagePath")
#NotNull
private String imagePath;
+Setters and Getters + ToString (Not added to keep post shorter)
ProductsManager
package cr.managers;
import cr.Entity.Products;
public interface ProductsManager {
void save(Products products);
void update(Products products);
void delete(Products products);
Products findByProductId(Long productId);
}
ProductsManagerImpl
package cr.managers.impl;
import cr.Entity.Products;
import cr.dao.ProductsDao;
import cr.managers.ProductsManager;
public class ProductsManagerImpl implements ProductsManager{
ProductsDao productsDao;
public void setProductsDao(ProductsDao productsDao){
this.productsDao=productsDao;
}
public void save(Products products) {
productsDao.save(products);
}
public void update(Products products) {
productsDao.update(products);
}
public void delete(Products products) {
productsDao.delete(products);
}
public Products findByProductId(Long productId) {
return productsDao.findByProductId(productId);
}
}
Daos.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-2.5.xsd">
<!-- Products Data Access Object -->
<bean id="productsDao" class="cr.dao.impl.ProductsDaoImpl">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
</beans>
services.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-2.5.xsd">
<!-- Products object -->
<bean id="productsManager" class="cr.managers.impl.ProductsManagerImpl">
<property name="productsDao" ref="productsDao"/>
</bean>
</beans>
BeanLocations.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-2.5.xsd">
<!-- Database Configuration -->
<import resource="../database/DataSource.xml"/>
<import resource="../database/Hibernate.xml"/>
<!-- Beans Declaration -->
<import resource="../beans/daos.xml"/>
<import resource="../beans/services.xml"/>
</beans>
DataSource.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-2.5.xsd">
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>properties/database.properties</value>
</property>
</bean>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
</beans>
Hibernate.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-2.5.xsd">
<!-- Hibernate session factory -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource"/>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
</beans>
Database.properties
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/schema
jdbc.username=user
jdbc.password=root
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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>
dispatcher-servlet.xml
<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/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/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
<!--================================= Component Scan ======================================-->
<!-- Scans within the base package of the application for #Controller to configure as beans -->
<!-- This entry looks for annotated classes and provides those beans in the Spring container. -->
<!-- So there is no need to declare bean definitions in the XML configuration -->
<context:component-scan base-package="cr"/>
<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources/ directory -->
<mvc:resources mapping="/resources/**" location="/resources/"/>
<mvc:annotation-driven />
<!--SimpleUrlHandlerMapping is already configured, disabling the default HandlerMappings.
The DispatcherServlet enables the DefaultAnnotationHandlerMapping, which looks for #RequestMapping annotations on #Controllers. -->
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<!-- Based on the value of the order property Spring sorts all handler mappings available in the context and applies the first matching handler. -->
<property name="order" value="1"/>
</bean>
</beans>
logging.properties
org.apache.catalina.core.ContainerBase.[Catalina].level = INFO
org.apache.catalina.core.ContainerBase.[Catalina].handlers = java.util.logging.ConsoleHandler
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app 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"
version="2.5">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<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>*.form</url-pattern>
</servlet-mapping>
</web-app>

This is where you get your error:
private ProductsManager productsManager;
#Autowired
public ProductsController(ProductsManager productsManager) {
this.productsManager = productsManager;
}
This is not the proper way to autowire a bean.
Replace all of that with
#Autowired
private ProductsManager productsManager;
You don't have to create a constructor for that. Alternatively, you can autowire a bean on a setter:
private ProductsManager productsManager;
#Autowired
public setProductsManager(ProductsManager productsManager) {
this.productsManager = productsManager;
}

Your applicationContext.xml does not import any of the XML files with the beans definitions, so these dont get processed
Your MVC dispatcher servlet scans 'cr' package for Spring-annotated classes. Your ProductsManager class is not annotated so is not found by component scanning, but ProductsController class is found, and cannot be instantiated since Spring does not have knowledge of your ProductsManager class.
Recommendations:
Import bean definitions XML in main application context. Do not instantiate ProductsController in root context - all #Controller beans should belong to MVC servlet context. You can achieve this with the following tags in MVC xml:
<context:component-scan base-package="cr" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
and in main context either add #Component annotations to your classes and use this:
<context:component-scan base-package="cr" use-default-filters="true">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
or skip component scanning completely and manually define your beans in XML

Option 1:-
Load services.xml in web.xml
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
//Load Services.xml here like <param-value>actualPath/services.xml</param-value>
</context-param>
import dao.xml in service.xml
//Like <import resource="classpath:actualClassPath/dao.xml" />
Then
You can autowire productsManager directly in the controller.
You can autowire productsDao directly in the productsManager.
Since you autowire productsManager,there is no need of constructor in the controller.
Since you autowire productsDao ,there is no need of constructor in the productsManager.
Below bean config is enough.
<bean id="productsManager" class="cr.managers.impl.ProductsManagerImpl"/>
Below code is enough for controller.
#Controller
#RequestMapping("/Products")
public class ProductsController {
#Autowired
private ProductsManager productsManager;
#RequestMapping(value = "/products/{productId}",
method = RequestMethod.GET)
#ResponseBody
public Products findByProductId(#PathVariable long productId) {
Products products = productsManager.findByProductId(productId);
return products;
}
}
Option2 :- (I wouldn't recommend this ( this is for better understanding))
Define productsManager,productsDao bean in applicationContext.xml
then
modify controller like above code it will work.

Related

Why isn't #Autowired working in my Spring MVC #Controller?

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.

#Qualifier annotation not working

I am trying DI with autowiring and I came across #Qualifier annotation annd tried the following code:
Car.java
package beans;
import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
import org.springframework.beans.factory.annotation.Qualifier;
public class Car {
#Autowired
#Qualifier("e1")
private Engine engine;
// no need to have setter or constructor
public void showData(){
System.out.println("Engine Model Year : "+engine.getModelyear());
}
}
Engine.java
package beans;
public class Engine {
private String modelyear;
public void setModelyear(String modelyear) {
this.modelyear = modelyear;
}
public String getModelyear() {
return modelyear;
}
}
Spring.xml
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN"
"http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<!-- activate autowire annotation -->
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
<bean id="e1" class="beans.Engine">
<property name="modelyear" value="2017"/>
</bean>
<bean id="e2" class="beans.Engine">
<property name="modelyear" value="2018"/>
</bean>
<bean id="c" class="beans.Car">
</bean>
</beans>
Main.java
package MainClass;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import beans.Car;
public class AutoAnno_Main {
public static void main(String[] args) {
ApplicationContext ap=new ClassPathXmlApplicationContext("resources/spring.xml");
Car c=(Car)ap.getBean("c");
c.showData();
}
}
And the error I am getting is:
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'beans.Engine' available: expected single matching bean but found 2: e1,e2
what's wrong in this I think the syntax is correct is there any problem with version
I am using eclipse Oxygen
You just need to add <context:annotation-config /> in your spring.xml. Certain spring annotations are not activated unless this is added. In your case, spring is not reading the #Qualifier annotation without the <context:annotation-config />.
I have tested by adding this and it seems to work.
Update:
Your spring xml needs to have the spring schema for that to detect <context:annotation-config>. Your final xml looks like this.
<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"
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.xsd">
<!-- activate autowire annotation -->
<context:annotation-config />
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
<bean id="e1" class="beans.Engine">
<property name="modelyear" value="2017"/>
</bean>
<bean id="e2" class="beans.Engine">
<property name="modelyear" value="2018"/>
</bean>
<bean id="c" class="beans.Car">
</bean>
</beans>

EntityManager is null in Jersey controller in Spring project with JPA (EclipseLink)

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.

Spring Autowire JdbcDaoSupport

I'm receiving the an error when trying to autowire a class that extends JdbcDaoSupport. I have my DAO classes and Controller classes separated into 2 different spring contexts. DAO classes are in the root context and the Controller classes are in the servlet context. I've set up the component-scanning so that there is no overlap in beans between the 2 contexts (is that the correct pattern?). All these factors combined with the fact that my DAOs extend JdbcDaoSupport seems to be causing the issue, and I don't understand why. I'm just learning spring so I don't fully understand all the concepts yet.
EDIT: This behavior seems to be caused by the fact that JdbcDaoSupport/DaoSupport implements the InitializingBean interface. Still confused though.
Here is the error I am receiving:
Error creating bean with name 'homeController': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: org.test.dao.CustomerDAO2 org.test.servlet.HomeController.customerDAO; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.test.dao.CustomerDAO2] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
Here are my files:
HomeController.java
package org.test.servlet;
import java.util.Locale;
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.test.dao.*;
#Controller
public class HomeController
{
#Autowired
CustomerDAO2 customerDAO;
#RequestMapping(value = "/", method = RequestMethod.GET)
public String home(Locale locale, Model model)
{
model.addAttribute("customer", customerDAO.getCustomer());
return "home";
}
}
CustomerDAO2.java
package org.test.dao;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.*;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.*;
import org.test.dto.Customer;
#Repository
public class CustomerDAO2 extends JdbcDaoSupport
{
public CustomerDAO2()
{
}
#Autowired
public CustomerDAO2(DataSource datasource)
{
this.setDataSource(datasource);
}
#Transactional
public Customer getCustomer()
{
JdbcTemplate jdbcTemplate = new JdbcTemplate(getDataSource());
Customer customer = jdbcTemplate.queryForObject("select * from customer", new CustomerMapper());
return customer;
}
public static class CustomerMapper implements RowMapper<Customer>
{
public Customer mapRow(ResultSet rs, int rowNum) throws SQLException
{
Customer customer = new Customer();
customer.setCustomerId(rs.getInt("customerId"));
customer.setCustomerNumber(rs.getString("customerNumber"));
return customer;
}
}
}
application-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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-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/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<!-- Scans within the base package of the application for #Components to configure as beans -->
<!-- #Controller, #Service, #Configuration, etc. -->
<context:component-scan base-package="org.test">
<context:exclude-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
</context:component-scan>
<!-- Enables the configuration of transactional behavior based on annotations -->
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost/crm?user=root&password=password" />
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
</beans>
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: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">
<!-- Scans within the base package of the application for #Components to configure as beans -->
<!-- #Controller, #Service, #Configuration, etc. -->
<context:component-scan base-package="org.test.servlet"/>
<!-- Enables the Spring MVC #Controller programming model -->
<mvc:annotation-driven />
<!-- Resolves views selected for rendering by #Controllers to .jsp resources in the /WEB-INF/views directory -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/" />
<property name="suffix" value=".jsp" />
</bean>
</beans>
I found my answer in this post:
Spring expected at least 1 bean which qualifies as autowire candidate for this dependency
Basically, I need to create an interface for my DAO classes. Something like this:
public interface ICustomerDAO {
Customer getCustomer();
}
Note: it would probably be better to make a more generic CRUD interface.
Then you use the interface type for dependency injection instead of using the class type:
#Autowired
ICustomerDAO customerDAO;
The reason this is necessary is because Spring creates underlying proxy classes:
http://insufficientinformation.blogspot.com/2007/12/spring-dynamic-proxies-vs-cglib-proxies.html
http://docs.spring.io/spring/docs/2.5.x/reference/aop.html#aop-proxying

I can persist data through the test but not through the app. aop problems

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.

Resources