Spring Autowire JdbcDaoSupport - spring

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

Related

#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>

#Autowired - No qualifying bean of type found for dependency at least 1 bean

Currently I'm facing an issue in Autowire configuration between controller and the service layer.
I'm unable to trace my mistakes.
Simple Log Info
SEVERE: Exception while loading the app
SEVERE: Undeployment failed for context /OTT
SEVERE: Exception while loading the app : java.lang.IllegalStateException: ContainerBase.addChild: start: org.apache.catalina.LifecycleException: org.apache.catalina.LifecycleException: org.springframework.beans.factory.NoSuchBeanDefinitionException:
No qualifying bean of type [com.ott.service.EmployeeService] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
Below I have also given the Controller and Service Layer code and also the dispatcher-servlet.xml
Controller
package com.ott.controller;
import com.ott.service.EmployeeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/**
*
* #author SPAR
*/
#Controller
public class AdminController {
private EmployeeService employeeService;
#RequestMapping("/employee")
public String employee(){
this.employeeService.fetchAll();
return "employee";
}
#Autowired(required = true)
#Qualifier(value="employeeService")
public void setEmployeeService(EmployeeService empService) {
this.employeeService = empService;
}
}
Service Interface
package com.ott.service;
import com.ott.hibernate.Employee;
import java.util.List;
/**
*
* #author SPAR
*/
public interface EmployeeService {
List<Employee> fetchAll();
}
Service Interface Impl
package com.ott.service;
import com.ott.dao.EmployeeDAO;
import com.ott.hibernate.Employee;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
*
* #author SPAR
*/
#Service
public class EmployeeServiceImpl implements EmployeeService{
private EmployeeDAO employeeDAO;
#Override
#Transactional(readOnly = true)
public List<Employee> fetchAll() {
List<Employee> employees = employeeDAO.fetchAll();
for (Employee employee : employees) {
System.out.println("Name : "+employee.getFirst_Name() +" "+ employee.getLast_Name());
System.out.println("Email Id : "+employee.getEmail_Id());
}
return employees;
}
#Autowired(required = true)
#Qualifier(value="employeeDAO")
public void setEmployeeDAO(EmployeeDAO empDAO) {
this.employeeDAO = empDAO;
}
}
Dispatcher-servlet.xml
<?xml version='1.0' encoding='UTF-8' ?>
<!-- was: <?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"
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-4.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">
<context:component-scan base-package="com.ott.controller"/>
<context:component-scan base-package="com.ott.hibernate"/>
<context:component-scan base-package="com.ott.service"/>
<context:component-scan base-package="com.ott.dao"/>
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>
<mvc:resources mapping="/resources/**" location="/resources/" />
<bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles3.TilesConfigurer">
<property name="definitions">
<list>
<value>/WEB-INF/tiles-def/general-layout.xml</value>
</list>
</property>
</bean>
<bean id="viewResolverTiles" class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.tiles3.TilesView"/>
</bean>
<mvc:annotation-driven />
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>/WEB-INF/pages/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
</beans>
Guys I found the issue
I just tried by adding the qualifier name in employee service finally it solved my issue.
#Service("employeeService")
public class EmployeeServiceImpl implements EmployeeService{
}
You don't have to necessarily provide name and Qualifier. If you set a name, that's the name with which the bean is registered in the context. If you don't provide a name for your service it will be registered as uncapitalized non-qualified class name based on BeanNameGenerator. So in your case the Implementation will be registered as employeeServiceImpl. So if you try to autowire with that name, it should resolve directly.
private EmployeeService employeeServiceImpl;
#RequestMapping("/employee")
public String employee() {
this.employeeService.fetchAll();
return "employee";
}
#Autowired(required = true)
public void setEmployeeService(EmployeeService employeeServiceImpl) {
this.employeeServiceImpl = employeeServiceImpl;
}
#Qualifier is used in case if there are more than one bean exists of same type and you want to autowire different implementation beans for various purposes.
I believe for #Service you have to add qualifier name like below :
#Service("employeeService") should solve your issue
or after #Service you should add #Qualifier annontion like below :
#Service
#Qualifier("employeeService")
In your controller class, just add #ComponentScan("package") annotation. In my case the package name is com.shoppingcart.So i wrote the code as #ComponentScan("com.shoppingcart") and it worked for me.
You forgot #Service annotation in your service class.
#Service: It tells that particular class is a Service to the client. Service class contains mainly business Logic. If you have more Service classes in a package than provide #Qualifier otherwise it should not require #Qualifier.
Case 1:
#Service("employeeService")
public class EmployeeServiceImpl implements EmployeeService{
}
Case2:
#Service
public class EmployeeServiceImpl implements EmployeeService{
}
both cases are working...
If you only have one bean of type EmployeeService, and the interface EmployeeService does not have other implementations, you can simply put "#Service" before the EmployeeServiceImpl and "#Autowire" before the setter method.
Otherwise, you should name the special bean like #Service("myspecial") and put "#autowire #Qualifier("myspecial") before the setter method.
Just add below annotation with qualifier name of service in service Implementation class:
#Service("employeeService")
#Transactional
public class EmployeeServiceImpl implements EmployeeService{
}
Missing the 'implements' keyword in the impl classes might also be the issue

Why `autowire=byType` will also inject beans by name?

I found something not clear about the autowire=byType behavior.
Java code under package my:
public class User {
private String name;
public User(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
#Component
public class UserService {
#Autowired
private User user1;
#Autowired
private User user2;
public String getNames() {
return user1.getName() + " & " + user2.getName();
}
}
Spring config:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd">
<context:component-scan base-package="my"/>
<context:annotation-config/>
<bean id="user1" class="my.User" autowire="byType">
<constructor-arg value="Freewind"/>
</bean>
<bean id="user2" class="my.User" autowire="byType">
<constructor-arg value="Lily"/>
</bean>
</beans>
Running code:
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService service = context.getBean(UserService.class);
System.out.println(service.getNames());
}
}
It's working well and prints:
Freewind & Lily
But I was expecting it should not work, because I used autowire="byType" when I defined the beans, and there are two beans with the same type User in UserService.
And, if I changed the name of the bean, say, user1 -> user999, it will report some error like No qualifying bean of type [my.User] is defined error.
It seems spring will automatic check the name even if I specified byType, which is strange.
PS: I've tested with spring 4.1.3.RELEASE and 3.2.2.RELEASE, same behavior.
<bean id="user2" class="my.User" autowire="byType">
<constructor-arg value="Lily"/>
</bean>
The autowire="byType" here means that you want to have (missing) dependencies injected into this bean byType. It only applies to the bean the attribute is placed on. In the xml namespace the default for all the beans could be set.
However in your case you are using actually using annotations (note <context:annotation-config /> is already implied by the usage of </context:component-scan />). Annotation driven injection (#Autowired, #Inject are always by type, #Resource uses a name or jndi lookup and as fallback by name).
When starting the application and scanning for components for each needed dependency the DependencyDescriptor is created. This class contains the details used for autowiring, it amongst other things contains the type and the name. The name, in case of a Field is derived from the actual name.

Spring MVC cannot autowire

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.

Spring Autowire Fundamentals

I am a newbie in Spring and am trying to understand the below concept.
Assume that accountDAO is a dependency of AccountService.
Scenario 1:
<bean id="accServiceRef" class="com.service.AccountService">
<property name="accountDAO " ref="accDAORef"/>
</bean>
<bean id="accDAORef" class="com.dao.AccountDAO"/>
Scenario 2:
<bean id="accServiceRef" class="com.service.AccountService" autowire="byName"/>
<bean id="accDAORef" class="com.dao.AccountDAO"/>
In AccountService Class:
public class AccountService {
AccountDAO accountDAO;
....
....
}
In the second scenario, How is the dependency injected ? When we say it is autowired by Name , how exactly is it being done. Which name is matched while injecing the dependency?
Thanks in advance!
Use #Component and #Autowire, it's the Spring 3.0 way
#Component
public class AccountService {
#Autowired
private AccountDAO accountDAO;
/* ... */
}
Put a component scan in your app context rather than declare the beans directly.
<?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"
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">
<context:component-scan base-package="com"/>
</beans>
<bean id="accServiceRef" class="com.service.accountService" autowire="byName">
</bean>
<bean id="accDAORef" class="com.dao.accountDAO">
</bean>
and
public class AccountService {
AccountDAO accountDAO;
/* more stuff */
}
When spring finds the autowire property inside accServiceRef bean, it will scan the instance variables inside the AccountService class for a matching name. If any of the instance variable name matches the bean name in the xml file, that bean will be injected into the AccountService class. In this case, a match is found for accountDAO.
Hope it makes sense.

Resources